web/views/old_calendar.py
changeset 0 b97547f5f1fa
child 431 18b4dd650ef8
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """html calendar views
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 
       
     8 from mx.DateTime import DateTime, RelativeDateTime, Date, Time, today, Sunday
       
     9 
       
    10 from logilab.mtconverter import html_escape
       
    11 
       
    12 from cubicweb.interfaces import ICalendarViews
       
    13 from cubicweb.common.utils import date_range
       
    14 from cubicweb.common.selectors import interface_selector
       
    15 from cubicweb.common.registerers import priority_registerer
       
    16 from cubicweb.common.view import EntityView
       
    17 
       
    18 # Define some useful constants
       
    19 ONE_MONTH = RelativeDateTime(months=1)
       
    20 TODAY = today()
       
    21 THIS_MONTH = TODAY.month
       
    22 THIS_YEAR = TODAY.year
       
    23 # mx.DateTime and ustrftime could be used to build WEEKDAYS
       
    24 WEEKDAYS = [_("monday"), _("tuesday"), _("wednesday"), _("thursday"),
       
    25             _("friday"), _("saturday"), _("sunday")]
       
    26 
       
    27 # used by i18n tools
       
    28 MONTHNAMES = [ _('january'), _('february'), _('march'), _('april'), _('may'),
       
    29                _('june'), _('july'), _('august'), _('september'), _('october'),
       
    30                _('november'), _('december')
       
    31                ]
       
    32 
       
    33 class _CalendarView(EntityView):
       
    34     """base calendar view containing helpful methods to build calendar views"""
       
    35     __registerer__ = priority_registerer
       
    36     __selectors__ = (interface_selector,)
       
    37     accepts_interfaces = (ICalendarViews,)
       
    38     need_navigation = False
       
    39 
       
    40     # Navigation building methods / views ####################################
       
    41 
       
    42     PREV = u'<a href="%s">&lt;&lt;</a>&nbsp;&nbsp;<a href="%s">&lt;</a>'
       
    43     NEXT = u'<a href="%s">&gt;</a>&nbsp;&nbsp;<a href="%s">&gt;&gt;</a>'
       
    44     NAV_HEADER = u"""<table class="calendarPageHeader">
       
    45 <tr><td class="prev">%s</td><td class="next">%s</td></tr>
       
    46 </table>
       
    47 """ % (PREV, NEXT)
       
    48     
       
    49     def nav_header(self, date, smallshift=3, bigshift=9):
       
    50         """prints shortcut links to go to previous/next steps (month|week)"""
       
    51         prev1 = date - RelativeDateTime(months=smallshift)
       
    52         prev2 = date - RelativeDateTime(months=bigshift)
       
    53         next1 = date + RelativeDateTime(months=smallshift)
       
    54         next2 = date + RelativeDateTime(months=bigshift)
       
    55         rql, vid = self.rset.printable_rql(), self.id
       
    56         return self.NAV_HEADER % (
       
    57             html_escape(self.build_url(rql=rql, vid=vid, year=prev2.year, month=prev2.month)),
       
    58             html_escape(self.build_url(rql=rql, vid=vid, year=prev1.year, month=prev1.month)),
       
    59             html_escape(self.build_url(rql=rql, vid=vid, year=next1.year, month=next1.month)),
       
    60             html_escape(self.build_url(rql=rql, vid=vid, year=next2.year, month=next2.month)))
       
    61         
       
    62     
       
    63     # Calendar building methods ##############################################
       
    64     
       
    65     def build_calendars(self, schedule, begin, end):
       
    66         """build several HTML calendars at once, one for each month
       
    67         between begin and end
       
    68         """
       
    69         return [self.build_calendar(schedule, date)
       
    70                 for date in date_range(begin, end, incr=ONE_MONTH)]
       
    71     
       
    72     def build_calendar(self, schedule, first_day):
       
    73         """method responsible for building *one* HTML calendar"""
       
    74         # FIXME  iterates between [first_day-first_day.day_of_week ;
       
    75         #                          last_day+6-last_day.day_of_week]
       
    76         umonth = self.format_date(first_day, '%B %Y') # localized month name
       
    77         rows = []
       
    78         current_row = [NO_CELL] * first_day.day_of_week
       
    79         for daynum in xrange(0, first_day.days_in_month):
       
    80             # build cell day
       
    81             day = first_day + daynum
       
    82             events = schedule.get(day)
       
    83             if events:
       
    84                 events = [u'\n'.join(event) for event in events.values()]
       
    85                 current_row.append(CELL % (daynum+1, '\n'.join(events)))
       
    86             else:
       
    87                 current_row.append(EMPTY_CELL % (daynum+1))
       
    88             # store & reset current row on Sundays
       
    89             if day.day_of_week == Sunday:
       
    90                 rows.append(u'<tr>%s%s</tr>' % (WEEKNUM_CELL % day.iso_week[1], ''.join(current_row)))
       
    91                 current_row = []
       
    92         current_row.extend([NO_CELL] * (Sunday-day.day_of_week))
       
    93         rql = self.rset.printable_rql()
       
    94         if day.day_of_week != Sunday:
       
    95             rows.append(u'<tr>%s%s</tr>' % (WEEKNUM_CELL % day.iso_week[1], ''.join(current_row)))
       
    96         url = self.build_url(rql=rql, vid='calendarmonth',
       
    97                              year=first_day.year, month=first_day.month)
       
    98         monthlink = u'<a href="%s">%s</a>' % (html_escape(url), umonth)
       
    99         return CALENDAR(self.req) % (monthlink, '\n'.join(rows))
       
   100 
       
   101     def _mk_schedule(self, begin, end, itemvid='calendaritem'):
       
   102         """private method that gathers information from resultset
       
   103         and builds calendars according to it
       
   104 
       
   105         :param begin: begin of date range
       
   106         :param end: end of date rangs
       
   107         :param itemvid: which view to call to render elements in cells
       
   108 
       
   109         returns { day1 : { hour : [views] },
       
   110                   day2 : { hour : [views] } ... }
       
   111         """
       
   112         # put this here since all sub views are calling this method        
       
   113         self.req.add_css('cubicweb.calendar.css') 
       
   114         schedule = {}
       
   115         for row in xrange(len(self.rset.rows)):
       
   116             entity = self.entity(row)
       
   117             infos = u'<div class="event">'
       
   118             infos += self.view(itemvid, self.rset, row=row)
       
   119             infos += u'</div>'
       
   120             for date in entity.matching_dates(begin, end):
       
   121                 day = Date(date.year, date.month, date.day)
       
   122                 time = Time(date.hour, date.minute, date.second) 
       
   123                 schedule.setdefault(day, {})
       
   124                 schedule[day].setdefault(time, []).append(infos)
       
   125         return schedule
       
   126         
       
   127 
       
   128     @staticmethod
       
   129     def get_date_range(day=TODAY, shift=4):
       
   130         """returns a couple (begin, end)
       
   131 
       
   132         <begin> is the first day of current_month - shift
       
   133         <end> is the last day of current_month + (shift+1)
       
   134         """
       
   135         first_day_in_month = DateTime(day.year, day.month, 1)
       
   136         begin = first_day_in_month - RelativeDateTime(months=shift)
       
   137         end = (first_day_in_month + RelativeDateTime(months=shift+1)) - 1
       
   138         return begin, end
       
   139 
       
   140 
       
   141     def _build_ampm_cells(self, daynum, events):
       
   142         """create a view without any hourly details.
       
   143 
       
   144         :param daynum: day of the built cell
       
   145         :param events: dictionnary with all events classified by hours"""
       
   146         # split events according am/pm
       
   147         am_events = [event for e_time, e_list in events.iteritems()
       
   148                      if 0 <= e_time.hour < 12
       
   149                      for event in e_list]
       
   150         pm_events = [event for e_time, e_list in events.iteritems()
       
   151                      if 12 <= e_time.hour < 24
       
   152                      for event in e_list]
       
   153         # format each am/pm cell
       
   154         if am_events:
       
   155             am_content = AMPM_CONTENT % ("amCell", "am", '\n'.join(am_events))
       
   156         else:
       
   157             am_content = AMPM_EMPTY % ("amCell", "am")
       
   158         if pm_events:
       
   159             pm_content = AMPM_CONTENT % ("pmCell", "pm", '\n'.join(pm_events))
       
   160         else:
       
   161             pm_content = AMPM_EMPTY % ("pmCell", "pm")
       
   162         return am_content, pm_content
       
   163 
       
   164 
       
   165 
       
   166 class YearCalendarView(_CalendarView):
       
   167     id = 'calendaryear'
       
   168     title = _('calendar (year)')
       
   169 
       
   170     def call(self, year=THIS_YEAR, month=THIS_MONTH):
       
   171         """this view renders a 3x3 calendars' table"""
       
   172         year = int(self.req.form.get('year', year))
       
   173         month = int(self.req.form.get('month', month))
       
   174         center_date = DateTime(year, month)
       
   175         begin, end = self.get_date_range(day=center_date)
       
   176         schedule = self._mk_schedule(begin, end)
       
   177         self.w(self.nav_header(center_date))
       
   178         calendars = tuple(self.build_calendars(schedule, begin, end))
       
   179         self.w(SMALL_CALENDARS_PAGE % calendars)
       
   180 
       
   181 
       
   182 class SemesterCalendarView(_CalendarView):
       
   183     """this view renders three semesters as three rows of six columns,
       
   184     one column per month
       
   185     """
       
   186     id = 'calendarsemester'
       
   187     title = _('calendar (semester)')
       
   188 
       
   189     def call(self, year=THIS_YEAR, month=THIS_MONTH):
       
   190         year = int(self.req.form.get('year', year))
       
   191         month = int(self.req.form.get('month', month))
       
   192         begin = DateTime(year, month) - RelativeDateTime(months=2)
       
   193         end = DateTime(year, month) + RelativeDateTime(months=3)
       
   194         schedule = self._mk_schedule(begin, end)
       
   195         self.w(self.nav_header(DateTime(year, month), 1, 6))
       
   196         self.w(u'<table class="semesterCalendar">')
       
   197         self.build_calendars(schedule, begin, end)
       
   198         self.w(u'</table>')
       
   199         self.w(self.nav_header(DateTime(year, month), 1, 6))
       
   200 
       
   201     def build_calendars(self, schedule, begin, end):
       
   202         self.w(u'<tr>')
       
   203         rql = self.rset.printable_rql()
       
   204         for cur_month in date_range(begin, end, incr=ONE_MONTH):
       
   205             umonth = u'%s&nbsp;%s' % (self.format_date(cur_month, '%B'), cur_month.year)
       
   206             url = self.build_url(rql=rql, vid=self.id,
       
   207                                  year=cur_month.year, month=cur_month.month)
       
   208             self.w(u'<th colspan="2"><a href="%s">%s</a></th>' % (html_escape(url),
       
   209                                                                   umonth))
       
   210         self.w(u'</tr>')
       
   211         _ = self.req._
       
   212         for day_num in xrange(31):
       
   213             self.w(u'<tr>')
       
   214             for cur_month in date_range(begin, end, incr=ONE_MONTH):
       
   215                 if day_num >= cur_month.days_in_month:
       
   216                     self.w(u'%s%s' % (NO_CELL, NO_CELL))
       
   217                 else:
       
   218                     day = DateTime(cur_month.year, cur_month.month, day_num+1)
       
   219                     events = schedule.get(day)
       
   220                     self.w(u'<td>%s&nbsp;%s</td>\n' % (_(WEEKDAYS[day.day_of_week])[0].upper(), day_num+1))
       
   221                     self.format_day_events(day, events)
       
   222             self.w(u'</tr>')
       
   223             
       
   224     def format_day_events(self, day, events):
       
   225         if events:
       
   226             events = ['\n'.join(event) for event in events.values()]
       
   227             self.w(WEEK_CELL % '\n'.join(events))
       
   228         else:
       
   229             self.w(WEEK_EMPTY_CELL)
       
   230         
       
   231 
       
   232 class MonthCalendarView(_CalendarView):
       
   233     """this view renders a 3x1 calendars' table"""
       
   234     id = 'calendarmonth'
       
   235     title = _('calendar (month)')
       
   236     
       
   237     def call(self, year=THIS_YEAR, month=THIS_MONTH):
       
   238         year = int(self.req.form.get('year', year))
       
   239         month = int(self.req.form.get('month', month))
       
   240         center_date = DateTime(year, month)
       
   241         begin, end = self.get_date_range(day=center_date, shift=1)
       
   242         schedule = self._mk_schedule(begin, end)
       
   243         calendars = self.build_calendars(schedule, begin, end)
       
   244         self.w(self.nav_header(center_date, 1, 3))
       
   245         self.w(BIG_CALENDARS_PAGE % tuple(calendars))
       
   246         self.w(self.nav_header(center_date, 1, 3))
       
   247 
       
   248         
       
   249 class WeekCalendarView(_CalendarView):
       
   250     """this view renders a calendar for week events"""
       
   251     id = 'calendarweek'
       
   252     title = _('calendar (week)')
       
   253     
       
   254     def call(self, year=THIS_YEAR, week=TODAY.iso_week[1]):
       
   255         year = int(self.req.form.get('year', year))
       
   256         week = int(self.req.form.get('week', week))
       
   257         day0 = DateTime(year)
       
   258         first_day_of_week = (day0-day0.day_of_week) + 7*week
       
   259         begin, end = first_day_of_week-7, first_day_of_week+14
       
   260         schedule = self._mk_schedule(begin, end, itemvid='calendarlargeitem')
       
   261         self.w(self.nav_header(first_day_of_week))
       
   262         self.w(u'<table class="weekCalendar">')
       
   263         _weeks = [(first_day_of_week-7, first_day_of_week-1),
       
   264                   (first_day_of_week, first_day_of_week+6),
       
   265                   (first_day_of_week+7, first_day_of_week+13)]
       
   266         self.build_calendar(schedule, _weeks)
       
   267         self.w(u'</table>')
       
   268         self.w(self.nav_header(first_day_of_week))
       
   269  
       
   270     def build_calendar(self, schedule, weeks):
       
   271         rql = self.rset.printable_rql()
       
   272         _ = self.req._
       
   273         for monday, sunday in weeks:            
       
   274             umonth = self.format_date(monday, '%B %Y')
       
   275             url = self.build_url(rql=rql, vid='calendarmonth',
       
   276                                  year=monday.year, month=monday.month)
       
   277             monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth)
       
   278             self.w(u'<tr><th colspan="3">%s %s (%s)</th></tr>' \
       
   279                   % (_('week'), monday.iso_week[1], monthlink))
       
   280             for day in date_range(monday, sunday):
       
   281                 self.w(u'<tr>')
       
   282                 self.w(u'<td>%s</td>' % _(WEEKDAYS[day.day_of_week]))
       
   283                 self.w(u'<td>%s</td>' % (day.strftime('%Y-%m-%d')))
       
   284                 events = schedule.get(day)
       
   285                 if events:
       
   286                     events = ['\n'.join(event) for event in events.values()]
       
   287                     self.w(WEEK_CELL % '\n'.join(events))
       
   288                 else:
       
   289                     self.w(WEEK_EMPTY_CELL)
       
   290                 self.w(u'</tr>')
       
   291         
       
   292     def nav_header(self, date, smallshift=1, bigshift=3):
       
   293         """prints shortcut links to go to previous/next steps (month|week)"""
       
   294         prev1 = date - RelativeDateTime(weeks=smallshift)
       
   295         prev2 = date - RelativeDateTime(weeks=bigshift)
       
   296         next1 = date + RelativeDateTime(weeks=smallshift)
       
   297         next2 = date + RelativeDateTime(weeks=bigshift)
       
   298         rql, vid = self.rset.printable_rql(), self.id
       
   299         return self.NAV_HEADER % (
       
   300             html_escape(self.build_url(rql=rql, vid=vid, year=prev2.year, week=prev2.iso_week[1])),
       
   301             html_escape(self.build_url(rql=rql, vid=vid, year=prev1.year, week=prev1.iso_week[1])),
       
   302             html_escape(self.build_url(rql=rql, vid=vid, year=next1.year, week=next1.iso_week[1])),
       
   303             html_escape(self.build_url(rql=rql, vid=vid, year=next2.year, week=next2.iso_week[1])))
       
   304 
       
   305 
       
   306         
       
   307 class AMPMYearCalendarView(YearCalendarView):
       
   308     id = 'ampmcalendaryear'
       
   309     title = _('am/pm calendar (year)')
       
   310     
       
   311     def build_calendar(self, schedule, first_day):
       
   312         """method responsible for building *one* HTML calendar"""
       
   313         umonth = self.format_date(first_day, '%B %Y') # localized month name
       
   314         rows = [] # each row is: (am,pm), (am,pm) ... week_title
       
   315         current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.day_of_week
       
   316         rql = self.rset.printable_rql()
       
   317         for daynum in xrange(0, first_day.days_in_month):
       
   318             # build cells day
       
   319             day = first_day + daynum
       
   320             events = schedule.get(day)
       
   321             if events:
       
   322                 current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events))
       
   323             else:
       
   324                 current_row.append((AMPM_DAY % (daynum+1),
       
   325                                     AMPM_EMPTY % ("amCell", "am"),
       
   326                                     AMPM_EMPTY % ("pmCell", "pm")))
       
   327             # store & reset current row on Sundays
       
   328             if day.day_of_week == Sunday:
       
   329                 url = self.build_url(rql=rql, vid='ampmcalendarweek',
       
   330                                      year=day.year, week=day.iso_week[1])
       
   331                 weeklink = '<a href="%s">%s</a>' % (html_escape(url),
       
   332                                                     day.iso_week[1])
       
   333                 current_row.append(WEEKNUM_CELL % weeklink)
       
   334                 rows.append(current_row)
       
   335                 current_row = []
       
   336         current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (Sunday-day.day_of_week))
       
   337         url = self.build_url(rql=rql, vid='ampmcalendarweek',
       
   338                              year=day.year, week=day.iso_week[1])
       
   339         weeklink = '<a href="%s">%s</a>' % (html_escape(url), day.iso_week[1])
       
   340         current_row.append(WEEKNUM_CELL % weeklink)
       
   341         rows.append(current_row)
       
   342         # build two rows for each week: am & pm
       
   343         formatted_rows = []
       
   344         for row in rows:
       
   345             week_title = row.pop()
       
   346             day_row = [day for day, am, pm in row]
       
   347             am_row = [am for day, am, pm in row]
       
   348             pm_row = [pm for day, am, pm in row]
       
   349             formatted_rows.append('<tr>%s%s</tr>'% (week_title, '\n'.join(day_row)))
       
   350             formatted_rows.append('<tr class="amRow"><td>&nbsp;</td>%s</tr>'% '\n'.join(am_row))
       
   351             formatted_rows.append('<tr class="pmRow"><td>&nbsp;</td>%s</tr>'% '\n'.join(pm_row))
       
   352         # tigh everything together
       
   353         url = self.build_url(rql=rql, vid='ampmcalendarmonth',
       
   354                              year=first_day.year, month=first_day.month)
       
   355         monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth)
       
   356         return CALENDAR(self.req) % (monthlink, '\n'.join(formatted_rows))
       
   357         
       
   358 
       
   359 
       
   360 class AMPMSemesterCalendarView(SemesterCalendarView):
       
   361     """this view renders a 3x1 calendars' table"""
       
   362     id = 'ampmcalendarsemester'
       
   363     title = _('am/pm calendar (semester)')
       
   364 
       
   365     def build_calendars(self, schedule, begin, end):
       
   366         self.w(u'<tr>')
       
   367         rql = self.rset.printable_rql()
       
   368         for cur_month in date_range(begin, end, incr=ONE_MONTH):
       
   369             umonth = u'%s&nbsp;%s' % (self.format_date(cur_month, '%B'), cur_month.year)
       
   370             url = self.build_url(rql=rql, vid=self.id,
       
   371                                  year=cur_month.year, month=cur_month.month)
       
   372             self.w(u'<th colspan="3"><a href="%s">%s</a></th>' % (html_escape(url),
       
   373                                                                   umonth))
       
   374         self.w(u'</tr>')
       
   375         _ = self.req._
       
   376         for day_num in xrange(31):
       
   377             self.w(u'<tr>')
       
   378             for cur_month in date_range(begin, end, incr=ONE_MONTH):
       
   379                 if day_num >= cur_month.days_in_month:
       
   380                     self.w(u'%s%s%s' % (NO_CELL, NO_CELL, NO_CELL))
       
   381                 else:
       
   382                     day = DateTime(cur_month.year, cur_month.month, day_num+1)
       
   383                     events = schedule.get(day)
       
   384                     self.w(u'<td>%s&nbsp;%s</td>\n' % (_(WEEKDAYS[day.day_of_week])[0].upper(),
       
   385                                                        day_num+1))
       
   386                     self.format_day_events(day, events)
       
   387             self.w(u'</tr>')
       
   388     
       
   389     def format_day_events(self, day, events):
       
   390         if events:
       
   391             self.w(u'\n'.join(self._build_ampm_cells(day, events)))
       
   392         else:
       
   393             self.w(u'%s %s'% (AMPM_EMPTY % ("amCell", "am"), 
       
   394                               AMPM_EMPTY % ("pmCell", "pm")))
       
   395 
       
   396 
       
   397 class AMPMMonthCalendarView(MonthCalendarView):
       
   398     """this view renders a 3x1 calendars' table"""
       
   399     id = 'ampmcalendarmonth'
       
   400     title = _('am/pm calendar (month)')
       
   401 
       
   402     def build_calendar(self, schedule, first_day):
       
   403         """method responsible for building *one* HTML calendar"""
       
   404         umonth = self.format_date(first_day, '%B %Y') # localized month name
       
   405         rows = [] # each row is: (am,pm), (am,pm) ... week_title
       
   406         current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.day_of_week
       
   407         rql = self.rset.printable_rql()
       
   408         for daynum in xrange(0, first_day.days_in_month):
       
   409             # build cells day
       
   410             day = first_day + daynum
       
   411             events = schedule.get(day)
       
   412             if events:
       
   413                 current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events))
       
   414             else:
       
   415                 current_row.append((AMPM_DAY % (daynum+1),
       
   416                                     AMPM_EMPTY % ("amCell", "am"),
       
   417                                     AMPM_EMPTY % ("pmCell", "pm")))
       
   418             # store & reset current row on Sundays
       
   419             if day.day_of_week == Sunday:
       
   420                 url = self.build_url(rql=rql, vid='ampmcalendarweek',
       
   421                                      year=day.year, week=day.iso_week[1])
       
   422                 weeklink = '<a href="%s">%s</a>' % (html_escape(url),
       
   423                                                     day.iso_week[1])
       
   424                 current_row.append(WEEKNUM_CELL % weeklink)
       
   425                 rows.append(current_row)
       
   426                 current_row = []
       
   427         current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (Sunday-day.day_of_week))
       
   428         url = self.build_url(rql=rql, vid='ampmcalendarweek',
       
   429                              year=day.year, week=day.iso_week[1])
       
   430         weeklink = '<a href="%s">%s</a>' % (html_escape(url),
       
   431                                             day.iso_week[1])
       
   432         current_row.append(WEEKNUM_CELL % weeklink)
       
   433         rows.append(current_row)
       
   434         # build two rows for each week: am & pm
       
   435         formatted_rows = []
       
   436         for row in rows:
       
   437             week_title = row.pop()
       
   438             day_row = [day for day, am, pm in row]
       
   439             am_row = [am for day, am, pm in row]
       
   440             pm_row = [pm for day, am, pm in row]
       
   441             formatted_rows.append('<tr>%s%s</tr>'% (week_title, '\n'.join(day_row)))
       
   442             formatted_rows.append('<tr class="amRow"><td>&nbsp;</td>%s</tr>'% '\n'.join(am_row))
       
   443             formatted_rows.append('<tr class="pmRow"><td>&nbsp;</td>%s</tr>'% '\n'.join(pm_row))
       
   444         # tigh everything together
       
   445         url = self.build_url(rql=rql, vid='ampmcalendarmonth',
       
   446                              year=first_day.year, month=first_day.month)
       
   447         monthlink = '<a href="%s">%s</a>' % (html_escape(url),
       
   448                                              umonth)
       
   449         return CALENDAR(self.req) % (monthlink, '\n'.join(formatted_rows))      
       
   450     
       
   451 
       
   452     
       
   453 class AMPMWeekCalendarView(WeekCalendarView):
       
   454     """this view renders a 3x1 calendars' table"""
       
   455     id = 'ampmcalendarweek'
       
   456     title = _('am/pm calendar (week)')
       
   457 
       
   458     def build_calendar(self, schedule, weeks):
       
   459         rql = self.rset.printable_rql()
       
   460         w = self.w
       
   461         _ = self.req._
       
   462         for monday, sunday in weeks:
       
   463             umonth = self.format_date(monday, '%B %Y')
       
   464             url = self.build_url(rql=rql, vid='ampmcalendarmonth',
       
   465                                  year=monday.year, month=monday.month)
       
   466             monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth)
       
   467             w(u'<tr>%s</tr>' % (
       
   468                 WEEK_TITLE % (_('week'), monday.iso_week[1], monthlink)))
       
   469             w(u'<tr><th>%s</th><th>&nbsp;</th></tr>'% _(u'Date'))
       
   470             for day in date_range(monday, sunday):
       
   471                 events = schedule.get(day)
       
   472                 style = day.day_of_week % 2 and "even" or "odd"
       
   473                 w(u'<tr class="%s">' % style)
       
   474                 if events:
       
   475                     hours = events.keys()
       
   476                     hours.sort()
       
   477                     w(AMPM_DAYWEEK % (
       
   478                         len(hours), _(WEEKDAYS[day.day_of_week]),
       
   479                         self.format_date(day)))
       
   480                     w(AMPM_WEEK_CELL % (
       
   481                         hours[0].hour, hours[0].minute,
       
   482                         '\n'.join(events[hours[0]])))
       
   483                     w(u'</tr>')
       
   484                     for hour in hours[1:]:
       
   485                         w(u'<tr class="%s">%s</tr>'% (
       
   486                             style, AMPM_WEEK_CELL % (hour.hour, hour.minute,
       
   487                                                      '\n'.join(events[hour]))))
       
   488                 else:
       
   489                     w(AMPM_DAYWEEK_EMPTY % (
       
   490                         _(WEEKDAYS[day.day_of_week]),
       
   491                         self.format_date(day)))
       
   492                     w(WEEK_EMPTY_CELL)
       
   493                     w(u'</tr>')
       
   494 
       
   495 
       
   496 SMALL_CALENDARS_PAGE = u"""<table class="smallCalendars">
       
   497 <tr><td class="calendar">%s</td><td class="calendar">%s</td><td class="calendar">%s</td></tr>
       
   498 <tr><td class="calendar">%s</td><td class="calendar">%s</td><td class="calendar">%s</td></tr>
       
   499 <tr><td class="calendar">%s</td><td class="calendar">%s</td><td class="calendar">%s</td></tr>
       
   500 </table>
       
   501 """
       
   502 
       
   503 BIG_CALENDARS_PAGE = u"""<table class="bigCalendars">
       
   504 <tr><td class="calendar">%s</td></tr>
       
   505 <tr><td class="calendar">%s</td></tr>
       
   506 <tr><td class="calendar">%s</td></tr>
       
   507 </table>
       
   508 """
       
   509 
       
   510 WEEKNUM_CELL = u'<td class="weeknum">%s</td>'
       
   511 
       
   512 def CALENDAR(req):
       
   513     _ = req._
       
   514     WEEKNUM_HEADER = u'<th class="weeknum">%s</th>' % _('week')
       
   515     CAL_HEADER = WEEKNUM_HEADER + u' \n'.join([u'<th class="weekday">%s</th>' % _(day)[0].upper()
       
   516                                                for day in WEEKDAYS])
       
   517     return u"""<table>
       
   518 <tr><th class="month" colspan="8">%%s</th></tr>
       
   519 <tr>
       
   520   %s
       
   521 </tr>
       
   522 %%s
       
   523 </table>
       
   524 """ % (CAL_HEADER,)
       
   525 
       
   526 
       
   527 DAY_TEMPLATE = """<tr><td class="weekday">%(daylabel)s</td><td>%(dmydate)s</td><td>%(dayschedule)s</td>
       
   528 """
       
   529 
       
   530 NO_CELL = u'<td class="noday"></td>'
       
   531 EMPTY_CELL = u'<td class="cellEmpty"><span class="cellTitle">%s</span></td>'
       
   532 CELL = u'<td class="cell"><span class="cellTitle">%s</span><div class="cellContent">%s</div></td>'
       
   533 
       
   534 AMPM_DAY = u'<td class="cellDay">%d</td>'
       
   535 AMPM_EMPTY = u'<td class="%sEmpty"><span class="cellTitle">%s</span></td>'
       
   536 AMPM_CONTENT = u'<td class="%s"><span class="cellTitle">%s</span><div class="cellContent">%s</div></td>'
       
   537 
       
   538 WEEK_TITLE = u'<th class="weekTitle" colspan="2">%s %s (%s)</th>'
       
   539 WEEK_EMPTY_CELL = u'<td class="weekEmptyCell">&nbsp;</td>'
       
   540 WEEK_CELL = u'<td class="weekCell"><div class="cellContent">%s</div></td>'
       
   541 
       
   542 AMPM_DAYWEEK_EMPTY = u'<td>%s&nbsp;%s</td>'
       
   543 AMPM_DAYWEEK = u'<td rowspan="%d">%s&nbsp;%s</td>'
       
   544 AMPM_WEEK_CELL = u'<td class="ampmWeekCell"><div class="cellContent">%02d:%02d - %s</div></td>'