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