WikiCalendarMacro: WikiCalendarMacro.4.py

File WikiCalendarMacro.4.py, 9.7 kB (added by JasonWinnebeck, 5 months ago)

For some reason, version 3 failed for me in python 2.4, trac 0.11rc1, with a date error. This is fixed.

Line 
1 # Copyright (C) 2005 Matthew Good <trac@matt-good.net>
2 # Copyright (C) 2005 Jan Finell <finell@cenix-bioscience.com>
3 #
4 # "THE BEER-WARE LICENSE" (Revision 42):
5 # <trac@matt-good.net> wrote this file.  As long as you retain this notice you
6 # can do whatever you want with this stuff.  If we meet some day, and you think
7 # this stuff is worth it, you can buy me a beer in return.  Matthew Good
8 # (Beer-ware license written by Poul-Henning Kamp
9 #  http://people.freebsd.org/~phk/)
10 #
11 # Author: Matthew Good <trac@matt-good.net>
12 # Month/Year navigation by: Jan Finell <finell@cenix-bioscience.com>
13 # trac 0.11 compatibility by: Vlad Sukhoy <vladimir.sukhoy@gmail.com>
14 # refactored; CSS added: Andy Schlaikjer <andrew.schlaikjer@gmail.com>
15
16 import time
17 import calendar
18 from cStringIO import StringIO
19 from trac.wiki.api import WikiSystem
20 from trac.wiki.macros import WikiMacroBase
21 from trac.util import *
22
23 class WikiCalendarMacro(WikiMacroBase):
24    
25     """Inserts a small calendar where each day links to a wiki page
26     whose name matches `wiki-page-format`. The current day is
27     highlighted, and days with Milestones are marked in bold. This
28     version makes heavy use of CSS for formatting. Tested in Firefox
29     2.0 only.
30     
31     Usage:
32     {{{
33     [[WikiCalendar([year, [month, [show-buttons, [wiki-page-format]]]])]]
34     }}}
35     
36     Arguments:
37      1. `year` (4-digit year) - defaults to `*` (current year)
38      1. `month` (2-digit month) - defaults to `*` (current month)
39      1. `show-buttons` (boolean) - defaults to `true`
40      1. `wiki-page-format` (string) - defaults to `%Y-%m-%d`
41     
42     Examples:
43     {{{
44     [[WikiCalendar(2006,07)]]
45     [[WikiCalendar(2006,07,false)]]
46     [[WikiCalendar(*,*,true,Meeting-%Y-%m-%d)]]
47     [[WikiCalendar(2006,07,false,Meeting-%Y-%m-%d)]]
48     }}}
49     """
50    
51     def expand_macro(self, formatter, name, content):
52         today = time.localtime()
53         # VS: The hdf is gone in 0.11, using request object instead
54         http_param_year = formatter.req.args.get('year', '')
55         http_param_month = formatter.req.args.get('month', '')
56         if content == "":
57             args = []
58         else:
59             args = content.split(',', 3)
60        
61         # find out whether use http param, current or macro param year/month
62        
63         if http_param_year == "":
64             # not clicked on a prev or next button
65             if len(args) >= 1 and args[0] <> "*":
66                 # year given in macro parameters
67                 year = int(args[0])
68             else:
69                 # use current year
70                 year = today.tm_year
71         else:
72             # year in http params (clicked by user) overrides everything
73             year = int(http_param_year)
74        
75         if http_param_month == "":
76             # not clicked on a prev or next button
77             if len(args) >= 2 and args[1] <> "*":
78                 # month given in macro parameters
79                 month = int(args[1])
80             else:
81                 # use current month
82                 month = today.tm_mon
83         else:
84             # month in http params (clicked by user) overrides everything
85             month = int(http_param_month)
86        
87         showbuttons = 1
88         if len(args) >= 3:
89             showbuttons = bool(args[2]=="True" or args[2]=="true" or args[2]=="no" or args[2]=="0")
90        
91         wiki_page_format = "%Y-%m-%d"
92         if len(args) >= 4:
93             wiki_page_format = args[3]
94        
95         curr_day = None
96         if year == today.tm_year and month == today.tm_mon:
97             curr_day = today.tm_mday
98        
99         # url to the current page (used in the navigation links)
100         # VS: hdf is gone in 0.11, using the new "Context" object instead
101         # AS: trac.web.Href object used instead of basic strings
102         thispageURL = formatter.context.href
103         # for the prev/next navigation links
104         prevMonth = month-1
105         prevYear  = year
106         nextMonth = month+1
107         nextYear  = year
108         # check for year change (KISS version)
109         if prevMonth == 0:
110             prevMonth = 12
111             prevYear -= 1
112         if nextMonth == 13:
113             nextMonth = 1
114             nextYear += 1
115        
116         # 9-tuple for use with time.* functions requiring a struct_time
117         date = list( today )
118        
119         # building the output
120         buff = StringIO()
121         buff.write('''\
122 <style type="text/css">
123 <!--
124 table.wiki-calendar { border: none; border-collapse: separate; border-spacing: 0px; }
125 table.wiki-calendar caption { font-size: 120%; white-space: nowrap; }
126 table.wiki-calendar caption a { display: inline; margin: 0; border: 0; padding: 0; text-decoration: none; color: #b00; }
127 table.wiki-calendar caption a.prev { padding-right: 5px; }
128 table.wiki-calendar caption a.next { padding-left: 5px; }
129 table.wiki-calendar caption a:hover { background-color: #eee; }
130 table.wiki-calendar caption a:visited  {}
131 table.wiki-calendar caption a:active {}
132 table.wiki-calendar th { border: none; border-bottom: 2px solid black; text-align: center; font-weight: bold; }
133 table.wiki-calendar td { padding: 0; border: 2px; text-align: right; }
134 table.wiki-calendar a { display: block; width: 2em; height: 100%; margin: 0; border: 2px solid transparent; padding: 0; text-decoration: none; color: #888; }
135 table.wiki-calendar a:hover { background-color: #eee !important; color: #000; }
136 table.wiki-calendar a:visited {}
137 table.wiki-calendar a:active {}
138 table.wiki-calendar a.empty { background-color: #fafafa; }
139 table.wiki-calendar a.milestone { border-color: #888; font-weight: bold; }
140 table.wiki-calendar a.haspage { color: #b00; }
141 table.wiki-calendar a.haspage:hover {}
142 table.wiki-calendar a.today { border-color: #b00; }
143 //-->
144 </style>
145 <table class="wiki-calendar"><caption>
146 ''')
147        
148         if showbuttons:
149             # prev year link
150             date[0:2] = [year-1, month]
151             buff.write('<a class="prev" href="%(url)s" title="%(title)s">&lt;&lt;</a>' % {
152                 'url': thispageURL(month=month, year=year-1),
153                 'title': time.strftime('%B %Y', tuple(date))
154                 })
155             # prev month link
156             date[0:2] = [prevYear, prevMonth]
157             buff.write('<a class="prev" href="%(url)s" title="%(title)s">&lt;</a>' % {
158                 'url': thispageURL(month=prevMonth, year=prevYear),
159                 'title': time.strftime('%B %Y', tuple(date))
160                 })
161        
162         # the caption
163         date[0:2] = [year, month]
164         buff.write(time.strftime('%B %Y', tuple(date)))
165        
166         if showbuttons:
167             # next month link
168             date[0:2] = [nextYear, nextMonth]
169             buff.write('<a class="next" href="%(url)s" title="%(title)s">&gt;</a>' % {
170                 'url': thispageURL(month=nextMonth, year=nextYear),
171                 'title': time.strftime('%B %Y', tuple(date))
172                 })
173             # next year link
174             date[0:2] = [year+1, month]
175             buff.write('<a class="next" href="%(url)s" title="%(title)s">&gt;&gt;</a>' % {
176                 'url': thispageURL(month=month, year=year+1),
177                 'title': time.strftime('%B %Y', tuple(date))
178                 })
179            
180         buff.write('</caption>\n<thead>\n<tr>')
181         for day in calendar.weekheader(2).split():
182             buff.write('<th scope="col">%s</th>' % day)
183         buff.write('</tr>\n</thead>\n<tbody>\n')
184        
185         last_week_prev_month = calendar.monthcalendar(prevYear, prevMonth)[-1];
186         first_week_next_month = calendar.monthcalendar(nextYear, nextMonth)[0];
187         w = -1
188         for week in calendar.monthcalendar(year, month):
189             buff.write('<tr>\n')
190             w = w+1
191             d = -1
192             for day in week:
193                 d = d+1
194                
195                 # calc date and update CSS classes
196                 date[0:3] = [year, month, day]
197                 classes = ''
198                 if not day:
199                     classes = 'empty'
200                     if w == 0:
201                         day = last_week_prev_month[d]
202                         date[0:3] = [prevYear, prevMonth, day]
203                     else:
204                         day = first_week_next_month[d]
205                         date[0:3] = [nextYear, nextMonth, day]
206                 else:
207                     classes = day == curr_day and 'today' or ''
208                 url = ''
209                 title = ''
210                
211                 # check for milestone
212                 db = self.env.get_db_cnx()
213                 cursor = db.cursor()
214                 duedate = time.mktime(tuple(date))
215                 cursor.execute("SELECT name FROM milestone WHERE due=%s", (duedate,))
216                 row = cursor.fetchone()
217                 if row:
218                     milestone_name = row[0]
219                     classes += ' milestone'
220                     url = self.env.href.milestone(milestone_name)
221                     title = milestone_name + ' - '
222                    
223                 # check for wikipage with name specified in 'wiki_page_format'
224                 wiki = time.strftime(wiki_page_format, tuple(date))
225                 url = self.env.href.wiki(wiki)
226                 if WikiSystem(self.env).has_page(wiki):
227                     classes += ' haspage'
228                     title += 'Go to page %s' % wiki
229                 else:
230                     url += "?action=edit"
231                     title += 'Create page %s' % wiki
232                    
233                 # buffer output
234                 buff.write('<td><a class="%(classes)s" href="%(url)s" title="%(title)s">%(day)s</a></td>' % {
235                     'classes': classes.strip(),
236                     'url': url,
237                     'title': title,
238                     'day': day
239                     })
240             buff.write('</tr>\n')
241         buff.write('</tbody>\n</table>\n')
242         table = buff.getvalue()
243         buff.close()
244         return table