Attachment 'EventCalendar-096.py'
Download 1 """
2 EventCalendar.py Version 0.96 April 17, 2006
3
4 This macro gives a list of the events recorded at the sub-pages in the form of various views:
5 monthly, weekly, daily, simple-month, list, and upcoming.
6
7 @copyright: 2006 by Seungik Lee <seungiklee<at>gmail.com> http://www.silee.net/
8 @license: GPL
9
10 For more information, please visit http://moinmoin.wikiwikiweb.de/MacroMarket/EventCalendar
11
12 <Usage>
13
14 * To list the events in a page, just insert [[EventCalendar]]
15 * To insert an event, insert the event information in any pages of specified category (CategoryEventCalendar by default).
16
17 <Parameters>
18
19 * category: the category of the event data to be used in the calendar. default: 'CategoryEventCalendar'
20 * menubar: shows menubar or not (1: show, 0: no menubar). default: 1
21 * monthlywidth: calendar width in pixel or percent (monthly view). default: '600' (pixel)
22 * simplewidth: calendar width in pixel or percent (simpleview). default: '150' (pixel)
23 * firstview: initial calendar view: monthly, weekly, daily, list, simple, upcoming. default: 'monthly'
24 * curdate: initial calendar date (in YYYYMM format). default: current month
25 * upcomingrange: # of days for the range of upcoming event list. default: 7 (days)
26 * changeview: enables to change the calendar view or not (1: enalbed, 0: disabled). default: 1
27 * numcal: # of calendar. default: 1
28
29
30 <Event Data Format>
31
32 * Example:
33
34 [default_description:: [default_description_text]]
35 [default_bgcolor:: [default_custom_background_color]]
36
37 == <title> ==
38 start:: <startdate> [starttime]
39 [end:: [enddate] [endtime]]
40 [description:: [description_text]]
41 [bgcolor:: [custom_background_color]]
42 [recur:: <recur_freq> <recur_type> [until <recur_until>]]
43
44 ...
45
46 ----
47 CategoryEventCalendar
48
49
50 * title: event title. required
51 * should be enclosed with heading marker ('='), Title cannot be omitted.
52
53 * startdate: date of start. required
54 * should be in YYYY/MM/DD or YYYY-MM-DD
55
56 * starttime: time of start. optional
57 * should be in HH:MM in 24-hour format
58
59 * enddate: date of end. optional
60 * should be in YYYY/MM/DD or YYYY-MM-DD. If omitted, it will be assigned equal to <startdate>.
61
62 * endtime: time of end. optional
63 * should be in HH:MM in 24-hour format. Both of start|end Time can be omitted but not either of them.
64
65 * description: description of the event. optional
66 * any text with no markup. should be in a line.
67
68 * bgcolor: custom background color of the event in monthly view. optional
69 * e.g., #abcdef
70
71 * recur: recurrence information of the event, optional
72 * recur_freq: how many intervals, digit, required
73 * recur_type: [day|week|weekday|month|year], required
74 * day: every [recur_freq] days
75 * week: every [recur_freq] weeks
76 * weekday: on the same weekday of [recur_freq]-th week of the month
77 * month: on the same day of [recur_freq]-th month
78 * year: on the same day of [recur_freq]-th year
79 * recur_until: recurred until when, YYYY/MM/DD or YYYY-MM-DD, optional
80
81 * e.g., 10 day, 2 week until 2006-06-31, 3 weekday, 6 month until 2007-12-31, 1 year
82
83 * default_bgcolor, default_description: default values of bgcolor and description in the page if unavailable
84
85 * The order of the fields after an event title does not matter.
86
87 <Event Data Examples>
88
89 = Default values =
90 default_bgcolor:: #c0c0c0
91 default_description:: testing...
92
93 === Test event ===
94 start:: 2006-01-10 14:00
95 end:: 2006-01-12 17:00
96 description:: test event
97 bgcolor:: #cfcfcf
98
99 === Jinah's Birthday ===
100 start:: 1977-10-20
101 recur:: 1 year
102
103 === Weekly meeting ===
104 start:: 2006-01-17 19:00
105 end:: 21:00
106 recur:: 1 week until 2006-12-31
107
108 ----
109 CategoryEventCalendar
110
111
112 <Notes>
113
114 * It caches all the page list of the specified category and the event information.
115 * If you added/removed a page into/from a category, you need to do 'Delete cache' in the macro page.
116
117 * 'MonthCalendar.py' developed by Thomas Waldmann <ThomasWaldmann@gmx.de> has inspired this macro.
118 * Much buggy.. : please report bugs and suggest your ideas.
119 * If you missed to add css for EventCalender, monthly view may not be readable.
120 * Insert the EventCalendar css classes into the screen.css of an appropriate theme.
121
122
123
124 """
125
126 from MoinMoin import wikiutil, config, search, caching
127 from MoinMoin.Page import Page
128 from MoinMoin.parser import wiki
129 import re, calendar, time, datetime
130 import codecs, os, urllib, sha
131
132 try:
133 import cPickle as pickle
134 except ImportError:
135 import pickle
136
137 # Set pickle protocol, see http://docs.python.org/lib/node64.html
138 PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
139
140
141 # The following line sets the calendar to have either Sunday or Monday as
142 # the first day of the week. Only SUNDAY or MONDAY (case sensitive) are
143 # valid here. All other values will not make good calendars.
144 # XXX change here ----------------vvvvvv
145 calendar.setfirstweekday(calendar.SUNDAY)
146
147
148 class Globs:
149 month_style_us = 1 # 1: October 2005; 2: 2005 / 10
150 defaultcategory = 'CategoryEventCalendar'
151 upcomingrange = 7 # days
152 dailystart = 9
153 dailyend = 18
154 pagename = ''
155 baseurl = ''
156 subname = ''
157 wkend = ''
158 months = ''
159 wkdays = ''
160 today = ''
161 now = ''
162 request = None
163 formatter = None
164 cal_action = ''
165 debugmsg = ''
166 page_action = ''
167 form_vals = {}
168 events = None
169
170
171 class Params:
172 menubar = 0
173 monthlywidth = ''
174 weeklywidth = ''
175 dailywidth = ''
176 simplewidth = ''
177 firstview = ''
178 curdate = ''
179 bgcolor = ''
180 category = ''
181 upcomingrange = 0
182 changeview = 0
183 numcal = 1
184 debug = 0
185
186
187 def execute(macro, args):
188
189 request = macro.request
190 formatter = macro.formatter
191
192 # INITIALIZATION ----------------------------------------
193 setglobalvalues(macro)
194 getparams(args)
195
196 # allowed actions
197 allowed_action = ['monthly', 'list', 'simple', 'upcoming', 'daily', 'weekly']
198 default_action = Params.firstview
199
200 # Internal variables
201 cal_action = ''
202 form_vals = {}
203
204 # PROCESSING ARGUEMENTS ----------------------------------------
205 if args:
206 args=request.getText(args)
207
208 for item in macro.form.items():
209 if not form_vals.has_key(item[0]):
210 try:
211 form_vals[item[0]]=item[1][0]
212 except AttributeError:
213 pass
214
215 # PROCESSING ACTIONS ----------------------------------------
216 cal_action = form_vals.get('calaction', default_action)
217 page_action = form_vals.get('action', 'show')
218
219 if not cal_action in allowed_action:
220 cal_action = default_action
221
222 form_vals['calaction'] = cal_action
223
224 Globs.form_vals = form_vals
225
226 # CONTROL FUNCTIONS ----------------------------------------
227
228 html = []
229 html_result = ''
230
231 Globs.cal_action = cal_action
232 Globs.page_action = page_action
233
234
235 # redirect to the appropriate view
236 if cal_action == 'monthly':
237 html_result = showcalendar()
238
239 if cal_action == 'list':
240 html_result = showeventlist()
241
242 if cal_action == 'simple':
243 html_result = showsimplecalendar()
244
245 if cal_action == 'upcoming':
246 html_result = showupcomingeventlist()
247
248 if cal_action == 'daily':
249 html_result = showdailycalendar()
250
251 if cal_action == 'weekly':
252 html_result = showweeklycalendar()
253
254
255 # format output
256 html.append( html_result )
257 html.append( showmenubar() )
258
259 if Params.debug and Globs.debugmsg:
260 html.append(u'<p><b>Debug messages:</b><font color="#aa0000"><ol>%s</ol></font>' % Globs.debugmsg)
261
262 return formatter.rawHTML(u''.join(html))
263
264
265
266 def getparams(args):
267 # process arguments
268
269 params = {}
270 if args:
271 # Arguments are comma delimited key=value pairs
272 sargs = args.split(',')
273
274 for item in sargs:
275 sitem = item.split('=')
276
277 if len(sitem) == 2:
278 key, value = sitem[0], sitem[1]
279 params[key.strip()] = value.strip()
280
281 # category name:
282 # default: 'CategoryEventCalendar'
283 Params.category = params.get('category', Globs.defaultcategory)
284
285 # menu bar: shows menubar or not (1: show, 0: no menubar)
286 # default: 1
287 try:
288 Params.menubar = int(params.get('menubar', 1))
289 except (TypeError, ValueError):
290 Params.menubar = 1
291
292 # calendar width in pixel or percent (monthly)
293 # default: 600px
294 Params.monthlywidth = params.get('monthlywidth', '600')
295 if Params.monthlywidth:
296 Params.monthlywidth = ' width="%s" ' % Params.monthlywidth
297
298 # calendar width in pixel or percent (weekly)
299 # default: 600px
300 Params.weeklywidth = params.get('weeklywidth', '600')
301 if Params.weeklywidth:
302 Params.weeklywidth = ' width="%s" ' % Params.weeklywidth
303
304 # calendar width in pixel or percent (daily)
305 # default: 600px
306 Params.dailywidth = params.get('dailywidth', '600')
307 if Params.monthlywidth:
308 Params.dailywidth = ' width="%s" ' % Params.dailywidth
309
310 # calendar width in pixel or percent (simply)
311 # default: 150px
312 Params.simplewidth = params.get('simplewidth', '150')
313 if Params.simplewidth:
314 # Params.simplewidth = Params.simplewidth.replace('%', '%%')
315 Params.simplewidth = ' width="%s" ' % Params.simplewidth
316
317 # calendar view: monthly, list, simple
318 # default: 'monthly'
319 Params.firstview = params.get('firstview', 'monthly')
320
321 # calendar date: in YYYYMM format (in monthly, simple view)
322 # default: current month
323 Params.curdate = params.get('curdate', '')
324
325 # upcoming range: # of days for upcoming event list
326 # default: 7
327 try:
328 Params.upcomingrange = int(params.get('upcomingrange', Globs.upcomingrange))
329 except (TypeError, ValueError):
330 Params.upcomingrange = Globs.upcomingrange
331
332 # number of calendar: # of calendar for monthly & simple view
333 # default: 1
334 try:
335 Params.numcal = int(params.get('numcal', '1'))
336 except (TypeError, ValueError):
337 Params.numcal = 1
338
339 # change view enabled?
340 # default: 1
341 try:
342 Params.changeview = int(params.get('changeview', '1'))
343 except (TypeError, ValueError):
344 Params.changeview = 1
345
346 # default bgcolor
347 Params.bgcolor = '#ddffdd'
348
349
350 def setglobalvalues(macro):
351
352 request = macro.request
353 formatter = macro.formatter
354
355 # Useful variables
356 Globs.baseurl = request.getBaseURL() + '/'
357 Globs.pagename = formatter.page.page_name
358 Globs.request = request
359 Globs.formatter = formatter
360 Globs.pageurl = '%s/%s' % (request.getScriptname(), wikiutil.quoteWikinameURL(formatter.page.page_name))
361
362 # This fixes the subpages bug. subname is now used instead of pagename when creating certain urls
363 Globs.subname = Globs.pagename.split('/')[-1]
364
365 pagepath = formatter.page.getPagePath()
366 Globs.pagepath = formatter.page.getPagePath()
367
368 # european / US differences
369 months = ('January','February','March','April','May','June','July','August','September','October','November','December')
370
371 # Set things up for Monday or Sunday as the first day of the week
372 if calendar.firstweekday() == calendar.MONDAY:
373 wkend = 6
374 wkdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
375 elif calendar.firstweekday() == calendar.SUNDAY:
376 wkend = 0
377 wkdays = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
378
379 Globs.months = months
380 Globs.wkdays = wkdays
381 Globs.wkend = wkend
382
383 year, month, day, h, m, s, wd, yd, ds = request.user.getTime(time.time())
384 Globs.today = datetime.date(year, month, day)
385 Globs.now = datetime.time(h, m, s)
386
387 Globs.debugmsg = ''
388
389
390 def showReferPageParsed(event, targettext='title', showdesc=0):
391 request = Globs.request
392 pagename = Globs.pagename
393
394 refer = event['refer']
395 targettext = event[targettext]
396 startdate = event['startdate']
397 enddate = event['enddate']
398 description = event['description']
399 starttime = event['starttime']
400 endtime = event['endtime']
401 hid = event['hid']
402
403 refer_url = '%s/%s' % (request.getScriptname(), wikiutil.quoteWikinameURL(refer))
404
405 if not Params.changeview:
406 refer_url = ''
407 hid = ''
408
409 if showdesc:
410 if (startdate == enddate) and (starttime and endtime):
411 timedescription = '(%s:%s ~ %s:%s)' % (starttime[:2], starttime[2:], endtime[:2], endtime[2:])
412 if description:
413 timedescription = '%s ' % timedescription
414 else:
415 timedescription = ''
416
417 targetlink = '<a href="%s#%s" title="%s%s">%s</a>' % ( refer_url, hid, timedescription, wikiutil.escape(description), wikiutil.escape(targettext) )
418
419 else:
420 targetlink = '<a href="%s#%s">%s</a>' % ( refer_url, hid, wikiutil.escape(targettext))
421
422 return targetlink
423
424
425 def getheadingid(request, referpage, title):
426
427 pntt = (referpage + title).encode(config.charset)
428 hid = "head-" + sha.new(pntt).hexdigest()
429 request._page_headings.setdefault(pntt, 0)
430 request._page_headings[pntt] += 1
431 if request._page_headings[pntt] > 1:
432 hid += '-%d'%(request._page_headings[pntt],)
433
434 return hid
435
436
437 def getquerystring(req_fields):
438
439 m_query = []
440 tmp_form_vals = Globs.form_vals
441
442 # format querystring
443 # action should be poped out
444 for field in req_fields:
445 if tmp_form_vals.has_key(field):
446 m_query.append(u'%s=%s' % (field, tmp_form_vals[field]) )
447
448 if 'prevcalaction' in req_fields:
449 if not tmp_form_vals.has_key('prevcalaction'):
450 m_query.append(u'%s=%s' % ('prevcalaction', tmp_form_vals['calaction']) )
451
452 m_query = u'&'.join(m_query)
453
454 if m_query:
455 m_query = '&%s' % m_query
456
457 return m_query
458
459
460 # bottom menu bar
461 def showmenubar():
462
463 request = Globs.request
464 cal_action = Globs.cal_action
465 page_name = Globs.pagename
466
467 page_url = Globs.pageurl
468
469 if not Params.menubar: return ''
470
471 if cal_action == 'simple':
472 menuwidth = Params.simplewidth
473 elif cal_action == 'monthly':
474 menuwidth = Params.monthlywidth
475 else:
476 menuwidth = ''
477
478 left_menu_selected = []
479 right_menu_selected = []
480
481 # Go Today
482 year, month, day = gettodaydate()
483 mnu_curmonthcal = u'<a href="%s?calaction=%s&caldate=%d%02d%02d%s" title="Go Today">[Today]</a>' % (page_url, cal_action, year, month, day, getquerystring(['numcal']))
484
485 # List View
486 mnu_listview = u'<a href="%s?calaction=list%s" title="List of all events">[List]</a>' % (page_url, getquerystring(['caldate', 'numcal']))
487
488 # Monthly View
489 mnu_monthview = u'<a href="%s?calaction=monthly%s" title="Monthly view">[Monthly]</a>' % (page_url, getquerystring(['caldate', 'numcal']) )
490
491 # Simple Calendar View
492 mnu_simpleview = u'<a href="%s?calaction=simple%s" title="Simple calendar view">[Simple]</a>' % (page_url, getquerystring(['caldate', 'numcal']) )
493
494 # Upcoming Event List
495 mnu_upcomingview = u'<a href="%s?calaction=upcoming%s" title="Upcoming event list">[Upcoming]</a>' % (page_url, getquerystring(['caldate', 'numcal']) )
496
497 # Daily View
498 mnu_dayview = u'<a href="%s?calaction=daily%s" title="Daily view">[Daily]</a>' % (page_url, getquerystring(['caldate', 'numcal']) )
499
500 # Weekly View
501 mnu_weekview = u'<a href="%s?calaction=weekly%s" title="Weekly view">[Weekly]</a>' % (page_url, getquerystring(['caldate', 'numcal']) )
502
503 html = [
504 u'\r\n',
505 u'<table class="eventcalendar_menubar" %s>',
506 u' <tr>',
507 u' <td class="eventcalendar_menubar" align="left">%s</td>',
508 u' <td class="eventcalendar_menubar" align="right">%s</td>',
509 u' </tr>',
510 u'</table>',
511 ]
512
513 if cal_action == 'list':
514 left_menu_selected.append(mnu_monthview)
515 left_menu_selected.append(mnu_weekview)
516 left_menu_selected.append(mnu_dayview)
517 left_menu_selected.append(mnu_simpleview)
518 right_menu_selected.append(mnu_upcomingview)
519
520 elif cal_action == 'simple':
521 left_menu_selected.append(mnu_monthview)
522 left_menu_selected.append(mnu_weekview)
523 left_menu_selected.append(mnu_dayview)
524 right_menu_selected.append(mnu_listview)
525 right_menu_selected.append(mnu_upcomingview)
526 right_menu_selected.append(mnu_curmonthcal)
527
528 elif cal_action == 'upcoming':
529 left_menu_selected.append(mnu_monthview)
530 left_menu_selected.append(mnu_weekview)
531 left_menu_selected.append(mnu_dayview)
532 left_menu_selected.append(mnu_simpleview)
533 right_menu_selected.append(mnu_listview)
534
535 elif cal_action == 'weekly':
536 left_menu_selected.append(mnu_monthview)
537 left_menu_selected.append(mnu_dayview)
538 left_menu_selected.append(mnu_simpleview)
539 right_menu_selected.append(mnu_upcomingview)
540 right_menu_selected.append(mnu_listview)
541 right_menu_selected.append(mnu_curmonthcal)
542
543 elif cal_action == 'daily':
544 left_menu_selected.append(mnu_monthview)
545 left_menu_selected.append(mnu_weekview)
546 left_menu_selected.append(mnu_simpleview)
547 right_menu_selected.append(mnu_upcomingview)
548 right_menu_selected.append(mnu_listview)
549 right_menu_selected.append(mnu_curmonthcal)
550
551 else:
552 left_menu_selected.append(mnu_weekview)
553 left_menu_selected.append(mnu_dayview)
554 left_menu_selected.append(mnu_simpleview)
555 right_menu_selected.append(mnu_upcomingview)
556 right_menu_selected.append(mnu_listview)
557 right_menu_selected.append(mnu_curmonthcal)
558
559 left_menu_selected = u'\r\n'.join(left_menu_selected)
560 right_menu_selected = u'\r\n'.join(right_menu_selected)
561
562 html = u'\r\n'.join(html)
563 html = html % (menuwidth, left_menu_selected, right_menu_selected)
564
565 return html
566
567
568 def getdatefield(str_date):
569 str_year = ''
570 str_month = ''
571 str_day = ''
572
573 if len(str_date) == 6:
574 # year+month
575 str_year = str_date[:4]
576 str_month = str_date[4:]
577 str_day = '1'
578
579 elif len(str_date) == 8:
580 # year+month+day
581 str_year = str_date[:4]
582 str_month = str_date[4:6]
583 str_day = str_date[6:]
584
585 elif len(str_date) == 10:
586 # year+?+month+?+day
587 str_year = str_date[:4]
588 str_month = str_date[5:7]
589 str_day = str_date[8:]
590
591 else:
592 raise ValueError
593
594 # It raises exception if the input date is incorrect
595 temp = datetime.date(int(str_year), int(str_month), int(str_day))
596
597 return temp.year, temp.month, temp.day
598
599
600 def gettimefield(str_time):
601 str_hour = ''
602 str_min = ''
603
604 if len(str_time) == 4:
605 # hour+minute
606 str_hour = str_time[:2]
607 str_min = str_time[2:]
608
609 elif len(str_time) == 5:
610 # hour+?+minute
611 str_hour = str_time[:2]
612 str_min = str_time[3:]
613
614 else:
615 raise ValueError
616
617 # It raises exception if the input date is incorrect
618 temp = datetime.time(int(str_hour), int(str_min))
619
620 return temp.hour, temp.minute
621
622
623 def gettodaydate():
624 today = Globs.today
625 return today.year, today.month, today.day
626
627
628 def cal_listhead():
629
630 html = [
631 u' <tr>',
632 u' <td class="list_head">Title</td>',
633 u' <td class="list_head">Start Date</td>',
634 u' <td class="list_head">End Date</td>',
635 u' <td class="list_head">Recurrence</td>',
636 u' <td class="list_head">Description</td>',
637 u' <td class="list_head">Reference</td>',
638 u' </tr>',
639 ]
640
641 return u'\r\n'.join(html)
642
643
644 def showeventlist():
645
646 debug('Show Calendar: List view')
647
648 request = Globs.request
649 formatter = Globs.formatter
650
651 html_event_rows = []
652 html_list_header = cal_listhead()
653
654 # read all the events
655 events, cal_events = loadEvents()
656
657 # sort events
658 sorted_eventids = events.keys()
659 sorted_eventids.sort(comp_list_events)
660
661 for eid in sorted_eventids:
662 if not events[eid]['clone']:
663 html_event_rows.append( listshow_event(events[eid]) )
664
665 html_event_rows = u'\r\n'.join(html_event_rows)
666
667 html_list_table = [
668 u'\r\n<div id="eventlist">',
669 u'<table class="eventlist">',
670 u'%s' % html_list_header,
671 u'%s' % html_event_rows,
672 u'</table>',
673 u'</div>',
674 ]
675 html_list_table = u'\r\n'.join(html_list_table)
676
677 return html_list_table
678
679
680 def listshow_event(event):
681
682 if event['recur_freq']:
683 recur_desc = 'every %d %s' % (event['recur_freq'], event['recur_type'])
684 if event['recur_until']:
685 recur_desc = '%s until %s' % (recur_desc, formatcfgdatetime(event['recur_until']))
686 else:
687 recur_desc = ''
688
689 html = [
690 u' <tr>',
691 u' <td class="list_entry">%s</td>' % converttext(event['title']),
692 u' <td class="list_entry">%s</td>' % formatcfgdatetime(event['startdate'], event['starttime']),
693 u' <td class="list_entry">%s</td>' % formatcfgdatetime(event['enddate'], event['endtime']),
694 u' <td class="list_entry">%s</td>' % recur_desc,
695 u' <td class="list_entry">%s</td>' % converttext(event['description']),
696 u' <td class="list_entry">%s</td>' % showReferPageParsed(event, 'refer'),
697 u' </tr>',
698 ]
699
700 return u'\r\n'.join(html)
701
702
703 def showupcomingeventlist():
704
705 debug('Show Calendar: Upcoming Event View')
706
707 request = Globs.request
708 formatter = Globs.formatter
709
710 html_event_rows = []
711 html_list_header = cal_listhead()
712
713 year, month, day = gettodaydate()
714 day_delta = datetime.timedelta(days=Params.upcomingrange)
715 cur_date = datetime.date(year, month, day)
716 next_range = cur_date + day_delta
717
718 # set ranges of events
719 datefrom = u'%04d%02d%02d' % (year, month, day)
720 dateto = u'%04d%02d%02d' % (next_range.year, next_range.month, next_range.day)
721
722 # read all the events (no cache)
723 events, cal_events = loadEvents(datefrom, dateto, 1)
724
725 nowtime = formattimeobject(Globs.now)
726
727 datefrom = formatcfgdatetime(cur_date, nowtime)
728 #u'%04d-%02d-%02d %s:%s' % (year, month, day, nowtime[:2], nowtime[2:])
729 dateto = formatcfgdatetime(formatdateobject(next_range))
730 #u'%04d-%02d-%02d' % (next_range.year, next_range.month, next_range.day)
731
732 # sort events
733 sorted_eventids = events.keys()
734 sorted_eventids.sort(comp_list_events)
735
736 for eid in sorted_eventids:
737 if events[eid]['enddate'] >= formatdateobject(Globs.today):
738 if (not events[eid]['endtime']) or events[eid]['endtime'] >= formattimeobject(Globs.now):
739 html_event_rows.append( listshow_event(events[eid]) )
740
741 html_event_rows = u'\r\n'.join(html_event_rows)
742
743 html_list_table = [
744 u'\r\n<div id="eventlist">',
745 u'<table class="eventlist">',
746 u'<tr><td colspan="7" class="list_entry" style="border-width: 0px;"><b>Upcoming Event List: %s ~ %s</b><p><br><p></td></tr>' % (datefrom, dateto),
747 u'%s' % html_list_header,
748 u'%s' % html_event_rows,
749 u'</table>',
750 u'</div>',
751 ]
752 html_list_table = u'\r\n'.join(html_list_table)
753
754 return html_list_table
755
756
757
758
759 def showcalendar():
760
761 request = Globs.request
762 formatter = Globs.formatter
763 form_vals = Globs.form_vals
764
765 html = []
766
767 if form_vals.has_key('caldate'):
768 try:
769 year, month, str_temp = getdatefield(form_vals['caldate'])
770 except (TypeError, ValueError):
771 debug('Invalid target date: e.g., "200510"')
772 year, month, dy = gettodaydate()
773 elif Params.curdate:
774 try:
775 year, month, str_temp = getdatefield(Params.curdate)
776 except (TypeError, ValueError):
777 debug('Invalid target date: e.g., "200510"')
778 year, month, dy = gettodaydate()
779
780 else:
781 year, month, dy = gettodaydate()
782
783 # check number of calendar
784 numcal = Params.numcal
785
786 if form_vals.has_key('numcal'):
787 try:
788 numcal = int(form_vals['numcal'])
789 except (TypeError, ValueError):
790 debug('Invalid number of calendar: e.g., 3')
791
792 if numcal < 1:
793 numcal = 1
794 elif numcal > 12:
795 numcal = 12
796
797 for index in range(numcal):
798
799 cyear, cmonth = yearmonthplusoffset(year, month, index)
800
801 cal_html = showeventcalendar(cyear, cmonth)
802 html.append(cal_html)
803
804 return u''.join(html)
805
806
807 def showdailycalendar():
808
809 request = Globs.request
810 formatter = Globs.formatter
811
812 form_vals = Globs.form_vals
813
814 if form_vals.has_key('caldate'):
815 try:
816 year, month, dy = getdatefield(form_vals['caldate'])
817
818 if len(form_vals['caldate']) <= 6:
819 tyear, tmonth, tdy = gettodaydate()
820 if tyear == year and month == tmonth:
821 dy = tdy
822
823 except (TypeError, ValueError):
824 debug('Invalid target date: e.g., "20051020"')
825 year, month, dy = gettodaydate()
826
827 elif Params.curdate:
828 try:
829 year, month, dy = getdatefield(Params.curdate)
830 except (TypeError, ValueError):
831 debug('Invalid target date: e.g., "200510"')
832 year, month, dy = gettodaydate()
833
834 else:
835 year, month, dy = gettodaydate()
836
837 html = showdailyeventcalendar(year, month, dy)
838
839 return u''.join(html)
840
841
842 def showweeklycalendar():
843
844 request = Globs.request
845 formatter = Globs.formatter
846
847 form_vals = Globs.form_vals
848
849 if form_vals.has_key('caldate'):
850 try:
851 year, month, dy = getdatefield(form_vals['caldate'])
852
853 if len(form_vals['caldate']) <= 6:
854 tyear, tmonth, tdy = gettodaydate()
855 if tyear == year and month == tmonth:
856 dy = tdy
857
858 except (TypeError, ValueError):
859 debug('Invalid target date: e.g., "20051020"')
860 year, month, dy = gettodaydate()
861
862 elif Params.curdate:
863 try:
864 year, month, dy = getdatefield(Params.curdate)
865 except (TypeError, ValueError):
866 debug('Invalid target date: e.g., "200510"')
867 year, month, dy = gettodaydate()
868 else:
869 year, month, dy = gettodaydate()
870
871 html = showweeklyeventcalendar(year, month, dy)
872
873 return u''.join(html)
874
875
876 def showsimplecalendar():
877
878 request = Globs.request
879 formatter = Globs.formatter
880 form_vals = Globs.form_vals
881
882 html = []
883
884 if form_vals.has_key('caldate'):
885 try:
886 year, month, str_temp = getdatefield(form_vals['caldate'])
887 except (TypeError, ValueError):
888 debug('Invalid target date: e.g., "200510"')
889 year, month, dy = gettodaydate()
890 elif Params.curdate:
891 try:
892 year, month, str_temp = getdatefield(Params.curdate)
893 except (TypeError, ValueError):
894 debug('Invalid target date: e.g., "200510"')
895 year, month, dy = gettodaydate()
896 else:
897 year, month, dy = gettodaydate()
898
899 # check number of calendar
900 numcal = Params.numcal
901
902 if form_vals.has_key('numcal'):
903 try:
904 numcal = int(form_vals['numcal'])
905 except (TypeError, ValueError):
906 debug('Invalid number of calendar: e.g., 3')
907
908 if numcal < 1:
909 numcal = 1
910 elif numcal > 12:
911 numcal = 12
912
913 for index in range(numcal):
914
915 cyear, cmonth = yearmonthplusoffset(year, month, index)
916
917 cal_html = showsimpleeventcalendar(cyear, cmonth)
918 html.append(cal_html)
919
920 return u''.join(html)
921
922
923
924 # sort events in cal_events by length of days of the event
925 def comp_cal_events(xid, yid):
926 events = Globs.events
927
928 if events[xid]['date_len'] > events[yid]['date_len']:
929 return -1
930 elif events[xid]['date_len'] == events[yid]['date_len']:
931 if events[xid]['date_len'] == 1:
932 if events[xid]['starttime'] == events[yid]['starttime']:
933 return cmp(events[yid]['time_len'], events[xid]['time_len'])
934 else:
935 return cmp(events[xid]['starttime'], events[yid]['starttime'])
936 else:
937 return 0
938 else:
939 return 1
940
941
942 # sort events in the list by start date of the event
943 def comp_list_events(xid, yid):
944 events = Globs.events
945
946 return cmp(events[xid]['startdate'], events[yid]['startdate'])
947
948 # load events from wiki pages
949 def loadEvents(datefrom='', dateto='', nocache=0):
950
951 request = Globs.request
952
953 debug('Loading event information.')
954
955 events = {}
956 cal_events = {}
957 raw_events = {}
958
959 raw_events = loadEventsFromWikiPages()
960
961 # handling cal_events
962 if datefrom or dateto:
963
964 # cache configurations
965 arena = Page(request, Globs.pagename)
966 eventkey = 'events'
967 filteredeventkey = 'events_%s-%s' % (datefrom, dateto)
968 caleventkey = 'calevents_%s-%s' % (datefrom, dateto)
969
970 cache_events = caching.CacheEntry(request, arena, eventkey)
971 cache_filteredevents = caching.CacheEntry(request, arena, filteredeventkey)
972 cache_calevents = caching.CacheEntry(request, arena, caleventkey)
973
974 dirty = 1
975
976 debug('Checking cal_events cache')
977
978 if not (cache_calevents.needsUpdate(cache_events._filename()) or cache_filteredevents.needsUpdate(cache_events._filename())):
979
980 try:
981 events = pickle.loads(cache_filteredevents.content())
982 cal_events = pickle.loads(cache_calevents.content())
983 debug('Cached event (filtered) information is used: total %d events' % len(events))
984 dirty = 0
985 except (pickle.UnpicklingError, IOError, EOFError, ValueError):
986 debug('Picke error at fetching cached events (filtered)')
987 events = {}
988 cal_events = {}
989
990
991 # if cache is dirty, update the cache
992 if dirty:
993
994 debug('Checking event cache: it\'s dirty or requested to refresh')
995 debug('Building new cal_event information')
996
997 try:
998 datefrom, dateto = int(datefrom), int(dateto)
999 except (TypeError, ValueError):
1000 datefrom, dateto = 0, 0
1001
1002 clone_num = 0
1003
1004 for e_id in raw_events.keys():
1005
1006 cur_event = raw_events[e_id]
1007
1008 # handling event recurrence
1009 recur_freq = cur_event['recur_freq']
1010
1011 if recur_freq:
1012
1013 if not (cur_event['recur_until'] and int(cur_event['recur_until']) < datefrom) or int(cur_event['startdate']) > dateto:
1014
1015 if not (int(cur_event['enddate']) < datefrom or int(cur_event['startdate']) > dateto):
1016 # generating cal_events for iteself
1017 events[e_id] = cur_event.copy()
1018 insertcalevents(cal_events, datefrom, dateto, e_id, cur_event['startdate'], cur_event['enddate'])
1019
1020 delta_date_len = datetime.timedelta(days = int(cur_event['date_len']) - 1 )
1021
1022 if cur_event['recur_type'] == 'day':
1023
1024 day_delta = int(recur_freq)
1025 startdate = getdatetimefromstring(cur_event['startdate'])
1026 datefrom_date = getdatetimefromstring(datefrom)
1027
1028 if int(datefrom) > int(cur_event['startdate']):
1029 diffs = datefrom_date - startdate
1030 q_delta = diffs.days / day_delta
1031 if diffs.days % day_delta > 0:
1032 q_delta += 1
1033 else:
1034 q_delta = 1
1035
1036 while 1:
1037
1038 if q_delta == 0:
1039 q_delta += 1
1040 continue
1041
1042 recurred_startdate = startdate + datetime.timedelta(days = q_delta * day_delta )
1043 recurred_enddate = recurred_startdate + delta_date_len
1044
1045 new_startdate = formatdateobject(recurred_startdate)
1046 new_enddate = formatdateobject(recurred_enddate)
1047
1048 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
1049 break
1050
1051 clone_num += 1
1052 clone_id = 'c%d' % clone_num
1053
1054 events[clone_id] = cur_event.copy()
1055 events[clone_id]['id'] = clone_id
1056 events[clone_id]['startdate'] = new_startdate
1057 events[clone_id]['enddate'] = new_enddate
1058 events[clone_id]['clone'] = 1
1059
1060 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
1061
1062 q_delta += 1
1063
1064 elif cur_event['recur_type'] == 'week':
1065
1066 day_delta = int(recur_freq) * 7
1067
1068 startdate = getdatetimefromstring(cur_event['startdate'])
1069 datefrom_date = getdatetimefromstring(datefrom)
1070
1071 if int(datefrom) > int(cur_event['startdate']):
1072 diffs = datefrom_date - startdate
1073 q_delta = diffs.days / day_delta
1074 if diffs.days % day_delta > 0:
1075 q_delta += 1
1076 else:
1077 q_delta = 1
1078
1079 while 1:
1080
1081 if q_delta == 0:
1082 q_delta += 1
1083 continue
1084
1085 recurred_startdate = startdate + datetime.timedelta(days = q_delta * day_delta )
1086 recurred_enddate = recurred_startdate + delta_date_len
1087
1088 new_startdate = formatdateobject(recurred_startdate)
1089 new_enddate = formatdateobject(recurred_enddate)
1090
1091 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
1092 break
1093
1094 clone_num += 1
1095 clone_id = 'c%d' % clone_num
1096
1097 events[clone_id] = cur_event.copy()
1098 events[clone_id]['id'] = clone_id
1099 events[clone_id]['startdate'] = new_startdate
1100 events[clone_id]['enddate'] = new_enddate
1101 events[clone_id]['clone'] = 1
1102
1103 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
1104
1105 q_delta += 1
1106
1107
1108 elif cur_event['recur_type'] == 'weekday':
1109
1110 syear, smonth, sday = getdatefield(cur_event['startdate'])
1111 cyear, cmonth, cday = getdatefield(str(datefrom))
1112
1113 recur_weekday = calendar.weekday(syear, smonth, sday)
1114
1115
1116 while 1:
1117
1118 firstweekday, daysinmonth = calendar.monthrange(cyear, cmonth)
1119 firstmatch = (recur_weekday - firstweekday) % 7 + 1
1120
1121 #XXX should handle error
1122 try:
1123 therecur_day = xrange(firstmatch, daysinmonth + 1, 7)[recur_freq-1]
1124 except IndexError:
1125 therecur_day = xrange(firstmatch, daysinmonth + 1, 7)[-1]
1126
1127 recurred_startdate = datetime.date(cyear, cmonth, therecur_day)
1128 recurred_enddate = recurred_startdate + delta_date_len
1129
1130 new_startdate = formatdateobject(recurred_startdate)
1131 new_enddate = formatdateobject(recurred_enddate)
1132
1133 if int(new_startdate) < int(datefrom):
1134 cyear, cmonth = yearmonthplusoffset(cyear, cmonth, 1)
1135 continue
1136
1137 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
1138 break
1139
1140 clone_num += 1
1141 clone_id = 'c%d' % clone_num
1142
1143 events[clone_id] = cur_event.copy()
1144 events[clone_id]['id'] = clone_id
1145 events[clone_id]['startdate'] = new_startdate
1146 events[clone_id]['enddate'] = new_enddate
1147 events[clone_id]['clone'] = 1
1148
1149 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
1150
1151 cyear, cmonth = yearmonthplusoffset(cyear, cmonth, 1)
1152
1153
1154 elif cur_event['recur_type'] == 'month':
1155
1156 cyear, cmonth, therecurday = getdatefield(cur_event['startdate'])
1157
1158 while 1:
1159
1160 cyear, cmonth = yearmonthplusoffset(cyear, cmonth, recur_freq)
1161 firstweekday, daysinmonth = calendar.monthrange(cyear, cmonth)
1162 recur_day = therecurday
1163 if daysinmonth < recur_day:
1164 recur_day = daysinmonth
1165 new_startdate = formatDate(cyear, cmonth, recur_day)
1166
1167 if int(new_startdate) < int(datefrom):
1168 continue
1169
1170 recurred_startdate = datetime.date(cyear, cmonth, recur_day)
1171 recurred_enddate = recurred_startdate + delta_date_len
1172
1173 new_startdate = formatdateobject(recurred_startdate)
1174 new_enddate = formatdateobject(recurred_enddate)
1175
1176 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
1177 break
1178
1179 clone_num += 1
1180 clone_id = 'c%d' % clone_num
1181
1182 events[clone_id] = cur_event.copy()
1183 events[clone_id]['id'] = clone_id
1184 events[clone_id]['startdate'] = new_startdate
1185 events[clone_id]['enddate'] = new_enddate
1186 events[clone_id]['clone'] = 1
1187
1188 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
1189
1190 elif cur_event['recur_type'] == 'year':
1191
1192 ryear, rmonth, rday = getdatefield(cur_event['startdate'])
1193 cyear, cmonth, cday = getdatefield(str(datefrom))
1194
1195 while 1:
1196
1197 ryear += recur_freq
1198 new_startdate = formatDate(ryear, rmonth, rday)
1199
1200 if int(new_startdate) < int(datefrom):
1201 continue
1202
1203 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
1204 break
1205
1206 recurred_startdate = datetime.date(ryear, rmonth, rday)
1207 recurred_enddate = recurred_startdate + delta_date_len
1208
1209 new_startdate = formatdateobject(recurred_startdate)
1210 new_enddate = formatdateobject(recurred_enddate)
1211
1212 clone_num += 1
1213 clone_id = 'c%d' % clone_num
1214
1215 events[clone_id] = cur_event.copy()
1216 events[clone_id]['id'] = clone_id
1217 events[clone_id]['startdate'] = new_startdate
1218 events[clone_id]['enddate'] = new_enddate
1219 events[clone_id]['clone'] = 1
1220
1221 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
1222
1223 else:
1224
1225 if not (int(cur_event['enddate']) < datefrom or int(cur_event['startdate']) > dateto):
1226 events[e_id] = cur_event.copy()
1227 insertcalevents(cal_events, datefrom, dateto, e_id, cur_event['startdate'], cur_event['enddate'])
1228
1229 # sort cal_events
1230 # store event list into global variables in order to sort them
1231 Globs.events = events
1232
1233 for eachdate in cal_events.keys():
1234 cal_events[eachdate].sort(comp_cal_events)
1235
1236 # cache update
1237 if not nocache:
1238 cache_filteredevents.update(pickle.dumps(events, PICKLE_PROTOCOL))
1239 cache_calevents.update(pickle.dumps(cal_events, PICKLE_PROTOCOL))
1240
1241 else:
1242 events = raw_events
1243
1244 # store event list into global variables in order to sort them
1245 Globs.events = events
1246
1247 debug(u'Total %d of events are loaded finally.' % len(events))
1248
1249 return events, cal_events
1250
1251
1252
1253 def loadEventsFromWikiPages():
1254
1255 events = {}
1256
1257 eventrecord_list = []
1258 eventpages = []
1259
1260 request = Globs.request
1261 category = Params.category
1262
1263 # cache configurations
1264 arena = Page(request, Globs.pagename)
1265 eventkey = 'events'
1266 pagelistkey = 'eventpages'
1267
1268 cache_events = caching.CacheEntry(request, arena, eventkey)
1269 cache_pages = caching.CacheEntry(request, arena, pagelistkey)
1270
1271
1272 # page list cache
1273
1274 debug('Checking page list cache')
1275
1276 # check the time at which page list cache has been created
1277
1278 cp_mtime = cache_pages.mtime()
1279 timedelta_days = 9999
1280
1281 if cp_mtime:
1282 cp_date = datetime.datetime.fromtimestamp(cp_mtime)
1283 today = datetime.datetime.fromtimestamp(time.time())
1284 datediff = today - cp_date
1285 timedelta_days = datediff.days
1286 debug('Time from page list cache built = %s' % datediff)
1287
1288
1289 if Globs.page_action == 'refresh' or cache_pages.needsUpdate(arena._text_filename()) or timedelta_days >= 1:
1290 categorypages = searchPages(request, category)
1291 for page in categorypages:
1292 eventpages.append(page.page_name)
1293 cache_pages.update('\n'.join(eventpages), True)
1294 debug('New page list is built: %d pages' % len(eventpages))
1295 else:
1296 eventpages = cache_pages.content(True).split('\n')
1297 debug('Cached page list is used: %d pages' % len(eventpages))
1298
1299
1300 # generating events
1301
1302 dirty = 0
1303 dirty_local = 0
1304 debug_records = {}
1305
1306 # fetch event records from each page in the category
1307 for page_name in eventpages:
1308
1309 p = Page(request, page_name)
1310 e_ref = page_name
1311
1312 eventrecordkey = 'eventrecords'
1313 cache_eventrecords = caching.CacheEntry(request, p, eventrecordkey)
1314
1315 if cache_eventrecords.needsUpdate(p._text_filename()) or Globs.page_action == 'refresh':
1316 dirty = 1
1317 page_content = p.get_raw_body()
1318 eventrecords = getEventRecordFromPage(page_content, e_ref)
1319 debug_records[e_ref] = '%d eventrecords are fetched from %s' % (len(eventrecords), e_ref)
1320 cache_eventrecords.update(pickle.dumps(eventrecords, PICKLE_PROTOCOL))
1321 else:
1322 try:
1323 eventrecords = pickle.loads(cache_eventrecords.content())
1324
1325 debug_records[e_ref] = '%d cached eventrecords are used from %s' % (len(eventrecords), e_ref)
1326
1327 if cache_events.needsUpdate(p._text_filename()):
1328 dirty_local = 1
1329
1330 except (pickle.UnpicklingError, IOError, EOFError, ValueError):
1331 dirty = 1
1332 page_content = p.get_raw_body()
1333 eventrecords = getEventRecordFromPage(page_content, e_ref)
1334 debug_records[e_ref] = '%d eventrecords are fetched from %s due to pickle error' % (len(eventrecords), e_ref)
1335 cache_eventrecords.update(pickle.dumps(eventrecords, PICKLE_PROTOCOL))
1336
1337 eventrecord_list.append(eventrecords)
1338
1339 # if no dirty, just fetch the cache
1340 if not (dirty or dirty_local or Globs.page_action == 'refresh'):
1341
1342 debug('Checking event cache: still valid')
1343
1344 try:
1345 events = pickle.loads(cache_events.content())
1346 debug('Cached event information is used: total %d events' % len(events))
1347 except (pickle.UnpicklingError, IOError, EOFError, ValueError):
1348 debug('Picke error at fetching cached events')
1349 events = {}
1350
1351 else:
1352
1353 debug('Checking event cache: it\'s dirty or requested to refresh')
1354
1355 # if there is no events (if it needs refreshed), generate events dictionary
1356 if not len(events.keys()):
1357
1358 # XXX: just debugging
1359 debug('Building new event information')
1360 for page_name in eventpages:
1361 debug(debug_records[page_name])
1362
1363 day_delta = datetime.timedelta(days=1)
1364
1365 for eventrecords in eventrecord_list:
1366
1367 for evtrecord in eventrecords:
1368
1369 e_id = evtrecord['id']
1370
1371 # generating events
1372 events[e_id] = evtrecord
1373
1374 # after generating updated events, update the cache
1375 cache_events.update(pickle.dumps(events, PICKLE_PROTOCOL))
1376
1377 debug('Event information is newly built: total %d events' % len(events))
1378
1379 # end of updating events block
1380
1381
1382 return events
1383
1384
1385
1386 def getEventRecordFromPage(pagecontent, referpage):
1387
1388 request = Globs.request
1389
1390 eventrecords = []
1391 page_bgcolor = ''
1392 page_description = ''
1393
1394 e_num = 0
1395
1396 # fetch the page default bgcolor
1397 regex_page_bgcolor = r"""
1398 ^\s+default_bgcolor::\s*
1399 (?P<pagebgcolor>\#[0-9a-fA-F]{6})
1400 \s*
1401 $
1402 """
1403
1404 pattern = re.compile(regex_page_bgcolor, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1405 match = pattern.search(pagecontent)
1406
1407 if match:
1408 page_bgcolor = match.group('pagebgcolor')
1409
1410 # fetch the page default description
1411 regex_page_description = r"""
1412 ^\s+default_description::\s*
1413 (?P<pagedescription>.*?)
1414 $
1415 """
1416
1417 pattern = re.compile(regex_page_description, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1418 match = pattern.search(pagecontent)
1419
1420 if match:
1421 page_description = match.group('pagedescription')
1422
1423
1424 # fetch event item
1425 regex_eventitem = r"""
1426 (?P<eventitem>
1427 (?P<heading>^\s*(?P<hmarker>=+)\s(?P<eventtitle>.*?)\s(?P=hmarker) $)
1428 (?P<eventdetail>.*?
1429 (?=
1430 ^\s*(?P<nexthmarker>=+)\s(?P<nexteventtitle>.*?)\s(?P=nexthmarker) $
1431 | \Z
1432 )
1433 )
1434 )
1435 """
1436
1437 pattern = re.compile(regex_eventitem, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1438 match = pattern.findall(pagecontent)
1439
1440 if match:
1441
1442 for matchitem in match:
1443
1444 eventitem = {}
1445
1446 eventtitle = matchitem[3]
1447 eventdetail = matchitem[4]
1448
1449 try:
1450 e_start_date, e_start_time, e_end_date, e_end_time, e_bgcolor, e_description, e_recur_freq, e_recur_type, e_recur_until = geteventfield(eventdetail)
1451 except (TypeError, ValueError):
1452 #debug('An event data is corrupted: invalid event format')
1453 continue
1454
1455 # set default values
1456 if not e_bgcolor:
1457 e_bgcolor = page_bgcolor
1458
1459 if not e_description:
1460 e_description = page_description
1461
1462 e_num += 1
1463 e_id = 'e_%s_%d' % (referpage, e_num)
1464
1465 eventitem['id'] = e_id
1466 eventitem['title'] = eventtitle
1467 eventitem['startdate'] = e_start_date
1468 eventitem['starttime'] = e_start_time
1469 eventitem['enddate'] = e_end_date
1470 eventitem['endtime'] = e_end_time
1471 eventitem['title'] = eventtitle
1472 eventitem['refer'] = referpage
1473 eventitem['bgcolor'] = e_bgcolor
1474 eventitem['description'] = e_description
1475 eventitem['recur_freq'] = e_recur_freq
1476 eventitem['recur_type'] = e_recur_type
1477 eventitem['recur_until'] = e_recur_until
1478
1479 eventitem['date_len'] = diffday(e_start_date, e_end_date) + 1
1480 eventitem['clone'] = 0
1481 eventitem['hid'] = getheadingid(request, referpage, eventtitle)
1482
1483 if eventitem['date_len'] == 1 and e_start_time and e_end_time:
1484 eventitem['time_len'] = difftime(e_start_time, e_end_time) + 1
1485 else:
1486 eventitem['time_len'] = 0
1487
1488 eventrecords.append(eventitem)
1489
1490 return eventrecords
1491
1492
1493
1494 def geteventfield(detail):
1495
1496 regex_startdate = r"""
1497 ^\s+start::\s*
1498 (?P<startdate>\d{4}[/-]\d{2}[/-]\d{2})
1499 \s*
1500 (?P<starttime>\d{2}[:]\d{2})*
1501 \s*
1502 $
1503 """
1504
1505 regex_enddate = r"""
1506 ^\s+end::\s*
1507 (?P<enddate>\d{4}[/-]\d{2}[/-]\d{2})*
1508 \s*
1509 (?P<endtime>\d{2}[:]\d{2})*
1510 \s*
1511 $
1512 """
1513
1514 regex_bgcolor = r"""
1515 ^\s+bgcolor::\s*
1516 (?P<bgcolor>\#[0-9a-fA-F]{6})
1517 \s*
1518 $
1519 """
1520
1521 regex_description = r"""
1522 ^\s+description::\s*
1523 (?P<description>.*?)
1524 $
1525 """
1526
1527 regex_recur = r"""
1528 ^\s+recur::\s*
1529 (?P<recur_freq>\d+)
1530 \s*
1531 (?P<recur_type>day|week|weekday|month|year)
1532 \s*
1533 (
1534 until
1535 \s*
1536 (?P<recur_until>\d{4}[/-]\d{2}[/-]\d{2})
1537 )*
1538 $
1539 """
1540
1541 # need help on regular expressions for more efficient/flexible form
1542
1543 # compile regular expression objects
1544
1545 pattern_startdate = re.compile(regex_startdate, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1546 pattern_enddate = re.compile(regex_enddate, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1547 pattern_bgcolor = re.compile(regex_bgcolor, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1548 pattern_description = re.compile(regex_description, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1549 pattern_recur = re.compile(regex_recur, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1550
1551 ##################### retrieve startdate
1552 match = pattern_startdate.search(detail)
1553
1554 if match:
1555 startdate = match.group('startdate')
1556 starttime = match.group('starttime')
1557 else:
1558 startdate = ''
1559 starttime = ''
1560
1561 ##################### retrieve enddate
1562 match = pattern_enddate.search(detail)
1563
1564 if match:
1565 enddate = match.group('enddate')
1566 endtime = match.group('endtime')
1567 else:
1568 enddate = ''
1569 endtime = ''
1570
1571 ##################### retrieve bgcolor
1572 match = pattern_bgcolor.search(detail)
1573
1574 if match:
1575 bgcolor = match.group('bgcolor')
1576 else:
1577 bgcolor = ''
1578
1579 ##################### retrieve description
1580 match = pattern_description.search(detail)
1581
1582 if match:
1583 description = match.group('description')
1584 else:
1585 description = ''
1586
1587 ##################### retrieve recurrence
1588 match = pattern_recur.search(detail)
1589
1590 if match:
1591 recur_freq = int(match.group('recur_freq'))
1592 recur_type = match.group('recur_type')
1593 recur_until = match.group('recur_until')
1594
1595 else:
1596 recur_freq = 0
1597 recur_type = ''
1598 recur_until = ''
1599
1600
1601 # check validity of each fields
1602
1603 if not startdate:
1604 #debug('start date is not specified')
1605 # self.printoutput('Parse Error', msg, '')
1606 # ERROR
1607 return '','','','','','','','','',''
1608
1609 #if (starttime or endtime) and not (starttime and endtime):
1610 #debug('no or 2 time field should be specified')
1611 # ERROR
1612 #return '','','','','','','','','',''
1613
1614 if (starttime or endtime):
1615 if not endtime:
1616 endtime = starttime
1617 elif not starttime:
1618 #debug('endtime field should be specified')
1619 # ERROR
1620 return '','','','','','','','','',''
1621
1622
1623 # if no time, it's 1-day event
1624 if not enddate:
1625 enddate = startdate
1626
1627 try:
1628 syear, smonth, sday = getdatefield(startdate)
1629 eyear, emonth, eday = getdatefield(enddate)
1630 except (TypeError, ValueError):
1631 #debug('invalid date format: %s, %s' % (startdate, enddate))
1632 return '','','','','','','','','',''
1633
1634 if datetime.date(syear, smonth, sday) > datetime.date(eyear, emonth, eday):
1635 #debug('startdate should precede enddate')
1636 return '','','','','','','','','',''
1637
1638 # format date
1639 startdate = formatDate(syear, smonth, sday)
1640 enddate = formatDate(eyear, emonth, eday)
1641
1642 if (starttime and endtime):
1643 try:
1644 shour, smin = gettimefield(starttime)
1645 ehour, emin = gettimefield(endtime)
1646 except (TypeError, ValueError):
1647 #debug('invalid time format: %s, %s' % (startdate, enddate))
1648 return '','','','','','','','','',''
1649
1650 if startdate == enddate:
1651 if datetime.time(shour, smin) > datetime.time(ehour, emin):
1652 #debug('starttime should precede endtime')
1653 return '','','','','','','','','',''
1654
1655 # format time
1656 starttime = u'%02d%02d' %(shour, smin)
1657 endtime = u'%02d%02d' %(ehour, emin)
1658
1659 # check recurrent data
1660 event_len = diffday(startdate, enddate)
1661 if recur_freq:
1662
1663 if recur_type == 'day':
1664 if event_len > int(recur_freq):
1665 debug('event length should be smaller than recurrence interval')
1666 return '','','','','','','','','',''
1667
1668 elif recur_type == 'week':
1669 if event_len > int(recur_freq) * 7:
1670 debug('event length should be smaller than recurrence interval')
1671 return '','','','','','','','','',''
1672
1673 elif recur_type == 'weekday':
1674 if event_len > 25:
1675 debug('event length should be smaller than recurrence interval')
1676 return '','','','','','','','','',''
1677
1678 elif recur_type == 'month':
1679 if event_len > int(recur_freq) * 25:
1680 debug('event length should be smaller than recurrence interval')
1681 return '','','','','','','','','',''
1682
1683 elif recur_type == 'year':
1684 if event_len > int(recur_freq) * 365:
1685 debug('event length should be smaller than recurrence interval')
1686 return '','','','','','','','','',''
1687
1688 if recur_until:
1689 try:
1690 ryear, rmonth, rday = getdatefield(recur_until)
1691 except (TypeError, ValueError):
1692 debug('invalid date format: %s' % recur_until)
1693 return '','','','','','','','','',''
1694
1695 recur_until = formatDate(ryear, rmonth, rday)
1696
1697 if int(recur_until) < int(enddate):
1698 debug('recur_until should precede enddate')
1699 return '','','','','','','','','',''
1700
1701 return startdate, starttime, enddate, endtime, bgcolor, description, recur_freq, recur_type, recur_until
1702
1703
1704
1705 def converttext(targettext):
1706 # Converts some special characters of html to plain-text style
1707 # What else to handle?
1708
1709 targettext = targettext.replace(u'&', '&')
1710 targettext = targettext.replace(u'>', '>')
1711 targettext = targettext.replace(u'<', '<')
1712 targettext = targettext.replace(u'\n', '<br>')
1713 targettext = targettext.replace(u'"', '"')
1714 targettext = targettext.replace(u'\t', '  ')
1715 targettext = targettext.replace(u' ', ' ')
1716
1717 return targettext
1718
1719
1720 # monthly view
1721 def showeventcalendar(year, month):
1722
1723 debug('Show Calendar: Monthly View')
1724
1725 request = Globs.request
1726 formatter = Globs.formatter
1727 _ = request.getText
1728
1729 wkend = Globs.wkend
1730 months= Globs.months
1731 wkdays = Globs.wkdays
1732
1733 # get the calendar
1734 monthcal = calendar.monthcalendar(year, month)
1735
1736 # shows current year & month
1737 html_header_curyearmonth = calhead_yearmonth(year, month, 'head_yearmonth')
1738
1739 r7 = range(7)
1740
1741 # shows header of week days
1742 html_header_weekdays = []
1743
1744 for wkday in r7:
1745 wday = _(wkdays[wkday])
1746 html_header_weekdays.append( calhead_weekday(wday, 'head_weekday') )
1747 html_header_weekdays = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_header_weekdays)
1748
1749 # pending events for next row
1750 next_pending = []
1751
1752 # gets previous, next month
1753 day_delta = datetime.timedelta(days=-1)
1754 cur_month = datetime.date(year, month, 1)
1755 prev_month = cur_month + day_delta
1756
1757 day_delta = datetime.timedelta(days=15)
1758 cur_month_end = datetime.date(year, month, 25)
1759 next_month = cur_month_end + day_delta
1760
1761 prev_monthcal = calendar.monthcalendar(prev_month.year, prev_month.month)
1762 next_monthcal = calendar.monthcalendar(next_month.year, next_month.month)
1763
1764 # shows days
1765 html_week_rows = []
1766
1767 # set ranges of events
1768 datefrom = u'%04d%02d21' % (prev_month.year, prev_month.month)
1769 dateto = u'%04d%02d06' % (next_month.year, next_month.month)
1770
1771 # read all the events
1772 events, cal_events = loadEvents(datefrom, dateto)
1773
1774 #debug(u' events: %s' % events)
1775 #debug(u' cal_events: %s' % cal_events)
1776
1777 for week in monthcal:
1778
1779 # day head rows
1780 html_headday_cols = []
1781 html_events_rows = []
1782
1783 for wkday in r7:
1784
1785 day = week[wkday]
1786
1787 if not day:
1788 if week == monthcal[0]:
1789 nb_day = prev_monthcal[-1][wkday]
1790 else:
1791 nb_day = next_monthcal[0][wkday]
1792
1793 html_headday_cols.append( calhead_day_nbmonth(nb_day) )
1794 else:
1795 html_headday_cols.append( calhead_day(year, month, day, wkday) )
1796
1797 html_headday_row = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_headday_cols)
1798 html_week_rows.append(html_headday_row)
1799
1800 # dummy rows
1801 html_headdummy_cols = []
1802
1803 for wkday in r7:
1804 day = week[wkday]
1805 if not day:
1806 html_headdummy_cols.append( calshow_blankbox('head_dummy_nbmonth') )
1807 else:
1808 html_headdummy_cols.append( calshow_blankbox('head_dummy') )
1809
1810 html_headdummy_cols = u'\r\n'.join(html_headdummy_cols)
1811 html_week_rows.append(' <tr>\r\n%s </tr>\r\n' % html_headdummy_cols)
1812
1813 # pending events for next row
1814 pending = next_pending
1815 next_pending = []
1816
1817 # show events
1818 while 1:
1819 event_left = 7
1820 colspan = -1
1821 html_events_cols = []
1822
1823 for wkday in r7:
1824
1825 day = week[wkday]
1826
1827 if not day:
1828 if week == monthcal[0]:
1829 cur_date = formatDate(prev_month.year, prev_month.month, prev_monthcal[-1][wkday])
1830 else:
1831 cur_date = formatDate(next_month.year, next_month.month, next_monthcal[0][wkday])
1832 else:
1833 cur_date = formatDate(year, month, day)
1834
1835 # if an event is already displayed with colspan
1836 if colspan > 0:
1837 colspan -= 1
1838 if cal_events.has_key(cur_date) and lastevent in cal_events[cur_date]:
1839 cal_events[cur_date].remove(lastevent)
1840
1841 continue
1842
1843 # if there is any event for this date
1844 if cal_events.has_key(cur_date):
1845 if len(cal_events[cur_date]) > 0:
1846
1847 # if there is any pending event in the previous week
1848 if wkday == 0 and len(pending) > 0:
1849 todo_event_id = pending.pop(0)
1850 if todo_event_id in cal_events[cur_date]:
1851 cur_event = events[todo_event_id]
1852 temp_len = diffday(cur_date, cur_event['enddate']) + 1
1853
1854 # calculate colspan value
1855 if (7-wkday) < temp_len:
1856 colspan = 7 - wkday
1857 next_pending.append(cur_event['id'])
1858 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append_pending', cur_date) )
1859
1860 else:
1861 colspan = temp_len
1862 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append', cur_date) )
1863
1864
1865 cal_events[cur_date].remove(todo_event_id)
1866
1867 colspan -= 1
1868 lastevent = todo_event_id
1869 else:
1870 debug('Warning: no such event in cal_events')
1871
1872 continue
1873
1874 # if there is no pending event in the previous week, start a new event
1875 event_found = 0
1876 for e_id in cal_events[cur_date]:
1877
1878 # if the start date of the event is current date
1879 if events[e_id]['startdate'] == cur_date:
1880
1881 cur_event = events[cal_events[cur_date].pop(cal_events[cur_date].index(e_id))]
1882
1883 # calculate colspan value
1884 if (7-wkday) < cur_event['date_len']:
1885 colspan = 7 - wkday
1886 next_pending.append(cur_event['id'])
1887 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'pending', cur_date) )
1888
1889 else:
1890 colspan = cur_event['date_len']
1891 html_events_cols.append( calshow_eventbox(cur_event, colspan, '', cur_date) )
1892
1893 colspan -= 1
1894 lastevent = cur_event['id']
1895 event_found = 1
1896 break
1897
1898 # if the start date of the event is NOT current date
1899 else:
1900
1901 # pending event from previous month
1902 if wkday == 0 and week == monthcal[0]:
1903
1904 cur_event = events[cal_events[cur_date].pop(0)]
1905 temp_len = diffday(cur_date, cur_event['enddate']) + 1
1906
1907 # calculate colspan value
1908 if (7-wkday) < temp_len:
1909 colspan = 7 - wkday
1910 next_pending.append(cur_event['id'])
1911 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append_pending', cur_date) )
1912 else:
1913 colspan = temp_len
1914 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append', cur_date) )
1915
1916 colspan -= 1
1917 lastevent = cur_event['id']
1918 event_found = 1
1919 break
1920
1921 # if there is no event to start
1922 if not event_found:
1923 if not day:
1924 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1925 else:
1926 html_events_cols.append( calshow_blankbox('cal_noevent') )
1927 event_left -= 1
1928
1929 else:
1930 if not day:
1931 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1932 else:
1933 html_events_cols.append( calshow_blankbox('cal_noevent') )
1934
1935 event_left -= 1
1936
1937 # if there is NO event for this date
1938 else:
1939 if not day:
1940 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1941 else:
1942 html_events_cols.append( calshow_blankbox('cal_noevent') )
1943
1944 event_left -= 1
1945
1946 # if no event for this entry
1947 if not event_left:
1948 # ignore the previous entry
1949 break
1950 else:
1951 html_events_rows.append(' <tr>\r\n%s </tr>\r\n' % u'\r\n'.join(html_events_cols))
1952
1953 # show dummy blank slots for week height
1954 left_blank_rows = 2 - len(html_events_rows)
1955
1956 # remove the followings
1957 if left_blank_rows > 0 and 0:
1958 for i in range(left_blank_rows):
1959 html_events_cols = []
1960 for wkday in r7:
1961 day = week[wkday]
1962 if not day:
1963 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1964 else:
1965 html_events_cols.append( calshow_blankbox('cal_noevent') )
1966
1967 html_events_rows.append(' <tr>\r\n%s </tr>\r\n' % u'\r\n'.join(html_events_cols))
1968
1969
1970 # close the week slots
1971 html_events_cols = []
1972 for wkday in r7:
1973 day = week[wkday]
1974 if not day:
1975 html_events_cols.append( calshow_blankbox('cal_last_nbmonth') )
1976 else:
1977 html_events_cols.append( calshow_blankbox('cal_last_noevent') )
1978
1979 html_events_rows.append(' <tr>\r\n%s </tr>\r\n' % u'\r\n'.join(html_events_cols))
1980
1981 html_events_rows = u'\r\n'.join(html_events_rows)
1982 html_week_rows.append(html_events_rows)
1983
1984 html_calendar_rows = u'\r\n'.join(html_week_rows)
1985
1986 html_cal_table = [
1987 u'\r\n<div id="eventcalendar">',
1988 u'<table class="eventcalendar" %s>' % Params.monthlywidth,
1989 u'%s' % html_header_curyearmonth,
1990 u'%s' % html_header_weekdays,
1991 u'%s' % html_calendar_rows,
1992 u'</table>',
1993 u'</div>',
1994 ]
1995 html_cal_table = u'\r\n'.join(html_cal_table)
1996
1997 return html_cal_table
1998
1999
2000
2001 # daily view
2002 def showdailyeventcalendar(year, month, day):
2003
2004 debug('Show Calendar: Daily View')
2005
2006 request = Globs.request
2007 formatter = Globs.formatter
2008 _ = request.getText
2009
2010 wkend = Globs.wkend
2011 months= Globs.months
2012 wkdays = Globs.wkdays
2013
2014 cur_date = formatDate(year, month, day)
2015
2016 # gets previous, next month
2017 day_delta = datetime.timedelta(days=-1)
2018 cur_month = datetime.date(year, month, 1)
2019 prev_month = cur_month + day_delta
2020
2021 day_delta = datetime.timedelta(days=15)
2022 cur_month_end = datetime.date(year, month, 25)
2023 next_month = cur_month_end + day_delta
2024
2025 # set ranges of events
2026 datefrom = u'%04d%02d21' % (prev_month.year, prev_month.month)
2027 dateto = u'%04d%02d06' % (next_month.year, next_month.month)
2028
2029 # read all the events
2030 events, cal_events = loadEvents(datefrom, dateto)
2031
2032 #debug(u' events: %s' % events)
2033 #debug(u' cal_events: %s' % cal_events)
2034
2035 # calculates hour_events
2036 hour_events = {}
2037
2038 if cal_events.has_key(cur_date):
2039 for e_id in cal_events[cur_date]:
2040 cur_event = events[e_id]
2041
2042 if cur_event['date_len'] == 1 and cur_event['time_len'] > 0:
2043 start_hour, start_min = gettimefield(cur_event['starttime'])
2044
2045 if not hour_events.has_key(start_hour):
2046 hour_events[start_hour] = []
2047
2048 hour_events[start_hour].append(e_id)
2049
2050 #debug(u'hour_events: %s' % hour_events)
2051
2052 # in-day events
2053 html_calendar_rows = []
2054 html_hour_cols = {}
2055
2056 slot_pending = {}
2057 max_num_slots = 0
2058 hour_max_slots = {}
2059 block_slots = []
2060
2061 start_hour_index = 0
2062
2063 r24 = range(24)
2064
2065 for hour_index in r24:
2066
2067 html_hour_cols[hour_index] = []
2068 hour_max_slots[hour_index] = 1
2069 html_hour_cols[hour_index].append ( calshow_daily_hourhead(hour_index) )
2070
2071 if len(slot_pending) > 0 or hour_events.has_key(hour_index):
2072
2073 #debug('start: hour_index = %d, slot_pending = %s' % (hour_index, slot_pending))
2074 if len(slot_pending) == 0:
2075 if max_num_slots < 1:
2076 max_num_slots = 1
2077
2078 for hour_lines in range(start_hour_index, hour_index):
2079 hour_max_slots[hour_lines] = max_num_slots
2080
2081 #debug('block ended: %d ~ %d, max=%d' % (start_hour_index, hour_index-1, max_num_slots))
2082
2083 block_slots.append(max_num_slots)
2084
2085 max_num_slots = 0
2086 start_hour_index = hour_index
2087
2088 for slot_index in range(max_num_slots):
2089 if slot_pending.has_key(slot_index) and slot_pending[slot_index] > 0:
2090 if slot_pending[slot_index] == 1:
2091 del slot_pending[slot_index]
2092 else:
2093 slot_pending[slot_index] -= 1
2094 html_hour_cols[hour_index].append ( '' )
2095
2096 else:
2097 if hour_events.has_key(hour_index) and len(hour_events[hour_index]) > 0:
2098 e_id = hour_events[hour_index][0]
2099 cur_event = events[hour_events[hour_index].pop(hour_events[hour_index].index(e_id))]
2100 html_hour_cols[hour_index].append ( calshow_daily_eventbox(cur_event) )
2101 slot_pending[slot_index] = cur_event['time_len'] - 1
2102 else:
2103 if not ((len(slot_pending) > 0 and slot_index > max(slot_pending.keys())) or len(slot_pending) == 0):
2104 html_hour_cols[hour_index].append ( calshow_blankeventbox() )
2105
2106 if hour_events.has_key(hour_index):
2107 for tmp_cnt in range(len(hour_events[hour_index])):
2108 e_id = hour_events[hour_index][0]
2109 cur_event = events[hour_events[hour_index].pop(hour_events[hour_index].index(e_id))]
2110 html_hour_cols[hour_index].append ( calshow_daily_eventbox(cur_event) )
2111 slot_pending[max_num_slots] = cur_event['time_len'] - 1
2112 if slot_pending[max_num_slots] == 0:
2113 del slot_pending[max_num_slots]
2114 max_num_slots += 1
2115
2116 else:
2117 html_hour_cols[hour_index].append ( calshow_blankeventbox() )
2118 #hour_max_slots[hour_index] = 1
2119
2120 if max_num_slots < 1:
2121 max_num_slots = 1
2122
2123 for hour_lines in range(start_hour_index, hour_index):
2124 hour_max_slots[hour_lines] = max_num_slots
2125
2126 #debug('block ended: %d ~ %d, max=%d' % (start_hour_index, hour_index-1, max_num_slots))
2127
2128 block_slots.append(max_num_slots)
2129
2130 max_num_slots = 0
2131 start_hour_index = hour_index
2132
2133
2134 #debug('end: hour_index = %d, slot_pending = %s' % (hour_index, slot_pending))
2135
2136 if max_num_slots < 1:
2137 max_num_slots = 1
2138
2139 for hour_lines in range(start_hour_index, 24):
2140 hour_max_slots[hour_lines] = max_num_slots
2141
2142 #debug('block ended: %d ~ %d, max=%d' % (start_hour_index, 23, max_num_slots))
2143
2144 block_slots.append(max_num_slots)
2145
2146 #debug('hour_max_slots: %s' % hour_max_slots)
2147
2148
2149 # calculates global colspan
2150 if len(block_slots):
2151 global_colspan = LCM(block_slots)
2152 else:
2153 global_colspan = 1
2154
2155 for hour_index in r24:
2156
2157 colspan = global_colspan / hour_max_slots[hour_index]
2158 width = 96 / hour_max_slots[hour_index]
2159
2160 left_slots = hour_max_slots[hour_index] - (len(html_hour_cols[hour_index]) - 1)
2161
2162 if left_slots > 0:
2163 #debug('appending left %d slots: %d' % (left_slots, hour_index))
2164 html_hour_cols[hour_index].append ( calshow_blankeventbox2( left_slots * colspan, left_slots * width ) )
2165
2166 html_cols = u'\r\n'.join(html_hour_cols[hour_index]) % {'colspan': colspan, 'width': u'%d%%' % width}
2167 html_cols = u'<tr>%s</tr>\r\n' % html_cols
2168
2169 html_calendar_rows.append (html_cols)
2170
2171 html_calendar_rows = u'\r\n'.join(html_calendar_rows)
2172
2173 # shows current year & month
2174 html_header_curyearmonthday = calhead_yearmonthday(year, month, day, 'head_yearmonth', global_colspan)
2175
2176 # one-day long events
2177 html_oneday_rows = []
2178
2179 #debug('before cal_events[cur_date] = %s' % cal_events[cur_date])
2180
2181 if cal_events.has_key(cur_date):
2182 if len(cal_events[cur_date]) > 0:
2183 for e_id in cal_events[cur_date]:
2184 #debug('before cal_events[cur_date] = %s' % cal_events[cur_date])
2185 #debug('test events[%s] = %s' % (e_id, events[e_id]))
2186 if events[e_id]['time_len'] <= 0 or events[e_id]['date_len'] > 1:
2187 #cur_event = events[cal_events[cur_date].pop(cal_events[cur_date].index(e_id))]
2188 cur_event = events[e_id]
2189
2190 if cur_event['startdate'] == cur_date:
2191 if cur_event['enddate'] == cur_date:
2192 str_status = ''
2193 else:
2194 str_status = 'pending'
2195 else:
2196 if cur_event['enddate'] == cur_date:
2197 str_status = 'append'
2198 else:
2199 str_status = 'append_pending'
2200
2201 tmp_html = u'<tr><td width="4%%" style="border-width: 0px; "> </td>%s</tr>' % calshow_daily_eventbox2(cur_event, global_colspan, str_status, cur_date)
2202 html_oneday_rows.append( tmp_html )
2203
2204 #debug('after cal_events[cur_date] = %s' % cal_events[cur_date])
2205 else:
2206 tmp_html = u'<tr><td width="4%%" style="border-width: 0px; "> </td>%s</tr>' % calshow_blankbox2('cal_daily_noevent', global_colspan)
2207 html_oneday_rows.append( tmp_html )
2208
2209 #debug('after cal_events[cur_date] = %s' % cal_events[cur_date])
2210 #debug('html_oneday_rows = %s' % html_oneday_rows)
2211
2212 html_oneday_rows = u'\r\n'.join(html_oneday_rows)
2213
2214
2215 html_cal_table = [
2216 u'\r\n<div id="eventcalendar">',
2217 u'<table class="eventcalendar" %s>' % Params.dailywidth,
2218 u'<table border="0">',
2219 u'%s' % html_header_curyearmonthday,
2220 u'%s' % html_oneday_rows,
2221 u'%s' % html_calendar_rows,
2222 u'</table>',
2223 u'</td></tr>',
2224 u'</div>',
2225 ]
2226 html_cal_table = u'\r\n'.join(html_cal_table)
2227
2228 return html_cal_table
2229
2230
2231
2232 # weekly view
2233 def showweeklyeventcalendar(year, month, day):
2234
2235 debug('Show Calendar: Weekly View')
2236
2237 request = Globs.request
2238 formatter = Globs.formatter
2239 _ = request.getText
2240
2241 wkend = Globs.wkend
2242 months= Globs.months
2243 wkdays = Globs.wkdays
2244
2245 cur_date = formatDate(year, month, day)
2246
2247 # gets previous, next month
2248 day_delta = datetime.timedelta(days=-1)
2249 cur_month = datetime.date(year, month, 1)
2250 prev_month = cur_month + day_delta
2251
2252 day_delta = datetime.timedelta(days=15)
2253 cur_month_end = datetime.date(year, month, 25)
2254 next_month = cur_month_end + day_delta
2255
2256 # set ranges of events
2257 datefrom = u'%04d%02d21' % (prev_month.year, prev_month.month)
2258 dateto = u'%04d%02d06' % (next_month.year, next_month.month)
2259
2260 # read all the events
2261 events, cal_events = loadEvents(datefrom, dateto)
2262
2263 #debug(u' events: %s' % events)
2264 #debug(u' cal_events: %s' % cal_events)
2265
2266 # calculates hour_events
2267 hour_events = {}
2268
2269 first_date_week = getFirstDateOfWeek(year, month, day)
2270
2271
2272 for dayindex in range(7):
2273 hour_events[dayindex] = {}
2274
2275 cur_date = first_date_week + datetime.timedelta(dayindex)
2276 cur_date = formatDate(cur_date.year, cur_date.month, cur_date.day)
2277
2278 if cal_events.has_key(cur_date):
2279 for e_id in cal_events[cur_date]:
2280 cur_event = events[e_id]
2281
2282 if cur_event['date_len'] == 1 and cur_event['time_len'] > 0:
2283 start_hour, start_min = gettimefield(cur_event['starttime'])
2284
2285 if not hour_events[dayindex].has_key(start_hour):
2286 hour_events[dayindex][start_hour] = []
2287
2288 hour_events[dayindex][start_hour].append(e_id)
2289
2290 #debug(u'hour_events: %s' % hour_events)
2291
2292 # in-day events
2293 html_calendar_rows = []
2294 html_hour_cols = {}
2295
2296 slot_pending = {}
2297 max_num_slots = {}
2298 hour_max_slots = {}
2299 block_slots = {}
2300
2301 start_hour_index = {}
2302
2303 r24 = range(24)
2304
2305 for hour_index in r24:
2306
2307 html_hour_cols[hour_index] = {}
2308 hour_max_slots[hour_index] = {}
2309
2310 #html_hour_cols[hour_index].append ( calshow_daily_hourhead(hour_index) )
2311
2312 for dayindex in range(7):
2313
2314 if not max_num_slots.has_key(dayindex):
2315 max_num_slots[dayindex] = 0
2316
2317 if not slot_pending.has_key(dayindex):
2318 slot_pending[dayindex] = {}
2319
2320 if not start_hour_index.has_key(dayindex):
2321 start_hour_index[dayindex] = 0
2322
2323 if not block_slots.has_key(dayindex):
2324 block_slots[dayindex] = []
2325
2326 html_hour_cols[hour_index][dayindex] = []
2327 hour_max_slots[hour_index][dayindex] = 1
2328
2329 if len(slot_pending[dayindex]) > 0 or hour_events[dayindex].has_key(hour_index):
2330
2331 #debug('start: hour_index = %d, slot_pending = %s' % (hour_index, slot_pending[dayindex]))
2332 if len(slot_pending[dayindex]) == 0:
2333 if max_num_slots[dayindex] < 1:
2334 max_num_slots[dayindex] = 1
2335
2336 for hour_lines in range(start_hour_index[dayindex], hour_index):
2337 hour_max_slots[hour_lines][dayindex] = max_num_slots[dayindex]
2338
2339 #debug('block ended: %d ~ %d, max=%d' % (start_hour_index[dayindex], hour_index-1, max_num_slots[dayindex]))
2340
2341 block_slots[dayindex].append(max_num_slots[dayindex])
2342
2343 max_num_slots[dayindex] = 0
2344 start_hour_index[dayindex] = hour_index
2345
2346 for slot_index in range(max_num_slots[dayindex]):
2347 if slot_pending[dayindex].has_key(slot_index) and slot_pending[dayindex][slot_index] > 0:
2348 if slot_pending[dayindex][slot_index] == 1:
2349 del slot_pending[dayindex][slot_index]
2350 else:
2351 slot_pending[dayindex][slot_index] -= 1
2352 html_hour_cols[hour_index][dayindex].append ( '' )
2353
2354 else:
2355 if hour_events[dayindex].has_key(hour_index) and len(hour_events[dayindex][hour_index]) > 0:
2356 e_id = hour_events[dayindex][hour_index][0]
2357 cur_event = events[hour_events[dayindex][hour_index].pop(hour_events[dayindex][hour_index].index(e_id))]
2358 html_hour_cols[hour_index][dayindex].append ( calshow_weekly_eventbox(cur_event) )
2359 slot_pending[dayindex][slot_index] = cur_event['time_len'] - 1
2360 else:
2361 if not ((len(slot_pending[dayindex]) > 0 and slot_index > max(slot_pending[dayindex].keys())) or len(slot_pending[dayindex]) == 0):
2362 html_hour_cols[hour_index][dayindex].append ( calshow_blankeventbox() )
2363
2364 if hour_events[dayindex].has_key(hour_index):
2365 for tmp_cnt in range(len(hour_events[dayindex][hour_index])):
2366 e_id = hour_events[dayindex][hour_index][0]
2367 cur_event = events[hour_events[dayindex][hour_index].pop(hour_events[dayindex][hour_index].index(e_id))]
2368 html_hour_cols[hour_index][dayindex].append ( calshow_weekly_eventbox(cur_event) )
2369 slot_pending[dayindex][max_num_slots[dayindex]] = cur_event['time_len'] - 1
2370 if slot_pending[dayindex][max_num_slots[dayindex]] == 0:
2371 del slot_pending[dayindex][max_num_slots[dayindex]]
2372 max_num_slots[dayindex] += 1
2373
2374 else:
2375 html_hour_cols[hour_index][dayindex].append ( calshow_blankeventbox() )
2376 #hour_max_slots[hour_index][dayindex] = 1
2377
2378 if max_num_slots[dayindex] < 1:
2379 max_num_slots[dayindex] = 1
2380
2381 for hour_lines in range(start_hour_index[dayindex], hour_index):
2382 hour_max_slots[hour_lines][dayindex] = max_num_slots[dayindex]
2383
2384 #debug('block ended: %d ~ %d, max=%d' % (start_hour_index[dayindex], hour_index-1, max_num_slots[dayindex]))
2385
2386 block_slots[dayindex].append(max_num_slots[dayindex])
2387
2388 max_num_slots[dayindex] = 0
2389 start_hour_index[dayindex] = hour_index
2390
2391 global_colspan = {}
2392 header_colspan = 0
2393
2394 for dayindex in range(7):
2395 if max_num_slots[dayindex] < 1:
2396 max_num_slots[dayindex] = 1
2397
2398 for hour_lines in range(start_hour_index[dayindex], 24):
2399 hour_max_slots[hour_lines][dayindex] = max_num_slots[dayindex]
2400
2401 block_slots[dayindex].append(max_num_slots[dayindex])
2402
2403 # calculates global colspan
2404 if len(block_slots[dayindex]):
2405 global_colspan[dayindex] = LCM(block_slots[dayindex])
2406 else:
2407 global_colspan[dayindex] = 1
2408
2409 header_colspan += global_colspan[dayindex]
2410
2411
2412 for hour_index in r24:
2413
2414 html_cols_days = []
2415
2416 for dayindex in range(7):
2417
2418 colspan = global_colspan[dayindex] / hour_max_slots[hour_index][dayindex]
2419 width = (100 - 2) / 7 / hour_max_slots[hour_index][dayindex]
2420
2421 left_slots = hour_max_slots[hour_index][dayindex] - len(html_hour_cols[hour_index][dayindex])
2422
2423 if left_slots > 0:
2424 #debug('appending left %d slots: %d' % (left_slots, hour_index))
2425 html_hour_cols[hour_index][dayindex].append ( calshow_blankeventbox2( left_slots * colspan, left_slots * width ) )
2426
2427 html_cols = u'\r\n'.join(html_hour_cols[hour_index][dayindex]) % {'colspan': colspan, 'width': u'%d%%' % width}
2428 html_cols_days.append(html_cols)
2429
2430 html_cols_collected = u'\r\n'.join(html_cols_days)
2431 html_cols = u'<tr>%s\r\n%s</tr>\r\n' % (calshow_weekly_hourhead(hour_index), html_cols_collected)
2432
2433 html_calendar_rows.append (html_cols)
2434
2435 html_calendar_rows = u'\r\n'.join(html_calendar_rows)
2436
2437 # shows current year & month
2438 html_header_curyearmonthday = calhead_yearmonthday2(year, month, day, 'head_yearmonth', header_colspan)
2439
2440 # one-day long events
2441 html_oneday_rows = {}
2442
2443 #debug('before cal_events[cur_date] = %s' % cal_events[cur_date])
2444
2445 #first_date_week = getFirstDateOfWeek(year, month, day)
2446
2447 html_oneday_rows = []
2448
2449 while 1:
2450 html_oneday_cols = []
2451 cnt_blank_cols = 0
2452 pending = -1
2453
2454 for dayindex in range(7):
2455
2456 if pending > 0:
2457 pending -= 1
2458 html_oneday_cols.append('')
2459 continue
2460 else:
2461 pending = -1
2462
2463 cur_date = first_date_week + datetime.timedelta(dayindex)
2464 cur_date = formatDate(cur_date.year, cur_date.month, cur_date.day)
2465
2466 if cal_events.has_key(cur_date) and len(cal_events[cur_date]) > 0:
2467
2468 tmpcount = len(cal_events[cur_date])
2469 for tmp_index in range(tmpcount):
2470 cur_event = events[cal_events[cur_date].pop(0)]
2471
2472 #debug('event poped out at %s: %s' % (cur_date, cur_event))
2473
2474 if (cur_event['startdate'] <= cur_date and dayindex == 0) or cur_event['startdate'] == cur_date:
2475 if cur_event['time_len'] <= 0 or cur_event['date_len'] > 1:
2476
2477 temp_len = diffday(cur_date, cur_event['enddate']) + 1
2478
2479 if cur_event['startdate'] == cur_date:
2480 if temp_len <= 7 - dayindex:
2481 str_status = ''
2482 else:
2483 str_status = 'pending'
2484 else:
2485 if temp_len <= 7 - dayindex:
2486 str_status = 'append'
2487 else:
2488 str_status = 'append_pending'
2489
2490 if temp_len > 7 - dayindex:
2491 temp_len = 7 - dayindex
2492
2493 pending = temp_len - 1
2494
2495 tmp_global_colspan = 0
2496 for tmp_index in range(dayindex, dayindex+temp_len):
2497 tmp_global_colspan += global_colspan[tmp_index]
2498
2499 #debug('event appended at %s with pending=%d: %s' % (cur_date, pending, cur_event))
2500
2501 html_oneday_cols.append( calshow_weekly_eventbox2(cur_event, tmp_global_colspan, 14 * temp_len, str_status, cur_date) )
2502 break
2503
2504 if pending < 0:
2505 html_oneday_cols.append( calshow_blankbox2('cal_weekly_noevent', global_colspan[dayindex]) )
2506 cnt_blank_cols += 1
2507
2508 else:
2509 html_oneday_cols.append( calshow_blankbox2('cal_weekly_noevent', global_colspan[dayindex]) )
2510 cnt_blank_cols += 1
2511
2512 if cnt_blank_cols >= 7:
2513 if len(html_oneday_rows) == 0:
2514 html_oneday_cols = u'<tr><td width="2%%" style="border-width: 0px; "> </td>%s</tr>' % u'\r\n'.join(html_oneday_cols)
2515 html_oneday_rows.append (html_oneday_cols)
2516 break
2517 else:
2518 html_oneday_cols = u'<tr><td width="2%%" style="border-width: 0px; "> </td>%s</tr>' % u'\r\n'.join(html_oneday_cols)
2519 html_oneday_rows.append (html_oneday_cols)
2520
2521 html_date_rows = []
2522
2523 for dayindex in range(7):
2524 cur_date = first_date_week + datetime.timedelta(dayindex)
2525 html_date_rows.append(calhead_weeklydate(cur_date.year, cur_date.month, cur_date.day, global_colspan[dayindex]))
2526
2527 html_date_rows = u'<tr><td width="2%%" style="border-width: 0px; "> </td>%s</tr>' % u'\r\n'.join(html_date_rows)
2528
2529 html_oneday_rows = u'\r\n'.join(html_oneday_rows)
2530
2531 html_cal_table = [
2532 u'\r\n<div id="eventcalendar">',
2533 u'<table class="eventcalendar" %s>' % Params.weeklywidth,
2534 u'<table border="0">',
2535 u'%s' % html_header_curyearmonthday,
2536 u'%s' % html_date_rows,
2537 u'%s' % html_oneday_rows,
2538 u'%s' % html_calendar_rows,
2539 u'</table>',
2540 u'</td></tr>',
2541 u'</div>',
2542 ]
2543 html_cal_table = u'\r\n'.join(html_cal_table)
2544
2545 return html_cal_table
2546
2547
2548
2549 # simple view
2550 def showsimpleeventcalendar(year, month):
2551
2552 debug('Show Calendar: Simple View')
2553
2554 request = Globs.request
2555 formatter = Globs.formatter
2556 _ = request.getText
2557 monthstyle_us = Globs.month_style_us
2558
2559 wkend = Globs.wkend
2560 months= Globs.months
2561 wkdays = Globs.wkdays
2562
2563 # get the calendar
2564 monthcal = calendar.monthcalendar(year, month)
2565
2566 # shows current year & month
2567 html_header_curyearmonth = calhead_yearmonth(year, month, 'simple_yearmonth')
2568
2569 r7 = range(7)
2570
2571 # shows header of week days
2572 html_header_weekdays = []
2573
2574 for wkday in r7:
2575 wday = wkdays[wkday]
2576 html_header_weekdays.append( calhead_weekday(wday, 'simple_weekday') )
2577 html_header_weekdays = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_header_weekdays)
2578
2579 # gets previous, next month
2580 day_delta = datetime.timedelta(days=-1)
2581 cur_month = datetime.date(year, month, 1)
2582 prev_month = cur_month + day_delta
2583
2584 day_delta = datetime.timedelta(days=15)
2585 cur_month_end = datetime.date(year, month, 25)
2586 next_month = cur_month_end + day_delta
2587
2588 prev_monthcal = calendar.monthcalendar(prev_month.year, prev_month.month)
2589 next_monthcal = calendar.monthcalendar(next_month.year, next_month.month)
2590
2591 # shows days
2592 html_week_rows = []
2593
2594 # set ranges of events
2595 datefrom = u'%04d%02d21' % (prev_month.year, prev_month.month)
2596 dateto = u'%04d%02d06' % (next_month.year, next_month.month)
2597
2598 # read all the events
2599 events, cal_events = loadEvents(datefrom, dateto)
2600
2601 maketip_js = []
2602
2603 for week in monthcal:
2604
2605 # day head rows
2606 html_headday_cols = []
2607 html_events_rows = []
2608
2609 for wkday in r7:
2610
2611 day = week[wkday]
2612
2613 if not day:
2614 if week == monthcal[0]:
2615 nb_day = prev_monthcal[-1][wkday]
2616 else:
2617 nb_day = next_monthcal[0][wkday]
2618
2619 html_headday_cols.append( simple_eventbox(year, month, day, nb_day, 'simple_nb') )
2620 else:
2621 cur_date = formatDate(year, month, day)
2622
2623 if cal_events.has_key(cur_date):
2624 html_headday_cols.append( simple_eventbox(year, month, day, wkday, 'simple_event') )
2625
2626 if monthstyle_us:
2627 tiptitle = u'%s %d, %d' % (months[month-1], day, year)
2628 else:
2629 tiptitle = u'%d / %02d / %02d' % (year, month, day)
2630
2631 date_today = datetime.date( year, month, day )
2632 tiptitle = u'%s (%s)' % (tiptitle, _(wkdays[date_today.weekday() - calendar.firstweekday()]))
2633
2634 tiptext = []
2635
2636 for e_id in cal_events[cur_date]:
2637 cur_event = events[e_id]
2638 if cur_event['starttime']:
2639 time_string = u'(%s:%s)' % (cur_event['starttime'][:2], cur_event['starttime'][2:])
2640 else:
2641 time_string = ''
2642
2643 title = wikiutil.escape(cur_event['title']).replace("'","\\'")
2644 description = wikiutil.escape(cur_event['description']).replace("'","\\'")
2645
2646 tiptext.append( u'<b>%s</b>%s %s' % (title, time_string, description) )
2647
2648 tiptext = u'<br>'.join(tiptext)
2649
2650 maketip_js.append("maketip('%s','%s','%s');" % (cur_date, tiptitle, tiptext))
2651 else:
2652 html_headday_cols.append( simple_eventbox(year, month, day, wkday, 'simple_noevent') )
2653
2654 html_headday_row = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_headday_cols)
2655 html_week_rows.append(html_headday_row)
2656
2657 html_calendar_rows = u'\r\n'.join(html_week_rows)
2658
2659 html_tooltip_result = """\
2660 <script language="JavaScript" type="text/javascript" src="%s/common/js/infobox.js"></script>
2661 <div id="infodiv" style="position:absolute; visibility:hidden; z-index:20; top:-999em; left:0px;"></div>
2662 <script language="JavaScript" type="text/javascript">
2663 <!--
2664 %s
2665 // -->
2666 </script>
2667
2668 """ % (request.cfg.url_prefix, "\n".join(maketip_js))
2669
2670
2671 html_cal_table = [
2672 u'\r\n<div id="eventcalendar">',
2673 u'%s' % html_tooltip_result,
2674 u'<table class="simplecalendar" %s>' % Params.simplewidth,
2675 u'%s' % html_header_curyearmonth,
2676 u'%s' % html_header_weekdays,
2677 u'%s' % html_calendar_rows,
2678 u'</table>',
2679 u'</div>',
2680 ]
2681 html_cal_table = u'\r\n'.join(html_cal_table)
2682
2683 return html_cal_table
2684
2685
2686 # show calendar head (year & month)
2687 def calhead_yearmonth(year, month, headclass):
2688
2689 request = Globs.request
2690
2691 months = Globs.months
2692 monthstyle_us = Globs.month_style_us
2693 cal_action = Globs.cal_action
2694 page_name = Globs.pagename
2695
2696 page_url = Globs.pageurl
2697
2698 nextyear, nextmonth = yearmonthplusoffset(year, month, 1)
2699 prevyear, prevmonth = yearmonthplusoffset(year, month, -1)
2700
2701 prevlink = u'%s?calaction=%s&caldate=%d%02d%s' % (page_url, cal_action, prevyear, prevmonth, getquerystring(['numcal']) )
2702 nextlink = u'%s?calaction=%s&caldate=%d%02d%s' % (page_url, cal_action, nextyear, nextmonth, getquerystring(['numcal']))
2703 curlink = u'%s?calaction=%s&caldate=%d%02d%s' % (page_url, cal_action, year, month, getquerystring(['numcal']))
2704
2705 if monthstyle_us:
2706 stryearmonth = u'%s %d' % (months[month-1], year)
2707 strnextmonth = u'%s %d' % (months[nextmonth-1], nextyear)
2708 strprevmonth = u'%s %d' % (months[prevmonth-1], prevyear)
2709 else:
2710 stryearmonth = u'%d / %02d' % (year, month)
2711 strnextmonth = u'%d / %02d' % (nextyear, nextmonth)
2712 strprevmonth = u'%d / %02d' % (prevyear, prevmonth)
2713
2714 html = [
2715 u' <tr>',
2716 u' <td class="%s"><a href="%s" title="%s"><</a></td>' % (headclass, prevlink, strprevmonth),
2717 u' <td colspan="5" class="%s"><a href="%s" title="Go/Refresh this month">%s</a></td>' % (headclass, curlink, stryearmonth),
2718 u' <td class="%s"><a href="%s" title="%s">></a></td>' % (headclass, nextlink, strnextmonth),
2719 u' </tr>',
2720 ]
2721
2722 return u'\r\n'.join(html)
2723
2724
2725 # show calendar head (year & month & day)
2726 def calhead_yearmonthday(year, month, day, headclass, colspan):
2727
2728 request = Globs.request
2729 _ = request.getText
2730
2731 months = Globs.months
2732 monthstyle_us = Globs.month_style_us
2733 cal_action = Globs.cal_action
2734 page_name = Globs.pagename
2735 wkdays = Globs.wkdays
2736
2737 page_url = Globs.pageurl
2738
2739 date_today = datetime.date( year, month, day )
2740 prevdate = date_today - datetime.timedelta(days=1)
2741 nextdate = date_today + datetime.timedelta(days=1)
2742
2743 prevlink = u'%s?calaction=%s&caldate=%d%02d%02d%s' % (page_url, cal_action, prevdate.year, prevdate.month, prevdate.day, getquerystring(['numcal']) )
2744 nextlink = u'%s?calaction=%s&caldate=%d%02d%02d%s' % (page_url, cal_action, nextdate.year, nextdate.month, nextdate.day, getquerystring(['numcal']))
2745 curlink = u'%s?calaction=%s&caldate=%d%02d%02d%s' % (page_url, cal_action, year, month, day, getquerystring(['numcal']))
2746
2747 if monthstyle_us:
2748 stryearmonth = u'%s %d, %d' % (months[month-1], day, year)
2749 strnextmonth = u'%s %d, %d' % (months[nextdate.month-1], nextdate.day, nextdate.year)
2750 strprevmonth = u'%s %d, %d' % (months[prevdate.month-1], prevdate.day, prevdate.year)
2751 else:
2752 stryearmonth = u'%d / %02d / %02d' % (year, month, day)
2753 strnextmonth = u'%d / %02d / %02d' % (nextdate.year, nextdate.month, nextdate.day)
2754 strprevmonth = u'%d / %02d / %02d' % (prevdate.year, prevdate.month, prevdate.day)
2755
2756 #stryearmonth = u'%s (%s)' % (stryearmonth, _(wkdays[date_today.weekday()]))
2757 stryearmonth = u'%s (%s)' % (stryearmonth, _(wkdays[date_today.weekday() - calendar.firstweekday()]))
2758
2759 html = [
2760 u'<tr><td width="4%" style="border: none;"> </td>',
2761 u'<td colspan="%d" style="border: none;">' % colspan,
2762 u'<table width="95%">',
2763 u' <tr>',
2764 u' <td class="%s"><a href="%s" title="%s"><</a></td>' % (headclass, prevlink, strprevmonth),
2765 u' <td class="%s"><a href="%s" title="Go/Refresh this day">%s</a></td>' % (headclass, curlink, stryearmonth),
2766 u' <td class="%s"><a href="%s" title="%s">></a></td>' % (headclass, nextlink, strnextmonth),
2767 u' </tr>',
2768 u'</table>',
2769 u'</td></tr>',
2770 ]
2771
2772 return u'\r\n'.join(html)
2773
2774 # show calendar head for weekly view (year & month & day)
2775 def calhead_yearmonthday2(year, month, day, headclass, colspan):
2776
2777 request = Globs.request
2778 _ = request.getText
2779
2780 months = Globs.months
2781 monthstyle_us = Globs.month_style_us
2782 cal_action = Globs.cal_action
2783 page_name = Globs.pagename
2784 wkdays = Globs.wkdays
2785
2786 page_url = Globs.pageurl
2787
2788 date_today = datetime.date( year, month, day )
2789 prevdate = date_today - datetime.timedelta(days=7)
2790 nextdate = date_today + datetime.timedelta(days=7)
2791
2792 first_date_week = getFirstDateOfWeek(year, month, day)
2793 prevdate_f = first_date_week - datetime.timedelta(days=7)
2794 nextdate_f = first_date_week + datetime.timedelta(days=7)
2795
2796 last_date_week = first_date_week + datetime.timedelta(days=6)
2797 prevdate_l = last_date_week - datetime.timedelta(days=7)
2798 nextdate_l = last_date_week + datetime.timedelta(days=7)
2799
2800 prevlink = u'%s?calaction=%s&caldate=%d%02d%02d%s' % (page_url, cal_action, prevdate.year, prevdate.month, prevdate.day, getquerystring(['numcal']) )
2801 nextlink = u'%s?calaction=%s&caldate=%d%02d%02d%s' % (page_url, cal_action, nextdate.year, nextdate.month, nextdate.day, getquerystring(['numcal']))
2802 curlink = u'%s?calaction=%s&caldate=%d%02d%02d%s' % (page_url, cal_action, year, month, day, getquerystring(['numcal']))
2803
2804 if monthstyle_us:
2805 stryearmonth = u'%s %d, %d ~ %s %d, %d' % (months[first_date_week.month-1], first_date_week.day, first_date_week.year, months[last_date_week.month-1], last_date_week.day, last_date_week.year)
2806 strnextmonth = u'%s %d, %d ~ %s %d, %d' % (months[nextdate_f.month-1], nextdate_f.day, nextdate_f.year, months[nextdate_l.month-1], nextdate_l.day, nextdate_l.year)
2807 strprevmonth = u'%s %d, %d ~ %s %d, %d' % (months[prevdate_f.month-1], prevdate_f.day, prevdate_f.year, months[prevdate_l.month-1], prevdate_l.day, prevdate_l.year)
2808 else:
2809 stryearmonth = u'%d / %02d / %02d ~ %d / %02d / %02d' % (first_date_week.year, first_date_week.month, first_date_week.day, last_date_week.year, last_date_week.month, last_date_week.day)
2810 strnextmonth = u'%d / %02d / %02d ~ %d / %02d / %02d' % (nextdate_f.year, nextdate_f.month, nextdate_f.day, nextdate_l.year, nextdate_l.month, nextdate_l.day)
2811 strprevmonth = u'%d / %02d / %02d ~ %d / %02d / %02d' % (prevdate_f.year, prevdate_f.month, prevdate_f.day, prevdate_l.year, prevdate_l.month, prevdate_l.day)
2812
2813 #stryearmonth = u'%s (%s)' % (stryearmonth, _(wkdays[date_today.weekday() - calendar.firstweekday()]))
2814
2815 html = [
2816 u'<tr><td width="2%" style="border: none;"> </td>',
2817 u'<td colspan="%d" style="border: none;">' % colspan,
2818 u'<table width="95%">',
2819 u' <tr>',
2820 u' <td class="%s"><a href="%s" title="%s"><</a></td>' % (headclass, prevlink, strprevmonth),
2821 u' <td class="%s"><a href="%s" title="Go/Refresh this week">%s</a></td>' % (headclass, curlink, stryearmonth),
2822 u' <td class="%s"><a href="%s" title="%s">></a></td>' % (headclass, nextlink, strnextmonth),
2823 u' </tr>',
2824 u'</table>',
2825 u'</td></tr>',
2826 ]
2827
2828 return u'\r\n'.join(html)
2829
2830
2831 # show calendar head for weekly view (the date)
2832 def calhead_weeklydate(year, month, day, colspan):
2833
2834 request = Globs.request
2835 _ = request.getText
2836
2837 months = Globs.months
2838 monthstyle_us = Globs.month_style_us
2839 cal_action = Globs.cal_action
2840 page_name = Globs.pagename
2841 wkdays = Globs.wkdays
2842
2843 page_url = Globs.pageurl
2844
2845 date_today = datetime.date( year, month, day )
2846
2847 if monthstyle_us:
2848 stryearmonth = u'%s %d' % (months[month-1], day)
2849 else:
2850 stryearmonth = u'%02d / %02d' % (month, day)
2851
2852 stryearmonth = u'%s (%s)' % (stryearmonth, _(wkdays[date_today.weekday() - calendar.firstweekday()]))
2853 curlink = u'%s?calaction=daily&caldate=%d%02d%02d' % (page_url, year, month, day)
2854
2855 cyear, cmonth, cday = gettodaydate()
2856 if cyear == year and cmonth == month and cday == day:
2857 bgcolor = 'background-color: #FFFFAA;'
2858 else:
2859 bgcolor = ''
2860
2861 if not Params.changeview:
2862 curlink = '#'
2863
2864 html = [
2865 u'<td colspan="%d" style="border-width: 2px; text-align: center; font-size: 9pt; %s">' % (colspan, bgcolor),
2866 u'<a href="%s">%s</a>' % (curlink, stryearmonth),
2867 u'</td>',
2868 ]
2869
2870 return u'\r\n'.join(html)
2871
2872 # show days in simple
2873 def simple_eventbox(year, month, day, wkday, boxclass):
2874 wkend = Globs.wkend
2875 if wkday == wkend:
2876 html_text = u'<font color="#aa7744">%s</font>' % day
2877 else:
2878 html_text = u'%s' % day
2879
2880 cyear, cmonth, cday = gettodaydate()
2881
2882 page_url = Globs.pageurl
2883 linkkey = u'%d%02d%02d' % (year, month, day)
2884
2885 curlink = u'%s?calaction=daily&caldate=%d%02d%02d' % (page_url, year, month, day)
2886
2887 if not Params.changeview:
2888 curlink = '#'
2889
2890 curlink = u'<a href="%s" onMouseOver="tip(\'%s\')" onMouseOut="untip()" >%s</a>' % (curlink, linkkey, html_text)
2891
2892 if boxclass == 'simple_nb':
2893 html = u' <td class="%s"> </td>\r\n' % boxclass
2894 else:
2895 if cyear == year and cmonth == month and cday == day:
2896 html = u' <td class="%s_today">%s</td>\r\n' % (boxclass, curlink)
2897 else:
2898 html = u' <td class="%s">%s</td>\r\n' % (boxclass, curlink)
2899
2900 return html
2901
2902
2903 # show weekday
2904 def calhead_weekday(wday, headclass):
2905 if headclass == 'simple_weekday':
2906 html = u' <td class="%s">%s</td>\r\n' % (headclass, wday[0])
2907 else:
2908 html = u' <td class="%s">%s</td>\r\n' % (headclass, wday)
2909
2910 return html
2911
2912
2913 # show days of current month
2914 def calhead_day(year, month, day, wkday):
2915
2916 request = Globs.request
2917 page_name = Globs.pagename
2918 wkend = Globs.wkend
2919
2920 if wkday == wkend:
2921 html_text = u'<font color="#FF3300">%s</font>' % day
2922 else:
2923 html_text = u'%s' % day
2924
2925 page_url = Globs.pageurl
2926 html_text = u'<a href="%s?calaction=daily&caldate=%d%02d%02d">%s</a>' % (page_url, year, month, day, html_text)
2927
2928 cyear, cmonth, cday = gettodaydate()
2929
2930 if cyear == year and cmonth == month and cday == day:
2931 html = u' <td class="head_day_today"> %s</td>\r\n' % html_text
2932 else:
2933 html = u' <td class="head_day"> %s</td>\r\n' % html_text
2934
2935 return html
2936
2937
2938 # show days of previous or next month
2939 def calhead_day_nbmonth(day):
2940 html = u' <td class="head_day_nbmonth"> %s</td>\r\n' % day
2941 return html
2942
2943
2944 # show blank calendar box
2945 def calshow_blankbox(classname):
2946 html = u' <td class="%s"> </td>' % classname
2947 return html
2948
2949
2950 def calshow_blankbox2(classname, colspan):
2951 html = u' <td class="%s" colspan="%d"> </td>' % (classname, colspan)
2952 return html
2953
2954
2955 # show eventbox
2956 def calshow_eventbox(event, colspan, status, cur_date):
2957 if status:
2958 status = u'_%s' % status
2959
2960 title = event['title']
2961 eid = event['id']
2962 startdate = event['startdate']
2963 enddate = event['enddate']
2964 starttime = event['starttime']
2965 endtime = event['endtime']
2966 description = event['description']
2967 bgcolor = event['bgcolor']
2968
2969 year, month, day = getdatefield(cur_date)
2970
2971 if bgcolor:
2972 bgcolor = 'background-color: %s;' % bgcolor
2973 else:
2974 bgcolor = 'background-color: %s;' % Params.bgcolor
2975
2976 if (startdate == enddate) and starttime:
2977 shour, smin = gettimefield(starttime)
2978
2979 link = [
2980 u'<table width="100%" style="border-width: 0px; padding: 0px; margin: 0px;"><tr>\r\n',
2981 u'<td nowrap class="cal_eventbox_time">%02d:%02d </td>\r\n' % (shour, smin),
2982 u'<td class="cal_eventbox_time_event">',
2983 u'%s' % showReferPageParsed(event, 'title', 1),
2984 u'</td>\r\n</tr></table>',
2985 ]
2986 link = u''.join(link)
2987 else:
2988 link = u'%s' % showReferPageParsed(event, 'title', 1)
2989
2990
2991 html = [
2992 u' <td class="cal_eventbox" colspan="%d"><table class="cal_event">' % colspan,
2993 u' <tr><td class="cal_event%s" style="%s">%s</td></tr>' % (status, bgcolor, link),
2994 u' </table></td>',
2995 ]
2996
2997 return u'\r\n'.join(html)
2998
2999
3000 # show eventbox
3001 def calshow_daily_eventbox2(event, colspan, status, cur_date):
3002 if status:
3003 status = u'_%s' % status
3004
3005 title = event['title']
3006 eid = event['id']
3007 startdate = event['startdate']
3008 enddate = event['enddate']
3009 starttime = event['starttime']
3010 endtime = event['endtime']
3011 description = event['description']
3012 bgcolor = event['bgcolor']
3013
3014 year, month, day = getdatefield(cur_date)
3015
3016 if bgcolor:
3017 bgcolor = 'background-color: %s;' % bgcolor
3018 else:
3019 bgcolor = 'background-color: %s;' % Params.bgcolor
3020
3021 if (startdate == enddate) and starttime:
3022 shour, smin = gettimefield(starttime)
3023
3024 link = [
3025 u'<table width="100%" style="border-width: 0px; padding: 0px; margin: 0px;"><tr>\r\n',
3026 u'<td width="10" nowrap style="border-width: 0px; padding: 0px; margin: 0px; text-align: left; vertical-align: top; font-size: 7pt; color: #000000;">%02d:%02d </td>\r\n' % (shour, smin),
3027 u'<td style="border-width: 0px; padding: 0px; margin: 0px; text-align: left; vertical-align: top;font-size: 8pt;">',
3028 u'%s' % showReferPageParsed(event, 'title', 1),
3029 u'</td>\r\n</tr></table>',
3030 ]
3031 link = u''.join(link)
3032 else:
3033 link = u'%s' % showReferPageParsed(event, 'title', 1)
3034
3035
3036 html = [
3037 u' <td colspan="%d" style="width: 96%%; border-width: 0px; line-height: 11px;"><table class="cal_event">' % colspan,
3038 u' <tr><td class="cal_event%s" style="%s">%s</td></tr>' % (status, bgcolor, link),
3039 u' </table></td>',
3040 ]
3041
3042 return u'\r\n'.join(html)
3043
3044
3045 # show eventbox
3046 def calshow_daily_eventbox(event):
3047
3048 title = event['title']
3049 eid = event['id']
3050 startdate = event['startdate']
3051 enddate = event['enddate']
3052 starttime = event['starttime']
3053 endtime = event['endtime']
3054 description = event['description']
3055 bgcolor = event['bgcolor']
3056 time_len = event['time_len']
3057
3058 if bgcolor:
3059 bgcolor = 'background-color: %s;' % bgcolor
3060 else:
3061 bgcolor = 'background-color: %s;' % Params.bgcolor
3062
3063 shour, smin = gettimefield(starttime)
3064 ehour, emin = gettimefield(endtime)
3065
3066 html = [
3067 u' <td colspan="%(colspan)d"',
3068 u' style="%s border-width: 2px; border-color: #000000; vertical-align: top; font-size: 9pt; ' % bgcolor,
3069 u' width: %(width)s;" ',
3070 u' rowspan="%(rowspan)d">' % { 'rowspan': time_len },
3071 u' %02d:%02d ~ %02d:%02d<br>%s' % (shour, smin, ehour, emin, showReferPageParsed(event, 'title', 1)),
3072 u' </td>',
3073 ]
3074
3075 return u'\r\n'.join(html)
3076
3077
3078 # show eventbox
3079 def calshow_weekly_eventbox(event):
3080
3081 title = event['title']
3082 eid = event['id']
3083 startdate = event['startdate']
3084 enddate = event['enddate']
3085 starttime = event['starttime']
3086 endtime = event['endtime']
3087 description = event['description']
3088 bgcolor = event['bgcolor']
3089 time_len = event['time_len']
3090
3091 if bgcolor:
3092 bgcolor = 'background-color: %s;' % bgcolor
3093 else:
3094 bgcolor = 'background-color: %s;' % Params.bgcolor
3095
3096 shour, smin = gettimefield(starttime)
3097 ehour, emin = gettimefield(endtime)
3098
3099 html = [
3100 u' <td colspan="%(colspan)d"',
3101 u' style="%s;' % bgcolor,
3102 u' width: %(width)s;" ',
3103 u' rowspan="%(rowspan)d"' % { 'rowspan': time_len },
3104 u' class="cal_weekly_eventbox">',
3105 u' %s' % showReferPageParsed(event, 'title', 1),
3106 u' </td>',
3107 ]
3108
3109 return u'\r\n'.join(html)
3110
3111 # show blank eventbox
3112 def calshow_blankeventbox():
3113
3114 html = [
3115 u' <td colspan="%(colspan)d" style="width: %(width)s;" class="cal_blankeventbox"> </td>',
3116 ]
3117
3118 return u'\r\n'.join(html)
3119
3120
3121 # show eventbox
3122 def calshow_weekly_eventbox2(event, colspan, width, status, cur_date):
3123 if status:
3124 status = u'_%s' % status
3125
3126 title = event['title']
3127 eid = event['id']
3128 startdate = event['startdate']
3129 enddate = event['enddate']
3130 starttime = event['starttime']
3131 endtime = event['endtime']
3132 description = event['description']
3133 bgcolor = event['bgcolor']
3134
3135 year, month, day = getdatefield(cur_date)
3136
3137 if bgcolor:
3138 bgcolor = 'background-color: %s;' % bgcolor
3139 else:
3140 bgcolor = 'background-color: %s;' % Params.bgcolor
3141
3142 link = u'%s' % showReferPageParsed(event, 'title', 1)
3143
3144 html = [
3145 u' <td colspan="%d" style="width: %d%%;" class="cal_weekly_eventbox2"><table class="cal_event">' % (colspan, width),
3146 u' <tr><td class="cal_event%s" style="%s">%s</td></tr>' % (status, bgcolor, link),
3147 u' </table></td>',
3148 ]
3149
3150 return u'\r\n'.join(html)
3151
3152
3153
3154 # show blank eventbox
3155 def calshow_blankeventbox2(colspan, width):
3156 html = [
3157 u' <td colspan="%(colspan)d"' % { 'colspan': colspan },
3158 u' style="width: %(width)s;" class="cal_blankeventbox"> </td>' % { 'width': '%d%%%%' % width },
3159 ]
3160
3161 return u'\r\n'.join(html)
3162
3163
3164
3165 def calshow_daily_hourhead(hour):
3166
3167 if hour >= Globs.dailystart and hour <= Globs.dailyend:
3168 bgcolor = "#ffffcc"
3169 else:
3170 bgcolor = "#ffeeee"
3171
3172 html = [
3173 u' <td class="cal_hourhead" style="background-color: %s; width: 4%%%%;">%02d</td>' % (bgcolor, hour),
3174 ]
3175
3176 return u'\r\n'.join(html)
3177
3178 def calshow_weekly_hourhead(hour):
3179
3180 if hour >= Globs.dailystart and hour <= Globs.dailyend:
3181 bgcolor = "#ffffcc"
3182 else:
3183 bgcolor = "#ffeeee"
3184
3185 html = [
3186 u' <td class="cal_hourhead" style="width: 2%%%%; background-color: %s; ">%02d</td>' % (bgcolor, hour),
3187 ]
3188
3189 return u'\r\n'.join(html)
3190
3191
3192
3193 def insertcalevents(cal_events, datefrom, dateto, e_id, e_start_date, e_end_date):
3194
3195 if not (int(e_start_date) > dateto or int(e_end_date) < datefrom):
3196
3197 e_start_date = str(max(int(e_start_date), datefrom))
3198 e_end_date = str(min(int(e_end_date), dateto))
3199
3200 day_delta = datetime.timedelta(days=1)
3201 e_start_year, e_start_month, e_start_day = getdatefield(e_start_date)
3202 cur_datetime = datetime.date(e_start_year, e_start_month, e_start_day)
3203
3204 while 1:
3205 tmp_record_date = formatdateobject(cur_datetime)
3206
3207 if not cal_events.has_key(tmp_record_date):
3208 cal_events[tmp_record_date] = []
3209 cal_events[tmp_record_date].append(e_id)
3210
3211 if tmp_record_date == e_end_date:
3212 break
3213
3214 cur_datetime = cur_datetime + day_delta
3215
3216 # date format should be like '20051004' for 2005, Oct., 04
3217 def diffday(date1, date2):
3218
3219 try:
3220 year1, month1, day1 = getdatefield(date1)
3221 year2, month2, day2 = getdatefield(date2)
3222 tmp_diff = datetime.date(year2, month2, day2) - datetime.date(year1, month1, day1)
3223 except (TypeError, ValueError):
3224 debug('An event data is corrupted: invalid date format')
3225 return 0
3226
3227 return tmp_diff.days
3228
3229
3230 # time format should be like '1700' for 05:00pm
3231 def difftime(time1, time2):
3232
3233 try:
3234 hour1, min1 = gettimefield(time1)
3235 hour2, min2 = gettimefield(time2)
3236
3237 except (TypeError, ValueError):
3238 debug('An event data is corrupted: invalid time format')
3239 return 0
3240
3241 if min2 == 0 and hour2 != 0 and hour1 != hour2:
3242 hour2 -= 1
3243
3244 tmp_diff = hour2 - hour1
3245
3246 return tmp_diff
3247
3248
3249 def difftime_sec(time1, time2):
3250
3251 try:
3252 hour1, min1 = gettimefield(time1)
3253 hour2, min2 = gettimefield(time2)
3254 tmp_diff = datetime.time(hour2, min2) - datetime.time(hour1, min1)
3255 except (TypeError, ValueError):
3256 debug('An event data is corrupted: invalid time format')
3257 return 0
3258
3259 return tmp_diff.seconds
3260
3261 def formatDate(year, month, day):
3262 # returns like: '20051004'
3263 return u'%4d%02d%02d' % (year, month, day)
3264
3265 def formatTime(hour, min):
3266 # returns like: '1700'
3267 return u'%2d%02d' % (hour, min)
3268
3269
3270 def formatdateobject(obj_date):
3271
3272 return formatDate(obj_date.year, obj_date.month, obj_date.day)
3273
3274 def formattimeobject(obj_time):
3275
3276 return formatTime(obj_time.hour, obj_time.minute)
3277
3278
3279 def debug(astring):
3280 Globs.debugmsg += u'<li>%s\n' % astring
3281
3282
3283 def yearmonthplusoffset(year, month, offset):
3284 month = month+offset
3285 # handle offset and under/overflows - quick and dirty, yes!
3286 while month < 1:
3287 month = month + 12
3288 year = year - 1
3289 while month > 12:
3290 month = month - 12
3291 year = year + 1
3292 return year, month
3293
3294
3295 def formatcfgdatetime(strdate, strtime=''):
3296
3297 if not strdate:
3298 return ''
3299
3300 request = Globs.request
3301
3302 if request.user.date_fmt:
3303 date_fmt = request.user.date_fmt
3304 else:
3305 date_fmt = request.cfg.date_fmt
3306
3307 if request.user.datetime_fmt:
3308 datetime_fmt = request.user.datetime_fmt
3309 else:
3310 datetime_fmt = request.cfg.datetime_fmt
3311
3312 ## XXX HACK
3313 datetime_fmt = datetime_fmt.replace(':%S', '')
3314
3315 date_fmt = str(date_fmt)
3316 datetime_fmt = str(datetime_fmt)
3317
3318 year, month, day = getdatefield(str(strdate))
3319 if strtime:
3320 hour, min = gettimefield(str(strtime))
3321 objdatetime = datetime.datetime(year, month, day, hour, min)
3322 return objdatetime.strftime(datetime_fmt)
3323 else:
3324 objdate = getdatetimefromstring(strdate)
3325 return objdate.strftime(date_fmt)
3326
3327
3328 def getdatetimefromstring(strdate):
3329 year, month, day = getdatefield(str(strdate))
3330 return datetime.date( year, month, day )
3331
3332
3333 def searchPages(request, needle):
3334 # Search the pages and return the results
3335 query = search.QueryParser().parse_query(needle)
3336 results = search.searchPages(request, query)
3337 #results.sortByPagename()
3338
3339 return results.hits
3340
3341 html = []
3342 for page in results.hits:
3343 html.append(page.page_name)
3344
3345 html = u',<br>'.join(html)
3346 return u'%s<p>%s' % (Params.category, html)
3347
3348
3349 def getFirstDateOfWeek(year, month, day):
3350 orgday = datetime.date(year, month, day)
3351 yearBase, week, weekday = orgday.isocalendar()
3352 baseDate = datetime.date(yearBase, 2, 1)
3353 yearBase, weekBase, dayBase = baseDate.isocalendar()
3354 days = datetime.timedelta(1-dayBase+(week-weekBase)*7)
3355 theday = baseDate + days
3356
3357 theday -= datetime.timedelta(7 - calendar.firstweekday())
3358
3359 if orgday - theday >= datetime.timedelta(7):
3360 theday += datetime.timedelta(7)
3361
3362 return theday
3363
3364 def gcd(a,b):
3365 """Return greatest common divisor using Euclid's Algorithm."""
3366 while b:
3367 a, b = b, a % b
3368
3369 return a
3370
3371 def lcm(a,b):
3372 """
3373 Return lowest common multiple."""
3374 return (a*b)/gcd(a,b)
3375
3376 def LCM(terms):
3377 "Return lcm of a list of numbers."
3378 return reduce(lambda a,b: lcm(a,b), terms)
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.