WikiCalendarMacro: WikiCalendarMacro.3.py

File WikiCalendarMacro.3.py, 9.8 kB (added by Andy, 5 months ago)

Further refinement of CSS / Javascript version, removed all Javascript

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         # argument. The ninth value of -1 signals "do the right thing"
118         # w.r.t. daylight savings time.
119         date = [0] * 8 + [-1]
120        
121         # building the output
122         buff = StringIO()
123         buff.write('''\
124 <style type="text/css">
125 <!--
126 table.wiki-calendar { border: none; border-collapse: separate; border-spacing: 0px; }
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; text-decoration: none; color: #b00; }
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 caption a:visited  {}
133 table.wiki-calendar caption a:active {}
134 table.wiki-calendar th { border: none; border-bottom: 2px solid black; text-align: center; font-weight: bold; }
135 table.wiki-calendar td { padding: 0; border: 2px; text-align: right; }
136 table.wiki-calendar a { display: block; width: 2em; height: 100%; margin: 0; border: 2px solid transparent; padding: 0; text-decoration: none; color: #888; }
137 table.wiki-calendar a:hover { background-color: #eee !important; color: #000; }
138 table.wiki-calendar a:visited {}
139 table.wiki-calendar a:active {}
140 table.wiki-calendar a.empty { background-color: #fafafa; }
141 table.wiki-calendar a.milestone { border-color: #888; font-weight: bold; }
142 table.wiki-calendar a.haspage { color: #b00; }
143 table.wiki-calendar a.haspage:hover {}
144 table.wiki-calendar a.today { border-color: #b00; }
145 //-->
146 </style>
147 <table class="wiki-calendar"><caption>
148 ''')
149        
150         if showbuttons:
151             # prev year link
152             date[0:2] = [year-1, month]
153             buff.write('<a class="prev" href="%(url)s" title="%(title)s">&lt;&lt;</a>' % {
154                 'url': thispageURL(month=month, year=year-1),
155                 'title': time.strftime('%B %Y', tuple(date))
156                 })
157             # prev month link
158             date[0:2] = [prevYear, prevMonth]
159             buff.write('<a class="prev" href="%(url)s" title="%(title)s">&lt;</a>' % {
160                 'url': thispageURL(month=prevMonth, year=prevYear),
161                 'title': time.strftime('%B %Y', tuple(date))
162                 })
163        
164         # the caption
165         date[0:2] = [year, month]
166         buff.write(time.strftime('%B %Y', tuple(date)))
167        
168         if showbuttons:
169             # next month link
170             date[0:2] = [nextYear, nextMonth]
171             buff.write('<a class="next" href="%(url)s" title="%(title)s">&gt;</a>' % {
172                 'url': thispageURL(month=nextMonth, year=nextYear),
173                 'title': time.strftime('%B %Y', tuple(date))
174                 })
175             # next year link
176             date[0:2] = [year+1, month]
177             buff.write('<a class="next" href="%(url)s" title="%(title)s">&gt;&gt;</a>' % {
178                 'url': thispageURL(month=month, year=year+1),
179                 'title': time.strftime('%B %Y', tuple(date))
180                 })
181            
182         buff.write('</caption>\n<thead>\n<tr>')
183         for day in calendar.weekheader(2).split():
184             buff.write('<th scope="col">%s</th>' % day)
185         buff.write('</tr>\n</thead>\n<tbody>\n')
186        
187         last_week_prev_month = calendar.monthcalendar(prevYear, prevMonth)[-1];
188         first_week_next_month = calendar.monthcalendar(nextYear, nextMonth)[0];
189         w = -1
190         for week in calendar.monthcalendar(year, month):
191             buff.write('<tr>\n')
192             w = w+1
193             d = -1
194             for day in week:
195                 d = d+1
196                
197                 # calc date and update CSS classes
198                 date[0:3] = [year, month, day]
199                 classes = ''
200                 if not day:
201                     classes = 'empty'
202                     if w == 0:
203                         day = last_week_prev_month[d]
204                         date[0:3] = [prevYear, prevMonth, day]
205                     else:
206                         day = first_week_next_month[d]
207                         date[0:3] = [nextYear, nextMonth, day]
208                 else:
209                     classes = day == curr_day and 'today' or ''
210                 url = ''
211                 title = ''
212                
213                 # check for milestone
214                 db = self.env.get_db_cnx()
215                 cursor = db.cursor()
216                 duedate = time.mktime(tuple(date))
217                 cursor.execute("SELECT name FROM milestone WHERE due=%s", (duedate,))
218                 row = cursor.fetchone()
219                 if row:
220                     milestone_name = row[0]
221                     classes += ' milestone'
222                     url = self.env.href.milestone(milestone_name)
223                     title = milestone_name + ' - '
224                    
225                 # check for wikipage with name specified in 'wiki_page_format'
226                 wiki = time.strftime(wiki_page_format, tuple(date))
227                 url = self.env.href.wiki(wiki)
228                 if WikiSystem(self.env).has_page(wiki):
229                     classes += ' haspage'
230                     title += 'Go to page %s' % wiki
231                 else:
232                     url += "?action=edit"
233                     title += 'Create page %s' % wiki
234                    
235                 # buffer output
236                 buff.write('<td><a class="%(classes)s" href="%(url)s" title="%(title)s">%(day)s</a></td>' % {
237                     'classes': classes.strip(),
238                     'url': url,
239                     'title': title,
240                     'day': day
241                     })
242             buff.write('</tr>\n')
243         buff.write('</tbody>\n</table>\n')
244         table = buff.getvalue()
245         buff.close()
246         return table