WikiCalendarMacro: WikiCalendarMacro.6.py

File WikiCalendarMacro.6.py, 9.8 kB (added by Andy, 4 months ago)

version 4 may have fixed something while running with Python 2.4, but it broke the SQL query for Milestones, so I've regressed the patch. This version tested with Python 2.5 ONLY. Expected to break with Python 2.4.

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