Attachment 'MonthCalendar.py'
Download 1 """
2 MoinMoin - MonthCalendar Macro
3
4 You can use this macro to put a months calendar page on a Wiki page.
5
6 The days are links to Wiki pages following this naming convention:
7 BasePageName/year-month-day
8
9 Copyright (c) 2002 by Thomas Waldmann <ThomasWaldmann@gmx.de>
10 changes for moin 1.2 Copyright (c) 2004 by Oliver Graf <ograf@bitart.de>
11 Licensed under GNU GPL - see COPYING for details.
12
13 ----
14
15 Revisions:
16 * first revision without a number (=1.0):
17 * was only online for a few hours and then replaced by 1.1
18 * 1.1:
19 * changed name to MonthCalendar to avoid conflict with "calendar" under case-insensitive OSes like Win32
20 * days as subpages
21 * basepage argument
22 * change order of year/month argument
23 * browsing links to prev/next month/year
24 * current limitation: you can only browse one calendar on the same
25 page/url, if you try to browse another calendar on the same page,
26 the first one jumps back to its original display
27 * show basepage in calendar header if basepage<>currentpage
28 * 1.2:
29 * minor fixes in argument parsing
30 * cosmetic fix for netscape, other cosmetic changes, changed css
31 * i18n support (weekday short names)
32 * 1.3:
33 * fixes to run with MoinMoin 0.11, thanks to JuergenHermann
34 * fix: withspace before "," allowed in argument list
35 * BasePage in calendar header (if present) is a link now
36 * more i18n
37 * HTML cleanup, generating code avoids bracketing errors
38 * colour cosmetics
39 * 1.4:
40 * new parameter for enabling fixed height of 6 "calendar weeks",
41 if you want to show a whole year's calendar, this just looks
42 better than having some months with 4, some with 5 and some with 6.
43 * group calendaring functions:
44 * you can give mutliple BasePages UserName1*UserName2*UserName3
45 * first BasePage is considered "your" Basepage,
46 used days are bright red
47 * 2nd and all other BasePages are considered "others" BasePages
48 and lead to an increasing green component the more "used" days
49 the others have. So white gets greener and red gets more yellowish.
50 * in the head part of the calendar, you can click on each name
51 to get to the Page of the same name
52 * colouring of my and others BasePage is done in a way to show
53 the colouring used in the calendar:
54 * others use green colouring (increasingly green if multiply used)
55 * I use red colouring, which gets more and more yellowish as
56 the day is used by more and more others, too
57 * 1.5:
58 * fixed username colouring when using a BasePage
59 * fixed navigation header of MonthCalendar not to get broken into
60 multiple lines
61 * fixed SubPage handling (please do not use relative SubPages like
62 /SubPage yet. Use MyName/SubPage.)
63 * 1.6:
64 * syntactic cleanup
65 * removed i18n compatibility for moin<1.1 or cvs<2003-06-10
66 * integrated Scott Chapman's changes:
67 * Made it configurable for Sunday or Monday as the first day of the week.
68 Search for 'change here'.
69 * Made it so weekend dates have different color.
70
71 TODO:
72 * integrate patch for including day page contents directly into cal
73 * still thinking over: does this make sense in a MonthCalendar?
74 * it would be definitely nice in a week or day calendar (more space to
75 burn)
76 * integr. daycal -link-> monthcal
77
78 ----
79
80 Usage:
81 [[MonthCalendar(BasePage,year,month,monthoffset,monthoffset2,height6)]]
82
83 each parameter can be empty and then defaults to currentpage or currentdate or monthoffset=0
84
85 Samples (paste that to one of your pages for a first try):
86
87 Calendar of current month for current page:
88 [[MonthCalendar]]
89
90 Calendar of last month:
91 [[MonthCalendar(,,,-1)]]
92
93 Calendar of next month:
94 [[MonthCalendar(,,,+1)]]
95
96 Calendar of Page SampleUser, this years december:
97 [[MonthCalendar(SampleUser,,12)]]
98
99 Calendar of current Page, this years december:
100 [[MonthCalendar(,,12)]]
101
102 Calendar of December, 2001:
103 [[MonthCalendar(,2001,12)]]
104
105 Calendar of the month two months after December, 2001
106 (maybe doesn't make much sense, but is possible)
107 [[MonthCalendar(,2001,12,+2)]]
108
109 Calendar of year 2002 (every month padded to height of 6):
110 ||||||Year 2002||
111 ||[[MonthCalendar(,2002,1,,,1)]]||[[MonthCalendar(,2002,2,,,1)]]||[[MonthCalendar(,2002,3,,,1)]]||
112 ||[[MonthCalendar(,2002,4,,,1)]]||[[MonthCalendar(,2002,5,,,1)]]||[[MonthCalendar(,2002,6,,,1)]]||
113 ||[[MonthCalendar(,2002,7,,,1)]]||[[MonthCalendar(,2002,8,,,1)]]||[[MonthCalendar(,2002,9,,,1)]]||
114 ||[[MonthCalendar(,2002,10,,,1)]]||[[MonthCalendar(,2002,11,,,1)]]||[[MonthCalendar(,2002,12,,,1)]]||
115
116 Current calendar of me, also showing entries of A and B:
117 [[MonthCalendar(MyPage*TestUserA*TestUserB)]]
118
119 SubPage calendars:
120 [[MonthCalendar(MyName/CalPrivate)]]
121 [[MonthCalendar(MyName/CalBusiness)]]
122 [[MonthCalendar(MyName/CalBusiness*MyName/CalPrivate)]]
123
124
125 Anniversary Calendars: (no year data)
126 [[MonthCalendar(Yearly,,,+1,,6,1)]]
127
128 This creates calendars of the format Yearly/MM-DD
129 By leaving out the year, you can set birthdays, and anniversaries in this
130 calendar and not have to re-enter each year.
131 ----
132
133 You need to have some stylesheet entries like the following.
134 Paste that to default.css / moinmoin.css:
135
136 /* begin css for MonthCalendar macro */
137 /* calendar table */
138 table.cal-table {
139 border: none;
140 padding: 2px;
141 spacing: 2px;
142 }
143
144 table.cal-table td {
145 border: none;
146 }
147
148 /* days without and with pages linked to them */
149 a.cal-emptyday {
150 color: #5A5A5A;
151 text-align: center;
152 text-decoration: none;
153 }
154 a.cal-usedday {
155 font-weight: bold;
156 color: #222200;
157 text-align: center;
158 text-decoration: none;
159 }
160 /* multi page calendars */
161 a.cal-thispage {
162 color: #777777;
163 text-align: center;
164 text-decoration: none;
165 }
166 a.cal-otherpage {
167 font-weight: bold;
168 color: #000000;
169 text-align: center;
170 }
171 /* general stuff: workdays, weekend, today */
172 .cal-cell {
173 width: 2em;
174 height: 1.5em;
175 }
176
177 td.cal-workday {
178 background-color: #DDDDFF;
179 text-align: center;
180 }
181 td.cal-weekend {
182 background-color: #FFDDDD;
183 text-align: center;
184 }
185 td.cal-today {
186 background-color: #CCFFCC;
187 text-align: center;
188 }
189 /* invalid places on the monthly calendar sheet */
190 td.cal-invalidday {
191 background-color: #DDDDFF;
192 text-align: center;
193 }
194 /* links to prev/next month/year */
195 a.cal-link {
196 color: #000000;
197 text-decoration: none;
198 }
199 th.cal-header {
200 background-color: #DDBBFF;
201 text-align: center;
202 }
203 /* end css for MonthCalendar macro */
204
205 ----
206
207 If you want translated (german) messages, add something like this to
208 i18n/de.py (if you have >=0.11, the weekday translation might be already
209 there):
210
211 'Mon':'Mo','Tue':'Di','Wed':'Mi','Thu':'Do','Fri':'Fr','Sat':'Sa','Sun':'So',
212
213 'Invalid MonthCalendar calparms "%s"!':
214 'Ung\366ltige MonthCalendar calparms "%s"!',
215
216 'Invalid MonthCalendar arguments "%s"!':
217 'Ung\366ltige MonthCalendar Argumente "%s"!',
218
219 """
220
221 # Imports
222 from MoinMoin import config, user, wikiutil
223 from MoinMoin.Page import Page
224 import sys, re, calendar, time, string
225
226 # The following line sets the calendar to have either Sunday or Monday as
227 # the first day of the week. Only SUNDAY or MONDAY (case sensitive) are
228 # valid here. All other values will not make good calendars.
229 # If set to Sunday, the calendar is displayed at "March 2003" vs. "2003 / 3" also.
230 # XXX change here ----------------vvvvvv
231 calendar.setfirstweekday(calendar.SUNDAY)
232
233 def yearmonthplusoffset(year, month, offset):
234 month = month+offset
235 # handle offset and under/overflows - quick and dirty, yes!
236 while month < 1:
237 month = month+12
238 year = year-1
239 while month > 12:
240 month = month-12
241 year = year+1
242 return year, month
243
244 def parseargs(args, defpagename, defyear, defmonth, defoffset, defoffset2, defheight6, defanniversary):
245 strpagename = args.group('basepage')
246 if strpagename:
247 parmpagename = strpagename
248 else:
249 parmpagename = defpagename
250 # multiple pagenames separated by "*" - split into list of pagenames
251 parmpagename = re.split(r'\*', parmpagename)
252
253 stryear = args.group('year')
254 if stryear:
255 parmyear = int(stryear)
256 else:
257 parmyear = defyear
258
259 strmonth = args.group('month')
260 if strmonth:
261 parmmonth = int(strmonth)
262 else:
263 parmmonth = defmonth
264
265 stroffset = args.group('offset')
266 if stroffset:
267 parmoffset = int(stroffset)
268 else:
269 parmoffset = defoffset
270
271 stroffset2 = args.group('offset2')
272 if stroffset2:
273 parmoffset2 = int(stroffset2)
274 else:
275 parmoffset2 = defoffset2
276
277 strheight6 = args.group('height6')
278 if strheight6:
279 parmheight6 = int(strheight6)
280 else:
281 parmheight6 = defheight6
282 stranniversary = args.group('anniversary')
283 if stranniversary:
284 paramanniversary = int(stranniversary)
285 else:
286 paramanniversary = stranniversary
287
288 return parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, paramanniversary
289
290 # FIXME: vvvvvv is there a better way for matching a pagename ?
291 _arg_basepage = r'\s*(?P<basepage>[^, ]+)?\s*'
292 _arg_year = r',\s*(?P<year>\d+)?\s*'
293 _arg_month = r',\s*(?P<month>\d+)?\s*'
294 _arg_offset = r',\s*(?P<offset>[+-]?\d+)?\s*'
295 _arg_offset2 = r',\s*(?P<offset2>[+-]?\d+)?\s*'
296 _arg_height6 = r',\s*(?P<height6>[+-]?\d+)?\s*'
297 _arg_anniversary = r',\s*(?P<anniversary>[+-]?\d+)?\s*'
298 _args_re_pattern = r'^(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?$' % \
299 (_arg_basepage,_arg_year,_arg_month, \
300 _arg_offset,_arg_offset2,_arg_height6,_arg_anniversary)
301
302
303 def execute(macro, text):
304 _ = macro.request.getText
305
306 # return immediately if getting links for the current page
307 if macro.request.mode_getpagelinks:
308 return ''
309
310 args_re=re.compile(_args_re_pattern)
311
312 currentyear, currentmonth, currentday, h, m, s, wd, yd, ds = time.localtime(time.time())
313 thispage = macro.formatter.page.page_name
314 # does the url have calendar params (= somebody has clicked on prev/next links in calendar) ?
315 if macro.form.has_key('calparms'):
316 text2 = macro.form['calparms'][0]
317 args2 = args_re.match(text2)
318 if not args2:
319 return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar calparms "%s"!')) % (text2,)
320 else:
321 has_calparms = 1 # yes!
322 cparmpagename, cparmyear, cparmmonth, cparmoffset, cparmoffset2, cparmheight6, cparmanniversary = \
323 parseargs(args2, thispage, currentyear, currentmonth, 0, 0, 0, 0)
324 else:
325 has_calparms = 0
326
327 if text is None: # macro call without parameters
328 parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, anniversary = \
329 [thispage], currentyear, currentmonth, 0, 0, 0, 0
330 else:
331 # parse and check arguments
332 args = args_re.match(text)
333 if not args:
334 return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar arguments "%s"!')) % (text,)
335 else:
336 parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, anniversary = \
337 parseargs(args, thispage, currentyear, currentmonth, 0, 0, 0, 0)
338
339 # does url have calendar params and is THIS the right calendar to modify (we can have multiple
340 # calendars on the same page)?
341 if has_calparms and cparmpagename == parmpagename:
342 year,month = yearmonthplusoffset(parmyear, parmmonth, parmoffset + cparmoffset2)
343 parmoffset2 = cparmoffset2
344 else:
345 year,month = yearmonthplusoffset(parmyear, parmmonth, parmoffset)
346
347 if not has_calparms:
348 cparmpagename = parmpagename[0]
349
350 # get the calendar
351 monthcal = calendar.monthcalendar(year, month)
352
353 # european / US differences
354 months = ('January','February','March','April','May','June','July','August','September','October','November','December')
355 # Set things up for Monday or Sunday as the first day of the week
356 if calendar.firstweekday() == calendar.MONDAY:
357 wkend = (5, 6)
358 wkdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
359 if calendar.firstweekday() == calendar.SUNDAY:
360 wkend = (0, 6)
361 wkdays = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
362
363 p = Page(thispage)
364 querystr = "calparms=%s,%d,%d,%d,%%d" % (string.join(parmpagename,'*'), parmyear, parmmonth, parmoffset)
365 prevlink = p.url(macro.request, querystr % (parmoffset2 - 1))
366 nextlink = p.url(macro.request, querystr % (parmoffset2 + 1))
367 prevylink = p.url(macro.request, querystr % (parmoffset2 - 12))
368 nextylink = p.url(macro.request, querystr % (parmoffset2 + 12))
369 prevmonth = macro.formatter.url(prevlink, '<-', 'cal-link')
370 nextmonth = macro.formatter.url(nextlink, '->', 'cal-link')
371 prevyear = macro.formatter.url(prevylink, '<<-', 'cal-link')
372 nextyear = macro.formatter.url(nextylink, '->>', 'cal-link')
373
374 # multiple base pages?
375 if parmpagename <> [thispage]:
376 pagelinks = []
377 for page in parmpagename:
378 daypage=Page(page)
379 if page == cparmpagename:
380 csslink = "cal-thispage"
381 else:
382 csslink = "cal-otherpage"
383 pagelinks.append('<a class="%s" href="%s">%s</a>' % (csslink, daypage.url(macro.request), page))
384 del daypage
385 showpagename = ' %s<BR>\n' % '*'.join(pagelinks)
386 else:
387 showpagename = ''
388 if calendar.firstweekday() == calendar.SUNDAY:
389 resth1 = ' <th colspan="7" class="cal-header">\n' \
390 '%s' \
391 ' %s %s <b> %s %s</b> %s %s\n' \
392 ' </th>\n' % (showpagename, prevyear, prevmonth, months[month-1], str(year), nextmonth, nextyear)
393 if calendar.firstweekday() == calendar.MONDAY:
394 resth1 = ' <th colspan="7" class="cal-header">\n' \
395 '%s' \
396 ' %s %s <b> %s / %s</b> %s %s\n' \
397 ' </th>\n' % (showpagename, prevyear, prevmonth, str(year), month, nextmonth, nextyear)
398 restr1 = ' <tr>\n%s </tr>\n' % resth1
399
400 r7 = range(7)
401 restd2 = []
402 for wkday in r7:
403 wday = _(wkdays[wkday])
404 if wkday in wkend:
405 cssday = "cal-weekend"
406 else:
407 cssday = "cal-workday"
408 restd2.append(' <td class="%s cal-cell">%s</td>\n' % (cssday, wday))
409 restr2 = ' <tr>\n%s </tr>\n' % "".join(restd2)
410
411 if parmheight6:
412 while len(monthcal) < 6:
413 monthcal = monthcal + [[0,0,0,0,0,0,0]]
414
415 restrn = []
416 for week in monthcal:
417 restdn = []
418 for wkday in r7:
419 day = week[wkday]
420 if not day:
421 restdn.append(' <td class="cal-invalidday cal-cell"> </td>\n')
422 else:
423 csslink = "cal-emptyday"
424 page = parmpagename[0]
425 if anniversary:
426 link = "%s/%02d-%02d" % (page, month, day)
427 else:
428 link = "%s/%4d-%02d-%02d" % (page, year, month, day)
429 daypage = Page(link)
430 if daypage.exists():
431 csslink = "cal-usedday"
432 for otherpage in parmpagename[1:]:
433 otherlink = "%s/%4d-%02d-%02d" % (otherpage, year, month, day)
434 otherdaypage = Page(otherlink)
435 if otherdaypage.exists():
436 csslink = "cal-usedday"
437 fmtlink = macro.formatter.url(daypage.url(macro.request), str(day), csslink)
438 if day == currentday and month == currentmonth and year == currentyear:
439 cssday = "cal-today"
440 else:
441 if wkday in wkend:
442 cssday = "cal-weekend"
443 else:
444 cssday = "cal-workday"
445 restdn.append(' <td class="%s cal-cell">%s</td>\n' % (cssday, fmtlink))
446 restrn.append(' <tr>\n%s </tr>\n' % "".join(restdn))
447
448 restable = '<table class="cal-table">\n%s%s%s</table>\n'
449 result = restable % (restr1, restr2, "".join(restrn))
450 return macro.formatter.rawHTML(result)
451
452 # EOF
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.