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,'&lt;-','cal-link')
 325     nextmonth = macro.formatter.url(nextlink,'-&gt;','cal-link')
 326     prevyear  = macro.formatter.url(prevylink,'&lt;&lt;-','cal-link')
 327     nextyear  = macro.formatter.url(nextylink,'-&gt;&gt;','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&nbsp;%s&nbsp;<b>&nbsp;%s&nbsp;/&nbsp;%s</b>&nbsp;%s\n&nbsp;%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">&nbsp;</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.
  • [get | view] (2003-12-07 18:15:55, 14.1 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.