8 from datetime import date, time, timedelta |
8 from datetime import date, time, timedelta |
9 |
9 |
10 from logilab.mtconverter import html_escape |
10 from logilab.mtconverter import html_escape |
11 |
11 |
12 from cubicweb.interfaces import ICalendarViews |
12 from cubicweb.interfaces import ICalendarViews |
13 from cubicweb.utils import ONEDAY, ONEWEEK, date_range, previous_month, next_month |
13 from cubicweb.utils import ONEDAY, ONEWEEK, date_range, first_day, last_day, previous_month, next_month, days_in_month |
14 from cubicweb.selectors import implements |
14 from cubicweb.selectors import implements |
15 from cubicweb.view import EntityView |
15 from cubicweb.view import EntityView |
16 |
16 |
17 # Define some useful constants |
|
18 ONE_MONTH = timedelta(days=31) # XXX |
|
19 # used by i18n tools |
17 # used by i18n tools |
20 WEEKDAYS = [_("monday"), _("tuesday"), _("wednesday"), _("thursday"), |
18 WEEKDAYS = [_("monday"), _("tuesday"), _("wednesday"), _("thursday"), |
21 _("friday"), _("saturday"), _("sunday")] |
19 _("friday"), _("saturday"), _("sunday")] |
22 MONTHNAMES = [ _('january'), _('february'), _('march'), _('april'), _('may'), |
20 MONTHNAMES = [ _('january'), _('february'), _('march'), _('april'), _('may'), |
23 _('june'), _('july'), _('august'), _('september'), _('october'), |
21 _('june'), _('july'), _('august'), _('september'), _('october'), |
62 def build_calendars(self, schedule, begin, end): |
60 def build_calendars(self, schedule, begin, end): |
63 """build several HTML calendars at once, one for each month |
61 """build several HTML calendars at once, one for each month |
64 between begin and end |
62 between begin and end |
65 """ |
63 """ |
66 return [self.build_calendar(schedule, date) |
64 return [self.build_calendar(schedule, date) |
67 for date in date_range(begin, end, incr=ONE_MONTH)] |
65 for date in date_range(begin, end, incmonth=1)] |
68 |
66 |
69 def build_calendar(self, schedule, first_day): |
67 def build_calendar(self, schedule, first_day): |
70 """method responsible for building *one* HTML calendar""" |
68 """method responsible for building *one* HTML calendar""" |
71 # FIXME iterates between [first_day-first_day.day_of_week ; |
69 # FIXME iterates between [first_day-first_day.day_of_week ; |
72 # last_day+6-last_day.day_of_week] |
70 # last_day+6-last_day.day_of_week] |
73 umonth = self.format_date(first_day, '%B %Y') # localized month name |
71 umonth = self.format_date(first_day, '%B %Y') # localized month name |
74 rows = [] |
72 rows = [] |
75 current_row = [NO_CELL] * first_day.day_of_week |
73 current_row = [NO_CELL] * first_day.weekday() |
76 for daynum in xrange(0, first_day.days_in_month): |
74 for daynum in xrange(0, days_in_month(first_day)): |
77 # build cell day |
75 # build cell day |
78 day = first_day + daynum |
76 day = first_day + timedelta(daynum) |
79 events = schedule.get(day) |
77 events = schedule.get(day) |
80 if events: |
78 if events: |
81 events = [u'\n'.join(event) for event in events.values()] |
79 events = [u'\n'.join(event) for event in events.values()] |
82 current_row.append(CELL % (daynum+1, '\n'.join(events))) |
80 current_row.append(CELL % (daynum+1, '\n'.join(events))) |
83 else: |
81 else: |
84 current_row.append(EMPTY_CELL % (daynum+1)) |
82 current_row.append(EMPTY_CELL % (daynum+1)) |
85 # store & reset current row on Sundays |
83 # store & reset current row on Sundays |
86 if day.day_of_week == Sunday: |
84 if day.weekday() == 6: |
87 rows.append(u'<tr>%s%s</tr>' % (WEEKNUM_CELL % day.isocalendar()[1], ''.join(current_row))) |
85 rows.append(u'<tr>%s%s</tr>' % (WEEKNUM_CELL % day.isocalendar()[1], ''.join(current_row))) |
88 current_row = [] |
86 current_row = [] |
89 current_row.extend([NO_CELL] * (Sunday-day.day_of_week)) |
87 current_row.extend([NO_CELL] * (6-day.weekday())) |
90 rql = self.rset.printable_rql() |
88 rql = self.rset.printable_rql() |
91 if day.day_of_week != Sunday: |
89 if day.weekday() != 6: |
92 rows.append(u'<tr>%s%s</tr>' % (WEEKNUM_CELL % day.isocalendar()[1], ''.join(current_row))) |
90 rows.append(u'<tr>%s%s</tr>' % (WEEKNUM_CELL % day.isocalendar()[1], ''.join(current_row))) |
93 url = self.build_url(rql=rql, vid='calendarmonth', |
91 url = self.build_url(rql=rql, vid='calendarmonth', |
94 year=first_day.year, month=first_day.month) |
92 year=first_day.year, month=first_day.month) |
95 monthlink = u'<a href="%s">%s</a>' % (html_escape(url), umonth) |
93 monthlink = u'<a href="%s">%s</a>' % (html_escape(url), umonth) |
96 return CALENDAR(self.req) % (monthlink, '\n'.join(rows)) |
94 return CALENDAR(self.req) % (monthlink, '\n'.join(rows)) |
198 self.w(self.nav_header(date(year, month, 1), 1, 6)) |
196 self.w(self.nav_header(date(year, month, 1), 1, 6)) |
199 |
197 |
200 def build_calendars(self, schedule, begin, end): |
198 def build_calendars(self, schedule, begin, end): |
201 self.w(u'<tr>') |
199 self.w(u'<tr>') |
202 rql = self.rset.printable_rql() |
200 rql = self.rset.printable_rql() |
203 for cur_month in date_range(begin, end, incr=ONE_MONTH): |
201 for cur_month in date_range(begin, end, incmonth=1): |
204 umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year) |
202 umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year) |
205 url = self.build_url(rql=rql, vid=self.id, |
203 url = self.build_url(rql=rql, vid=self.id, |
206 year=cur_month.year, month=cur_month.month) |
204 year=cur_month.year, month=cur_month.month) |
207 self.w(u'<th colspan="2"><a href="%s">%s</a></th>' % (html_escape(url), |
205 self.w(u'<th colspan="2"><a href="%s">%s</a></th>' % (html_escape(url), |
208 umonth)) |
206 umonth)) |
209 self.w(u'</tr>') |
207 self.w(u'</tr>') |
210 _ = self.req._ |
208 _ = self.req._ |
211 for day_num in xrange(31): |
209 for day_num in xrange(31): |
212 self.w(u'<tr>') |
210 self.w(u'<tr>') |
213 for cur_month in date_range(begin, end, incr=ONE_MONTH): |
211 for cur_month in date_range(begin, end, incmonth=1): |
214 if day_num >= cur_month.days_in_month: |
212 if day_num >= days_in_month(cur_month): |
215 self.w(u'%s%s' % (NO_CELL, NO_CELL)) |
213 self.w(u'%s%s' % (NO_CELL, NO_CELL)) |
216 else: |
214 else: |
217 day = date(cur_month.year, cur_month.month, day_num+1) |
215 day = date(cur_month.year, cur_month.month, day_num+1) |
218 events = schedule.get(day) |
216 events = schedule.get(day) |
219 self.w(u'<td>%s %s</td>\n' % (_(WEEKDAYS[day.day_of_week])[0].upper(), day_num+1)) |
217 self.w(u'<td>%s %s</td>\n' % (_(WEEKDAYS[day.weekday()])[0].upper(), day_num+1)) |
220 self.format_day_events(day, events) |
218 self.format_day_events(day, events) |
221 self.w(u'</tr>') |
219 self.w(u'</tr>') |
222 |
220 |
223 def format_day_events(self, day, events): |
221 def format_day_events(self, day, events): |
224 if events: |
222 if events: |
250 id = 'calendarweek' |
248 id = 'calendarweek' |
251 title = _('calendar (week)') |
249 title = _('calendar (week)') |
252 |
250 |
253 def call(self, year=None, week=None): |
251 def call(self, year=None, week=None): |
254 year = year or int(self.req.form.get('year', date.today().year)) |
252 year = year or int(self.req.form.get('year', date.today().year)) |
255 week = week or int(self.req.form.get('week', week, |
253 week = week or int(self.req.form.get('week', date.today().isocalendar()[1])) |
256 date.today().isocalendar()[1])) |
|
257 day0 = date(year, 1, 1) |
254 day0 = date(year, 1, 1) |
258 first_day_of_week = day0 - day0.day_of_week*ONEDAY + ONEWEEK |
255 first_day_of_week = day0 - day0.weekday()*ONEDAY + ONEWEEK |
259 begin, end = first_day_of_week- ONEWEEK, first_day_of_week + 2*ONEWEEK |
256 begin, end = first_day_of_week- ONEWEEK, first_day_of_week + 2*ONEWEEK |
260 schedule = self._mk_schedule(begin, end, itemvid='calendarlargeitem') |
257 schedule = self._mk_schedule(begin, end, itemvid='calendarlargeitem') |
261 self.w(self.nav_header(first_day_of_week)) |
258 self.w(self.nav_header(first_day_of_week)) |
262 self.w(u'<table class="weekCalendar">') |
259 self.w(u'<table class="weekCalendar">') |
263 _weeks = [(first_day_of_week-ONEWEEK, first_day_of_week-ONEDAY), |
260 _weeks = [(first_day_of_week-ONEWEEK, first_day_of_week-ONEDAY), |
277 monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth) |
274 monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth) |
278 self.w(u'<tr><th colspan="3">%s %s (%s)</th></tr>' \ |
275 self.w(u'<tr><th colspan="3">%s %s (%s)</th></tr>' \ |
279 % (_('week'), monday.isocalendar()[1], monthlink)) |
276 % (_('week'), monday.isocalendar()[1], monthlink)) |
280 for day in date_range(monday, sunday): |
277 for day in date_range(monday, sunday): |
281 self.w(u'<tr>') |
278 self.w(u'<tr>') |
282 self.w(u'<td>%s</td>' % _(WEEKDAYS[day.day_of_week])) |
279 self.w(u'<td>%s</td>' % _(WEEKDAYS[day.weekday()])) |
283 self.w(u'<td>%s</td>' % (day.strftime('%Y-%m-%d'))) |
280 self.w(u'<td>%s</td>' % (day.strftime('%Y-%m-%d'))) |
284 events = schedule.get(day) |
281 events = schedule.get(day) |
285 if events: |
282 if events: |
286 events = ['\n'.join(event) for event in events.values()] |
283 events = ['\n'.join(event) for event in events.values()] |
287 self.w(WEEK_CELL % '\n'.join(events)) |
284 self.w(WEEK_CELL % '\n'.join(events)) |
310 |
307 |
311 def build_calendar(self, schedule, first_day): |
308 def build_calendar(self, schedule, first_day): |
312 """method responsible for building *one* HTML calendar""" |
309 """method responsible for building *one* HTML calendar""" |
313 umonth = self.format_date(first_day, '%B %Y') # localized month name |
310 umonth = self.format_date(first_day, '%B %Y') # localized month name |
314 rows = [] # each row is: (am,pm), (am,pm) ... week_title |
311 rows = [] # each row is: (am,pm), (am,pm) ... week_title |
315 current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.day_of_week |
312 current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.weekday() |
316 rql = self.rset.printable_rql() |
313 rql = self.rset.printable_rql() |
317 for daynum in xrange(0, first_day.days_in_month): |
314 for daynum in xrange(0, days_in_month(first_day)): |
318 # build cells day |
315 # build cells day |
319 day = first_day + daynum |
316 day = first_day + timedelta(daynum) |
320 events = schedule.get(day) |
317 events = schedule.get(day) |
321 if events: |
318 if events: |
322 current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events)) |
319 current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events)) |
323 else: |
320 else: |
324 current_row.append((AMPM_DAY % (daynum+1), |
321 current_row.append((AMPM_DAY % (daynum+1), |
325 AMPM_EMPTY % ("amCell", "am"), |
322 AMPM_EMPTY % ("amCell", "am"), |
326 AMPM_EMPTY % ("pmCell", "pm"))) |
323 AMPM_EMPTY % ("pmCell", "pm"))) |
327 # store & reset current row on Sundays |
324 # store & reset current row on Sundays |
328 if day.day_of_week == Sunday: |
325 if day.weekday() == 6: |
329 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
326 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
330 year=day.year, week=day.isocalendar()[1]) |
327 year=day.year, week=day.isocalendar()[1]) |
331 weeklink = '<a href="%s">%s</a>' % (html_escape(url), |
328 weeklink = '<a href="%s">%s</a>' % (html_escape(url), |
332 day.isocalendar()[1]) |
329 day.isocalendar()[1]) |
333 current_row.append(WEEKNUM_CELL % weeklink) |
330 current_row.append(WEEKNUM_CELL % weeklink) |
334 rows.append(current_row) |
331 rows.append(current_row) |
335 current_row = [] |
332 current_row = [] |
336 current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (Sunday-day.day_of_week)) |
333 current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (6-day.weekday())) |
337 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
334 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
338 year=day.year, week=day.isocalendar()[1]) |
335 year=day.year, week=day.isocalendar()[1]) |
339 weeklink = '<a href="%s">%s</a>' % (html_escape(url), day.isocalendar()[1]) |
336 weeklink = '<a href="%s">%s</a>' % (html_escape(url), day.isocalendar()[1]) |
340 current_row.append(WEEKNUM_CELL % weeklink) |
337 current_row.append(WEEKNUM_CELL % weeklink) |
341 rows.append(current_row) |
338 rows.append(current_row) |
363 title = _('am/pm calendar (semester)') |
360 title = _('am/pm calendar (semester)') |
364 |
361 |
365 def build_calendars(self, schedule, begin, end): |
362 def build_calendars(self, schedule, begin, end): |
366 self.w(u'<tr>') |
363 self.w(u'<tr>') |
367 rql = self.rset.printable_rql() |
364 rql = self.rset.printable_rql() |
368 for cur_month in date_range(begin, end, incr=ONE_MONTH): |
365 for cur_month in date_range(begin, end, incmonth=1): |
369 umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year) |
366 umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year) |
370 url = self.build_url(rql=rql, vid=self.id, |
367 url = self.build_url(rql=rql, vid=self.id, |
371 year=cur_month.year, month=cur_month.month) |
368 year=cur_month.year, month=cur_month.month) |
372 self.w(u'<th colspan="3"><a href="%s">%s</a></th>' % (html_escape(url), |
369 self.w(u'<th colspan="3"><a href="%s">%s</a></th>' % (html_escape(url), |
373 umonth)) |
370 umonth)) |
374 self.w(u'</tr>') |
371 self.w(u'</tr>') |
375 _ = self.req._ |
372 _ = self.req._ |
376 for day_num in xrange(31): |
373 for day_num in xrange(31): |
377 self.w(u'<tr>') |
374 self.w(u'<tr>') |
378 for cur_month in date_range(begin, end, incr=ONE_MONTH): |
375 for cur_month in date_range(begin, end, incmonth=1): |
379 if day_num >= cur_month.days_in_month: |
376 if day_num >= days_in_month(cur_month): |
380 self.w(u'%s%s%s' % (NO_CELL, NO_CELL, NO_CELL)) |
377 self.w(u'%s%s%s' % (NO_CELL, NO_CELL, NO_CELL)) |
381 else: |
378 else: |
382 day = date(cur_month.year, cur_month.month, day_num+1) |
379 day = date(cur_month.year, cur_month.month, day_num+1) |
383 events = schedule.get(day) |
380 events = schedule.get(day) |
384 self.w(u'<td>%s %s</td>\n' % (_(WEEKDAYS[day.day_of_week])[0].upper(), |
381 self.w(u'<td>%s %s</td>\n' % (_(WEEKDAYS[day.weekday()])[0].upper(), |
385 day_num+1)) |
382 day_num+1)) |
386 self.format_day_events(day, events) |
383 self.format_day_events(day, events) |
387 self.w(u'</tr>') |
384 self.w(u'</tr>') |
388 |
385 |
389 def format_day_events(self, day, events): |
386 def format_day_events(self, day, events): |
401 |
398 |
402 def build_calendar(self, schedule, first_day): |
399 def build_calendar(self, schedule, first_day): |
403 """method responsible for building *one* HTML calendar""" |
400 """method responsible for building *one* HTML calendar""" |
404 umonth = self.format_date(first_day, '%B %Y') # localized month name |
401 umonth = self.format_date(first_day, '%B %Y') # localized month name |
405 rows = [] # each row is: (am,pm), (am,pm) ... week_title |
402 rows = [] # each row is: (am,pm), (am,pm) ... week_title |
406 current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.day_of_week |
403 current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.weekday() |
407 rql = self.rset.printable_rql() |
404 rql = self.rset.printable_rql() |
408 for daynum in xrange(0, first_day.days_in_month): |
405 for daynum in xrange(0, days_in_month(first_day)): |
409 # build cells day |
406 # build cells day |
410 day = first_day + daynum |
407 day = first_day + timedelta(daynum) |
411 events = schedule.get(day) |
408 events = schedule.get(day) |
412 if events: |
409 if events: |
413 current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events)) |
410 current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events)) |
414 else: |
411 else: |
415 current_row.append((AMPM_DAY % (daynum+1), |
412 current_row.append((AMPM_DAY % (daynum+1), |
416 AMPM_EMPTY % ("amCell", "am"), |
413 AMPM_EMPTY % ("amCell", "am"), |
417 AMPM_EMPTY % ("pmCell", "pm"))) |
414 AMPM_EMPTY % ("pmCell", "pm"))) |
418 # store & reset current row on Sundays |
415 # store & reset current row on Sundays |
419 if day.day_of_week == Sunday: |
416 if day.weekday() == 6: |
420 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
417 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
421 year=day.year, week=day.isocalendar()[1]) |
418 year=day.year, week=day.isocalendar()[1]) |
422 weeklink = '<a href="%s">%s</a>' % (html_escape(url), |
419 weeklink = '<a href="%s">%s</a>' % (html_escape(url), |
423 day.isocalendar()[1]) |
420 day.isocalendar()[1]) |
424 current_row.append(WEEKNUM_CELL % weeklink) |
421 current_row.append(WEEKNUM_CELL % weeklink) |
425 rows.append(current_row) |
422 rows.append(current_row) |
426 current_row = [] |
423 current_row = [] |
427 current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (Sunday-day.day_of_week)) |
424 current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (6-day.weekday())) |
428 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
425 url = self.build_url(rql=rql, vid='ampmcalendarweek', |
429 year=day.year, week=day.isocalendar()[1]) |
426 year=day.year, week=day.isocalendar()[1]) |
430 weeklink = '<a href="%s">%s</a>' % (html_escape(url), |
427 weeklink = '<a href="%s">%s</a>' % (html_escape(url), |
431 day.isocalendar()[1]) |
428 day.isocalendar()[1]) |
432 current_row.append(WEEKNUM_CELL % weeklink) |
429 current_row.append(WEEKNUM_CELL % weeklink) |
467 w(u'<tr>%s</tr>' % ( |
464 w(u'<tr>%s</tr>' % ( |
468 WEEK_TITLE % (_('week'), monday.isocalendar()[1], monthlink))) |
465 WEEK_TITLE % (_('week'), monday.isocalendar()[1], monthlink))) |
469 w(u'<tr><th>%s</th><th> </th></tr>'% _(u'Date')) |
466 w(u'<tr><th>%s</th><th> </th></tr>'% _(u'Date')) |
470 for day in date_range(monday, sunday): |
467 for day in date_range(monday, sunday): |
471 events = schedule.get(day) |
468 events = schedule.get(day) |
472 style = day.day_of_week % 2 and "even" or "odd" |
469 style = day.weekday() % 2 and "even" or "odd" |
473 w(u'<tr class="%s">' % style) |
470 w(u'<tr class="%s">' % style) |
474 if events: |
471 if events: |
475 hours = events.keys() |
472 hours = events.keys() |
476 hours.sort() |
473 hours.sort() |
477 w(AMPM_DAYWEEK % ( |
474 w(AMPM_DAYWEEK % ( |
478 len(hours), _(WEEKDAYS[day.day_of_week]), |
475 len(hours), _(WEEKDAYS[day.weekday()]), |
479 self.format_date(day))) |
476 self.format_date(day))) |
480 w(AMPM_WEEK_CELL % ( |
477 w(AMPM_WEEK_CELL % ( |
481 hours[0].hour, hours[0].minute, |
478 hours[0].hour, hours[0].minute, |
482 '\n'.join(events[hours[0]]))) |
479 '\n'.join(events[hours[0]]))) |
483 w(u'</tr>') |
480 w(u'</tr>') |