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