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 
  72 TODO:
  73     * integrate patch for including day page contents directly into cal
  74      * still thinking over: does this make sense in a MonthCalendar?
  75      * it would be definitely nice in a week or day calendar (more space to
  76        burn)
  77     * integr. daycal -link-> monthcal
  78 
  79 ----
  80 
  81     Usage:
  82         [[MonthCalendar(BasePage,year,month,monthoffset,monthoffset2,height6)]]
  83 
  84         each parameter can be empty and then defaults to currentpage or currentdate or monthoffset=0
  85 
  86     Samples (paste that to one of your pages for a first try):
  87 
  88 Calendar of current month for current page:
  89 [[MonthCalendar]]
  90 
  91 Calendar of last month:
  92 [[MonthCalendar(,,,-1)]]
  93 
  94 Calendar of next month:
  95 [[MonthCalendar(,,,+1)]]
  96 
  97 Calendar of Page SampleUser, this years december:
  98 [[MonthCalendar(SampleUser,,12)]]
  99 
 100 Calendar of current Page, this years december:
 101 [[MonthCalendar(,,12)]]
 102 
 103 Calendar of December, 2001:
 104 [[MonthCalendar(,2001,12)]]
 105 
 106 Calendar of the month two months after December, 2001
 107 (maybe doesn't make much sense, but is possible)
 108 [[MonthCalendar(,2001,12,+2)]]
 109 
 110 Calendar of year 2002 (every month padded to height of 6):
 111 ||||||Year 2002||
 112 ||[[MonthCalendar(,2002,1,,,1)]]||[[MonthCalendar(,2002,2,,,1)]]||[[MonthCalendar(,2002,3,,,1)]]||
 113 ||[[MonthCalendar(,2002,4,,,1)]]||[[MonthCalendar(,2002,5,,,1)]]||[[MonthCalendar(,2002,6,,,1)]]||
 114 ||[[MonthCalendar(,2002,7,,,1)]]||[[MonthCalendar(,2002,8,,,1)]]||[[MonthCalendar(,2002,9,,,1)]]||
 115 ||[[MonthCalendar(,2002,10,,,1)]]||[[MonthCalendar(,2002,11,,,1)]]||[[MonthCalendar(,2002,12,,,1)]]||
 116 
 117 Current calendar of me, also showing entries of A and B:
 118 [[MonthCalendar(MyPage*TestUserA*TestUserB)]]
 119 
 120 SubPage calendars:
 121 [[MonthCalendar(MyName/CalPrivate)]]
 122 [[MonthCalendar(MyName/CalBusiness)]]
 123 [[MonthCalendar(MyName/CalBusiness*MyName/CalPrivate)]]
 124 
 125 ----
 126 
 127     You need to have some stylesheet entries like the following.
 128     Paste that to  default.css / moinmoin.css:
 129     
 130 /* begin css for MonthCalendar macro */
 131 /* days without and with pages linked to them */
 132 a.cal-emptyday {
 133     color: #777777;
 134     text-align: center;
 135 }
 136 a.cal-usedday {
 137     font-weight: bold;
 138     color: #000000;
 139     text-align: center;
 140 }
 141 /* general stuff: workdays, weekend, today */
 142 td.cal-workday {
 143     background-color: #DDDDFF;
 144     text-align: center;
 145 }
 146 td.cal-weekend {
 147     background-color: #FFDDDD;
 148     text-align: center;
 149 }
 150 td.cal-today {
 151     background-color: #CCFFCC;
 152     border-style: solid;
 153     border-width: 2pt;
 154     text-align: center;
 155 }
 156 /* invalid places on the monthly calendar sheet */
 157 td.cal-invalidday {
 158     background-color: #CCCCCC;
 159 }
 160 /* links to prev/next month/year */
 161 a.cal-link {
 162     color: #000000;
 163     text-decoration: none;
 164 }
 165 th.cal-header {
 166     background-color: #DDBBFF;
 167     text-align: center;
 168 }
 169 /* end css for MonthCalendar macro */
 170 
 171 ----
 172 
 173     If you want translated (german) messages, add something like this to
 174     i18n/de.py (if you have >=0.11, the weekday translation might be already
 175     there):
 176     
 177 'Mon':'Mo','Tue':'Di','Wed':'Mi','Thu':'Do','Fri':'Fr','Sat':'Sa','Sun':'So',
 178     
 179 'Invalid MonthCalendar calparms "%s"!':
 180 'Ung\366ltige MonthCalendar calparms "%s"!',
 181 
 182 'Invalid MonthCalendar arguments "%s"!':
 183 'Ung\366ltige MonthCalendar Argumente "%s"!',
 184 
 185 """
 186 
 187 # Imports
 188 from MoinMoin import config, user, wikiutil
 189 from MoinMoin.Page import Page
 190 import sys, re, calendar, time, string
 191 
 192 # The following line sets the calendar to have either Sunday or Monday as
 193 # the first day of the week. Only SUNDAY or MONDAY (case sensitive) are
 194 # valid here.  All other values will not make good calendars.
 195 # If set to Sunday, the calendar is displayed at "March 2003" vs. "2003 / 3" also.
 196 # XXX change here ----------------vvvvvv
 197 calendar.setfirstweekday(calendar.MONDAY)
 198 
 199 def cliprgb(r,g,b): # don't use 255!
 200     if r < 0:   r=0
 201     if r > 254: r=254
 202     if b < 0:   b=0
 203     if b > 254: b=254
 204     if g < 0:   g=0
 205     if g > 254: g=254
 206     return r, g, b
 207 
 208 def yearmonthplusoffset(year, month, offset):
 209     month = month+offset
 210     # handle offset and under/overflows - quick and dirty, yes!
 211     while month < 1:
 212         month = month+12
 213         year = year-1
 214     while month > 12:
 215         month = month-12
 216         year = year+1
 217     return year, month
 218 
 219 def parseargs(args, defpagename, defyear, defmonth, defoffset, defoffset2, defheight6):
 220     strpagename = args.group('basepage')
 221     if strpagename:
 222         parmpagename = strpagename
 223     else:
 224         parmpagename = defpagename
 225     # multiple pagenames separated by "*" - split into list of pagenames
 226     parmpagename = re.split(r'\*', parmpagename)
 227 
 228     stryear = args.group('year')
 229     if stryear:
 230         parmyear = int(stryear)
 231     else:
 232         parmyear = defyear
 233 
 234     strmonth = args.group('month')
 235     if strmonth:
 236         parmmonth = int(strmonth)
 237     else:
 238         parmmonth = defmonth
 239     
 240     stroffset = args.group('offset')
 241     if stroffset:
 242         parmoffset = int(stroffset)
 243     else:
 244         parmoffset = defoffset
 245 
 246     stroffset2 = args.group('offset2')
 247     if stroffset2:
 248         parmoffset2 = int(stroffset2)
 249     else:
 250         parmoffset2 = defoffset2
 251 
 252     strheight6 = args.group('height6')
 253     if strheight6:
 254         parmheight6 = int(strheight6)
 255     else:
 256         parmheight6 = defheight6
 257 
 258     return parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6
 259         
 260 # FIXME:                          vvvvvv is there a better way for matching a pagename ?
 261 _arg_basepage = r'\s*(?P<basepage>[^, ]+)?\s*'
 262 _arg_year = r',\s*(?P<year>\d+)?\s*'
 263 _arg_month = r',\s*(?P<month>\d+)?\s*'
 264 _arg_offset = r',\s*(?P<offset>[+-]?\d+)?\s*'
 265 _arg_offset2 = r',\s*(?P<offset2>[+-]?\d+)?\s*'
 266 _arg_height6 = r',\s*(?P<height6>[+-]?\d+)?\s*'
 267 _args_re_pattern = r'^(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?$' % \
 268                    (_arg_basepage,_arg_year,_arg_month, \
 269 		    _arg_offset,_arg_offset2,_arg_height6)
 270 
 271 
 272 def execute(macro, text):
 273     _ = macro.request.getText
 274 
 275     # return immediately if getting links for the current page
 276     if macro.request.mode_getpagelinks:
 277         return ''
 278 
 279     args_re=re.compile(_args_re_pattern)
 280     
 281     currentyear, currentmonth, currentday, h, m, s, wd, yd, ds = time.localtime(time.time())
 282     thispage = macro.formatter.page.page_name
 283     # does the url have calendar params (= somebody has clicked on prev/next links in calendar) ?
 284     if macro.form.has_key('calparms'):
 285         text2 = macro.form['calparms'].value
 286         args2 = args_re.match(text2)
 287         if not args2:
 288             return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar calparms "%s"!')) % (text2,)
 289         else:
 290 	    has_calparms = 1 # yes!
 291 	    cparmpagename, cparmyear, cparmmonth, cparmoffset, cparmoffset2, cparmheight6 = \
 292                 parseargs(args2, thispage, currentyear, currentmonth, 0, 0, 0)
 293     else:
 294         has_calparms = 0
 295 	
 296     if text is None: # macro call without parameters
 297         parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6 = \
 298 	    [thispage], currentyear, currentmonth, 0, 0, 0
 299     else:
 300         # parse and check arguments
 301         args = args_re.match(text)
 302         if not args:
 303             return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar arguments "%s"!')) % (text,)
 304         else:
 305 	    parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6 = \
 306 	        parseargs(args, thispage, currentyear, currentmonth, 0, 0, 0)
 307 
 308     # does url have calendar params and is THIS the right calendar to modify (we can have multiple
 309     # calendars on the same page)?
 310     if has_calparms and (cparmpagename,cparmyear,cparmmonth,cparmoffset) == (parmpagename,parmyear,parmmonth,parmoffset):
 311         year,month = yearmonthplusoffset(parmyear, parmmonth, parmoffset + cparmoffset2)
 312 	parmoffset2 = cparmoffset2
 313     else:
 314         year,month = yearmonthplusoffset(parmyear, parmmonth, parmoffset)
 315 
 316     # get the calendar
 317     monthcal = calendar.monthcalendar(year, month)
 318 
 319     # european / US differences
 320     months = ('January','February','March','April','May','June','July','August','September','October','November','December')
 321     # Set things up for Monday or Sunday as the first day of the week
 322     if calendar.firstweekday() == calendar.MONDAY:
 323         wkend = (5, 6)
 324         wkdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
 325     if calendar.firstweekday() == calendar.SUNDAY:
 326         wkend = (0, 6)
 327         wkdays = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
 328 
 329     colorstep = 85
 330     p = Page(thispage)
 331     querystr = "calparms=%s,%d,%d,%d,%%d" % (string.join(parmpagename,'*'), parmyear, parmmonth, parmoffset)
 332     prevlink  = p.url(querystr % (parmoffset2 - 1))
 333     nextlink  = p.url(querystr % (parmoffset2 + 1))
 334     prevylink = p.url(querystr % (parmoffset2 - 12))
 335     nextylink = p.url(querystr % (parmoffset2 + 12))
 336     prevmonth = macro.formatter.url(prevlink, '&lt;-', 'cal-link')
 337     nextmonth = macro.formatter.url(nextlink, '-&gt;', 'cal-link')
 338     prevyear  = macro.formatter.url(prevylink, '&lt;&lt;-', 'cal-link')
 339     nextyear  = macro.formatter.url(nextylink, '-&gt;&gt;', 'cal-link')
 340     
 341     if parmpagename <> [thispage]:
 342         pagelinks = ''
 343         r,g,b = (255, 0, 0)
 344 	l = len(parmpagename[0])
 345         steps = len(parmpagename)
 346 	maxsteps = (255 / colorstep)
 347 	if steps > maxsteps:
 348 	    steps = maxsteps
 349 	chstep = int(l / steps)
 350 	st = 0
 351 	while st < l:
 352 	    ch = parmpagename[0][st:st+chstep]
 353 	    r, g, b = cliprgb(r, g, b)
 354 	    pagelinks = pagelinks + '<a style="%s" href="%s">%s</a>' % \
 355                 ('background-color:#%02x%02x%02x;color:#000000;text-decoration:none' % \
 356                     (r,g,b), Page(parmpagename[0]).url(), ch)
 357 	    r, g, b = (r, g+colorstep, b)
 358 	    st = st + chstep
 359         r, g, b = (255-colorstep, 255, 255-colorstep)
 360         for page in parmpagename[1:]:
 361 	    pagelinks = pagelinks + '*<a style="%s" href="%s">%s</a>' % \
 362 	                    ('background-color:#%02x%02x%02x;color:#000000;text-decoration:none' % \
 363                                 (r,g,b), Page(page).url(), page)
 364         showpagename = '   %s<BR>\n' % pagelinks
 365     else:
 366         showpagename = ''
 367     if calendar.firstweekday() == calendar.SUNDAY:
 368         resth1 = '  <th colspan="7" class="cal-header">\n' \
 369                  '%s' \
 370                  '   %s&nbsp;%s&nbsp;<b>&nbsp;%s&nbsp;%s</b>&nbsp;%s\n&nbsp;%s\n' \
 371                  '  </th>\n' % (showpagename, prevyear, prevmonth, months[month-1], str(year), nextmonth, nextyear)
 372     if calendar.firstweekday() == calendar.MONDAY:
 373         resth1 = '  <th colspan="7" class="cal-header">\n' \
 374                  '%s' \
 375 	         '   %s&nbsp;%s&nbsp;<b>&nbsp;%s&nbsp;/&nbsp;%s</b>&nbsp;%s\n&nbsp;%s\n' \
 376                  '  </th>\n' % (showpagename, prevyear, prevmonth, str(year), month, nextmonth, nextyear)
 377     restr1 = ' <tr>\n%s </tr>\n' % resth1
 378 
 379     r7 = range(7)
 380     restd2 = []
 381     for wkday in r7:
 382         wday = _(wkdays[wkday])
 383         if wkday in wkend:
 384             cssday = "cal-weekend"
 385         else:
 386             cssday = "cal-workday"
 387         restd2.append('  <td class="%s" width="14%%">%s</td>\n' % (cssday, wday))
 388     restr2 = ' <tr>\n%s </tr>\n' % "".join(restd2)
 389  
 390     if parmheight6:
 391         while len(monthcal) < 6:
 392             monthcal = monthcal + [[0,0,0,0,0,0,0]]
 393 	
 394     restrn = []
 395     for week in monthcal:
 396 	restdn = []
 397         for wkday in r7:
 398             day = week[wkday]
 399             if not day:
 400                 restdn.append('  <td class="cal-invalidday">&nbsp;</td>\n')
 401             else:
 402 	        csslink = "cal-emptyday"
 403 		r, g, b, u = (255, 255, 255, 0)
 404 		page = parmpagename[0]
 405                 link = "%s/%4d-%02d-%02d" % (page, year, month, day)
 406 	        daypage = Page(link)
 407 	        if daypage.exists():
 408     	            csslink = "cal-usedday"
 409 		    r, g, b, u = (255, 0, 0, 1)
 410 		else:
 411                     if wkday in wkend:
 412                         csslink = "cal-weekend"
 413                 for otherpage in parmpagename[1:]:
 414                     otherlink = "%s/%4d-%02d-%02d" % (otherpage, year, month, day)
 415 	            otherdaypage = Page(otherlink)
 416 	            if otherdaypage.exists():
 417     	                csslink = "cal-usedday"
 418 			if u == 0:
 419 			    r, g, b = (r-colorstep, g, b-colorstep)
 420 			else:
 421 			    r, g, b = (r, g+colorstep, b)
 422 		r, g, b = cliprgb(r, g, b)
 423 		style = 'background-color:#%02x%02x%02x' % (r, g, b)
 424 	        fmtlink = macro.formatter.url(daypage.url(), str(day), csslink)
 425 	        if day == currentday and month == currentmonth and year == currentyear:
 426 	            cssday = "cal-today"
 427                     fmtlink = "<b>%s</b>" % fmtlink # for browser with CSS probs
 428 		else:
 429 		    cssday = "cal-nottoday"
 430 	        restdn.append('  <td style="%s" class="%s">%s</td>\n' % (style, cssday, fmtlink))
 431         restrn.append(' <tr>\n%s </tr>\n' % "".join(restdn))
 432 
 433     restable = '<table border="2" cellspacing="2" cellpadding="2">\n%s%s%s</table>\n'
 434     result = restable % (restr1, restr2, "".join(restrn))
 435     return macro.formatter.rawHTML(result)
 436 
 437 # 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-04 13:15:01, 16.2 KB) [[attachment:MonthCalendar-moin12.py]]
  • [get | view] (2004-11-15 00:39:12, 16.9 KB) [[attachment:MonthCalendar-moin13.py]]
  • [get | view] (2003-12-07 18:15:54, 15.8 KB) [[attachment:MonthCalendar.py]]
 All files | Selected Files: delete move to page copy to page

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