Attachment 'HackedMonthCalendar.py'

Download

   1 """
   2     ##
   3     ## Great!!
   4     ## 100% invalid html 4.01 strict - and all for free!! So what do you want more??
   5     ##
   6     
   7     MoinMoin - HackedMonthCalendar Macro
   8     
   9     You can use this macro to put a month's calendar page on a Wiki page.
  10 
  11     The days are links to Wiki pages following this naming convention:
  12     BasePageName/year-month-day
  13 
  14     @copyright: 2002-2005 by Thomas Waldmann <ThomasWaldmann@gmx.de>
  15     @copyright: 2007-forever by Oliver Siemoneit
  16     @license: GNU GPL - see COPYING for details.
  17 
  18     Revisions:
  19     * first revision without a number (=1.0):
  20         * was only online for a few hours and then replaced by 1.1
  21     * 1.1:
  22         * changed name to MonthCalendar to avoid conflict with "calendar" under case-insensitive OSes like Win32
  23         * days as subpages
  24         * basepage argument
  25         * change order of year/month argument
  26         * browsing links to prev/next month/year
  27             * current limitation: you can only browse one calendar on the same
  28               page/url, if you try to browse another calendar on the same page,
  29               the first one jumps back to its original display
  30     * show basepage in calendar header if basepage<>currentpage
  31     * 1.2:
  32         * minor fixes in argument parsing
  33         * cosmetic fix for netscape, other cosmetic changes, changed css
  34         * i18n support (weekday short names)
  35     * 1.3:
  36         * fixes to run with MoinMoin 0.11, thanks to JuergenHermann
  37         * fix: withspace before "," allowed in argument list
  38         * BasePage in calendar header (if present) is a link now
  39         * more i18n
  40         * HTML cleanup, generating code avoids bracketing errors
  41         * colour cosmetics
  42     * 1.4:
  43         * new parameter for enabling fixed height of 6 "calendar weeks",
  44           if you want to show a whole year's calendar, this just looks
  45           better than having some months with 4, some with 5 and some with 6.
  46         * group calendaring functions:
  47           * you can give mutliple BasePages UserName1*UserName2*UserName3
  48           * first BasePage is considered "your" Basepage,
  49             used days are bright red
  50           * 2nd and all other BasePages are considered "others" BasePages
  51             and lead to an increasing green component the more "used" days
  52             the others have. So white gets greener and red gets more yellowish.
  53           * in the head part of the calendar, you can click on each name
  54             to get to the Page of the same name
  55           * colouring of my and others BasePage is done in a way to show
  56             the colouring used in the calendar:
  57           * others use green colouring (increasingly green if multiply used)
  58           * I use red colouring, which gets more and more yellowish as
  59             the day is used by more and more others, too
  60     * 1.5:
  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     * 1.6:
  67         * syntactic cleanup
  68         * removed i18n compatibility for moin<1.1 or cvs<2003-06-10
  69         * integrated Scott Chapman's changes:
  70             * Made it configurable for Sunday or Monday as the first day of the week.
  71               Search for "change here".
  72             * Made it so that today is not only set to a seperate css style, but also boldfaced.
  73               Some browsers don't show the other css style (Netscape).
  74             * Made it so weekend dates have different color.
  75     * 1.7:
  76         * added request parameter where needed
  77     * 1.8:
  78         * some fixes for moin 1.2 (use this version ONLY if you run moin 1.2, too):
  79             * .value backtrace fixed when selecting next/prev month/year
  80             * request param added to macro function
  81     * 1.9:
  82         * adapted to moin 1.3
  83     * 2.0:
  84         * integrated into moin 1.3
  85         * added some nice JS (thanks to Klaus Knopper) to show nice mouseovers
  86           showing a preview of the day page linked (use first level headlines
  87           to make entries)
  88         * merged "common navigation" change of OliverGraf
  89         * merged AnnualMonthlyCalendar change of JonathanDietrich
  90     * 2.1:
  91         * fixed CSS for IE users
  92         * fix javascript for IE4
  93         * do a correct calculation of "today" using user's timezone
  94     * 2.2:
  95         * added template argument for specifying an edit template for new pages
  96     * 2.3:
  97         * MonthCalender macro messed by Oliver Siemoneit in only two hours by adding some
  98           preview frame which is not allowed in html 4.01 strict...
  99 
 100     Usage:
 101         [[MonthCalendar(BasePage,year,month,monthoffset,monthoffset2,height6)]]
 102 
 103         each parameter can be empty and then defaults to currentpage or currentdate or monthoffset=0
 104 
 105     Samples (paste that to one of your pages for a first try):
 106 
 107 Calendar of current month for current page:
 108 [[MonthCalendar]]
 109 
 110 Calendar of last month:
 111 [[MonthCalendar(,,,-1)]]
 112 
 113 Calendar of next month:
 114 [[MonthCalendar(,,,+1)]]
 115 
 116 Calendar of Page SampleUser, this years december:
 117 [[MonthCalendar(SampleUser,,12)]]
 118 
 119 Calendar of current Page, this years december:
 120 [[MonthCalendar(,,12)]]
 121 
 122 Calendar of December, 2001:
 123 [[MonthCalendar(,2001,12)]]
 124 
 125 Calendar of the month two months after December, 2001
 126 (maybe doesn't make much sense, but is possible)
 127 [[MonthCalendar(,2001,12,+2)]]
 128 
 129 Calendar of year 2002 (every month padded to height of 6):
 130 ||||||Year 2002||
 131 ||[[MonthCalendar(,2002,1,,,1)]]||[[MonthCalendar(,2002,2,,,1)]]||[[MonthCalendar(,2002,3,,,1)]]||
 132 ||[[MonthCalendar(,2002,4,,,1)]]||[[MonthCalendar(,2002,5,,,1)]]||[[MonthCalendar(,2002,6,,,1)]]||
 133 ||[[MonthCalendar(,2002,7,,,1)]]||[[MonthCalendar(,2002,8,,,1)]]||[[MonthCalendar(,2002,9,,,1)]]||
 134 ||[[MonthCalendar(,2002,10,,,1)]]||[[MonthCalendar(,2002,11,,,1)]]||[[MonthCalendar(,2002,12,,,1)]]||
 135 
 136 Current calendar of me, also showing entries of A and B:
 137 [[MonthCalendar(MyPage*TestUserA*TestUserB)]]
 138 
 139 SubPage calendars:
 140 [[MonthCalendar(MyName/CalPrivate)]]
 141 [[MonthCalendar(MyName/CalBusiness)]]
 142 [[MonthCalendar(MyName/CalBusiness*MyName/CalPrivate)]]
 143 
 144 
 145 Anniversary Calendars: (no year data)
 146 [[MonthCalendar(Yearly,,,+1,,6,1)]]
 147 
 148 This creates calendars of the format Yearly/MM-DD 
 149 By leaving out the year, you can set birthdays, and anniversaries in this 
 150 calendar and not have to re-enter each year.
 151 
 152 This creates a calendar which uses MonthCalendarTemplate for directly editing
 153 nonexisting day pages:
 154 [[MonthCalendar(,,,,,,MonthCalendarTemplate)]]
 155 """
 156 
 157 Dependencies = ['namespace', 'time', ]
 158 
 159 from MoinMoin import wikiutil
 160 from MoinMoin.Page import Page
 161 import re, calendar, time
 162 
 163 # The following line sets the calendar to have either Sunday or Monday as
 164 # the first day of the week. Only SUNDAY or MONDAY (case sensitive) are
 165 # valid here.  All other values will not make good calendars.
 166 # If set to Sunday, the calendar is displayed at "March 2003" vs. "2003 / 3" also.
 167 # XXX change here ----------------vvvvvv
 168 calendar.setfirstweekday(calendar.MONDAY)
 169 
 170 def cliprgb(r, g, b): # don't use 255!
 171     if r < 0: r = 0
 172     if r > 254: r = 254
 173     if b < 0: b = 0
 174     if b > 254: b = 254
 175     if g < 0: g = 0
 176     if g > 254: g = 254
 177     return r, g, b
 178 
 179 def yearmonthplusoffset(year, month, offset):
 180     month = month+offset
 181     # handle offset and under/overflows - quick and dirty, yes!
 182     while month < 1:
 183         month = month + 12
 184         year = year - 1
 185     while month > 12:
 186         month = month - 12
 187         year = year + 1
 188     return year, month
 189 
 190 def parseargs(args, defpagename, defyear, defmonth, defoffset, defoffset2, defheight6, defanniversary, deftemplate):
 191     strpagename = args.group('basepage')
 192     if strpagename:
 193         parmpagename = wikiutil.unquoteWikiname(strpagename)
 194     else:
 195         parmpagename = defpagename
 196     # multiple pagenames separated by "*" - split into list of pagenames
 197     parmpagename = re.split(r'\*', parmpagename)
 198 
 199     stryear = args.group('year')
 200     if stryear:
 201         parmyear = int(stryear)
 202     else:
 203         parmyear = defyear
 204 
 205     strmonth = args.group('month')
 206     if strmonth:
 207         parmmonth = int(strmonth)
 208     else:
 209         parmmonth = defmonth
 210 
 211     stroffset = args.group('offset')
 212     if stroffset:
 213         parmoffset = int(stroffset)
 214     else:
 215         parmoffset = defoffset
 216 
 217     stroffset2 = args.group('offset2')
 218     if stroffset2:
 219         parmoffset2 = int(stroffset2)
 220     else:
 221         parmoffset2 = defoffset2
 222 
 223     strheight6 = args.group('height6')
 224     if strheight6:
 225         parmheight6 = int(strheight6)
 226     else:
 227         parmheight6 = defheight6
 228 
 229     stranniversary = args.group('anniversary')
 230     if stranniversary:
 231             parmanniversary = int(stranniversary)
 232     else:
 233         parmanniversary = defanniversary
 234 
 235     strtemplate = args.group('template')
 236     if strtemplate:
 237         parmtemplate = wikiutil.unquoteWikiname(strtemplate)
 238     else:
 239         parmtemplate = deftemplate
 240     return parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, parmanniversary, parmtemplate
 241 
 242 # FIXME:                          vvvvvv is there a better way for matching a pagename ?
 243 _arg_basepage = r'\s*(?P<basepage>[^, ]+)?\s*'
 244 _arg_year = r',\s*(?P<year>\d+)?\s*'
 245 _arg_month = r',\s*(?P<month>\d+)?\s*'
 246 _arg_offset = r',\s*(?P<offset>[+-]?\d+)?\s*'
 247 _arg_offset2 = r',\s*(?P<offset2>[+-]?\d+)?\s*'
 248 _arg_height6 = r',\s*(?P<height6>[+-]?\d+)?\s*'
 249 _arg_anniversary = r',\s*(?P<anniversary>[+-]?\d+)?\s*'
 250 _arg_template = r',\s*(?P<template>[^, ]+)?\s*' # XXX see basepage comment
 251 _args_re_pattern = r'^(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?$' % \
 252                      (_arg_basepage, _arg_year, _arg_month,
 253                       _arg_offset, _arg_offset2, _arg_height6, _arg_anniversary, _arg_template)
 254 
 255 
 256 def execute(macro, text):
 257     request = macro.request
 258     formatter = macro.formatter
 259     _ = request.getText
 260 
 261     # return immediately if getting links for the current page
 262     if request.mode_getpagelinks:
 263         return ''
 264 
 265     args_re = re.compile(_args_re_pattern)
 266 
 267     currentyear, currentmonth, currentday, h, m, s, wd, yd, ds = request.user.getTime(time.time())
 268     thispage = formatter.page.page_name
 269     # does the url have calendar params (= somebody has clicked on prev/next links in calendar) ?
 270     if macro.form.has_key('calparms'):
 271         text2 = macro.form['calparms'][0]
 272         args2 = args_re.match(text2)
 273         if not args2:
 274             return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar calparms "%s"!')) % (text2,)
 275         else:
 276             has_calparms = 1 # yes!
 277             cparmpagename, cparmyear, cparmmonth, cparmoffset, cparmoffset2, cparmheight6, cparmanniversary, cparmtemplate = \
 278                 parseargs(args2, thispage, currentyear, currentmonth, 0, 0, 0, 0, '')
 279     else:
 280         has_calparms = 0
 281 
 282     if text is None: # macro call without parameters
 283         parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, anniversary, parmtemplate = \
 284             [thispage], currentyear, currentmonth, 0, 0, 0, 0, ''
 285     else:
 286         # parse and check arguments
 287         args = args_re.match(text)
 288         if not args:
 289             return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar arguments "%s"!')) % (text,)
 290         else:
 291             parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, anniversary, parmtemplate = \
 292                 parseargs(args, thispage, currentyear, currentmonth, 0, 0, 0, 0, '')
 293 
 294     # does url have calendar params and is THIS the right calendar to modify (we can have multiple
 295     # calendars on the same page)?
 296     #if has_calparms and (cparmpagename,cparmyear,cparmmonth,cparmoffset) == (parmpagename,parmyear,parmmonth,parmoffset):
 297 
 298     # move all calendars when using the navigation:
 299     if has_calparms and cparmpagename == parmpagename:
 300         year, month = yearmonthplusoffset(parmyear, parmmonth, parmoffset + cparmoffset2)
 301         parmoffset2 = cparmoffset2
 302         parmtemplate = cparmtemplate
 303     else:
 304         year, month = yearmonthplusoffset(parmyear, parmmonth, parmoffset)
 305 
 306     # get the calendar
 307     monthcal = calendar.monthcalendar(year, month)
 308 
 309     # european / US differences
 310     months = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
 311     # Set things up for Monday or Sunday as the first day of the week
 312     if calendar.firstweekday() == calendar.MONDAY:
 313         wkend = (5, 6)
 314         wkdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
 315     if calendar.firstweekday() == calendar.SUNDAY:
 316         wkend = (0, 6)
 317         wkdays = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
 318 
 319     colorstep = 85
 320     p = Page(request, thispage)
 321     qpagenames = '*'.join(map(wikiutil.quoteWikinameURL, parmpagename))
 322     qtemplate = wikiutil.quoteWikinameURL(parmtemplate)
 323     querystr = "calparms=%%s,%d,%d,%d,%%d,%%s" % (parmyear, parmmonth, parmoffset)
 324     prevlink = p.url(request, querystr % (qpagenames, parmoffset2 - 1, qtemplate), escape=0)
 325     nextlink = p.url(request, querystr % (qpagenames, parmoffset2 + 1, qtemplate), escape=0)
 326     prevylink = p.url(request, querystr % (qpagenames, parmoffset2 - 12, qtemplate), escape=0)
 327     nextylink = p.url(request, querystr % (qpagenames, parmoffset2 + 12, qtemplate), escape=0)
 328     prevmonth = formatter.url(1, prevlink, 'cal-link') + '&lt;' + formatter.url(0)
 329     nextmonth = formatter.url(1, nextlink, 'cal-link') + '&gt;' + formatter.url(0)
 330     prevyear = formatter.url(1, prevylink, 'cal-link') + '&lt;&lt;' + formatter.url(0)
 331     nextyear = formatter.url(1, nextylink, 'cal-link') + '&gt;&gt;' + formatter.url(0)
 332 
 333     if parmpagename != [thispage]:
 334         pagelinks = ''
 335         r, g, b = (255, 0, 0)
 336         l = len(parmpagename[0])
 337         steps = len(parmpagename)
 338         maxsteps = (255 / colorstep)
 339         if steps > maxsteps:
 340             steps = maxsteps
 341         chstep = int(l / steps)
 342         st = 0
 343         while st < l:
 344             ch = parmpagename[0][st:st+chstep]
 345             r, g, b = cliprgb(r, g, b)
 346             link = Page(request, parmpagename[0]).link_to(request, ch,
 347                         style='background-color:#%02x%02x%02x;color:#000000;text-decoration:none' % (r, g, b))
 348             pagelinks = pagelinks + link
 349             r, g, b = (r, g+colorstep, b)
 350             st = st + chstep
 351         r, g, b = (255-colorstep, 255, 255-colorstep)
 352         for page in parmpagename[1:]:
 353             link = Page(request, page).link_to(request, page,
 354                         style='background-color:#%02x%02x%02x;color:#000000;text-decoration:none' % (r, g, b))
 355             pagelinks = pagelinks + '*' + link
 356         showpagename = '   %s<BR>\n' % pagelinks
 357     else:
 358         showpagename = ''
 359     if calendar.firstweekday() == calendar.SUNDAY:
 360         resth1 = '  <th colspan="7" class="cal-header">\n' \
 361                  '%s' \
 362                  '   %s&nbsp;%s&nbsp;<b>&nbsp;%s&nbsp;%s</b>&nbsp;%s\n&nbsp;%s\n' \
 363                  '  </th>\n' % (showpagename, prevyear, prevmonth, months[month-1], str(year), nextmonth, nextyear)
 364     if calendar.firstweekday() == calendar.MONDAY:
 365         resth1 = '  <th colspan="7" class="cal-header">\n' \
 366                  '%s' \
 367                  '   %s&nbsp;%s&nbsp;<b>&nbsp;%s&nbsp;/&nbsp;%s</b>&nbsp;%s\n&nbsp;%s\n' \
 368                  '  </th>\n' % (showpagename, prevyear, prevmonth, str(year), month, nextmonth, nextyear)
 369     restr1 = ' <tr>\n%s </tr>\n' % resth1
 370 
 371     r7 = range(7)
 372     restd2 = []
 373     for wkday in r7:
 374         wday = _(wkdays[wkday])
 375         if wkday in wkend:
 376             cssday = "cal-weekend"
 377         else:
 378             cssday = "cal-workday"
 379         restd2.append('  <td class="%s" width="14%%">%s</td>\n' % (cssday, wday))
 380     restr2 = ' <tr>\n%s </tr>\n' % "".join(restd2)
 381 
 382     if parmheight6:
 383         while len(monthcal) < 6:
 384             monthcal = monthcal + [[0, 0, 0, 0, 0, 0, 0]]
 385 
 386     maketip_js = []
 387     restrn = []
 388     for week in monthcal:
 389         restdn = []
 390         for wkday in r7:
 391             day = week[wkday]
 392             if not day:
 393                 restdn.append('  <td class="cal-invalidday">&nbsp;</td>\n')
 394             else:
 395                 page = parmpagename[0]
 396                 if anniversary:
 397                     link = "%s/%02d-%02d" % (page, month, day)
 398                 else:
 399                     link = "%s/%4d-%02d-%02d" % (page, year, month, day)
 400                 daypage = Page(request, link)
 401                 if daypage.exists():
 402                     csslink = "cal-usedday"
 403                     query = {}
 404                     r, g, b, u = (255, 0, 0, 1)
 405                     daycontent = daypage.get_raw_body()
 406                     header1_re = re.compile(r'^\s*=\s(.*)\s=$', re.MULTILINE) # re.UNICODE
 407                     titletext = []
 408                     for match in header1_re.finditer(daycontent):
 409                         if match:
 410                             title = match.group(1)
 411                             title = wikiutil.escape(title).replace("'", "\\'")
 412                             titletext.append(title)
 413                     tipname = link
 414                     tiptitle = link
 415                     tiptext = '<br>'.join(titletext)
 416                     maketip_js.append("maketip('%s','%s','%s');" % (tipname, tiptitle, tiptext))
 417                     onmouse = {'onClick': "updatePreview('%s', ''); return false;" % link,
 418                                'onMouseOver': "tip('%s')" % tipname,
 419                                'onMouseOut': "untip()"}
 420                 else:
 421                     csslink = "cal-emptyday"
 422                     if parmtemplate:
 423                         query = parmtemplate
 424                     else:
 425                         query = 'none'
 426                     r, g, b, u = (255, 255, 255, 0)
 427                     if wkday in wkend:
 428                         csslink = "cal-weekend"
 429                     onmouse = {'onClick': "updatePreview('%s', '%s'); return false;" % (link, query)}
 430                 for otherpage in parmpagename[1:]:
 431                     otherlink = "%s/%4d-%02d-%02d" % (otherpage, year, month, day)
 432                     otherdaypage = Page(request, otherlink)
 433                     if otherdaypage.exists():
 434                         csslink = "cal-usedday"
 435                         if u == 0:
 436                             r, g, b = (r-colorstep, g, b-colorstep)
 437                         else:
 438                             r, g, b = (r, g+colorstep, b)
 439                 r, g, b = cliprgb(r, g, b)
 440                 style = 'background-color:#%02x%02x%02x' % (r, g, b)
 441                 fmtlink = formatter.url(1, "#", csslink, **onmouse) + str(day) + formatter.url(0)
 442                 if day == currentday and month == currentmonth and year == currentyear:
 443                     cssday = "cal-today"
 444                     fmtlink = "<b>%s</b>" % fmtlink # for browser with CSS probs
 445                 else:
 446                     cssday = "cal-nottoday"
 447                 restdn.append('  <td style="%s" class="%s">%s</td>\n' % (style, cssday, fmtlink))
 448         restrn.append(' <tr>\n%s </tr>\n' % "".join(restdn))
 449 
 450     restable = '<table border="2" cellspacing="2" cellpadding="2">\n%s%s%s</table>\n'
 451     restable = restable % (restr1, restr2, "".join(restrn))
 452 
 453     result = """\
 454 <script language="JavaScript" type="text/javascript" src="%s/common/js/infobox.js"></script>
 455 <script language="JavaScript" type="text/javascript">
 456 <!--
 457 function updatePreview(link, template) {
 458     var preview = document.getElementById('calendar_preview');
 459     if(template == ''){
 460         preview.setAttribute("src", link);
 461     }
 462     else if(template == 'none') {
 463         preview.setAttribute("src", link + + "?action=edit");
 464     }
 465     else {
 466         preview.setAttribute("src", link + "?action=edit&template=" + template);
 467     }
 468 }
 469 // -->
 470 </script>
 471 <div id="infodiv" style="position:absolute; visibility:hidden; z-index:20; top:-999em; left:0px;"></div>
 472 <script language="JavaScript" type="text/javascript">
 473 <!--
 474 %s
 475 // -->
 476 </script>
 477 %s
 478 <br>
 479 <iframe src="" width="800px" height="400px" id="calendar_preview">
 480 <p>%s</p>
 481 </iframe>
 482 """ % (request.cfg.url_prefix_static, "\n".join(maketip_js), restable, _('Your browser does not support inlined frames.'))
 483     return formatter.rawHTML(result)
 484 
 485 # 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] (2007-03-26 19:33:58, 19.8 KB) [[attachment:HackedMonthCalendar.py]]
  • [get | view] (2008-01-31 19:50:28, 80.7 KB) [[attachment:sc.png]]
 All files | Selected Files: delete move to page copy to page

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