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

You are not allowed to attach a file to this page.