diff -r 000000000000 -r b97547f5f1fa web/views/old_calendar.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/old_calendar.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,544 @@ +"""html calendar views + +:organization: Logilab +:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" + +from mx.DateTime import DateTime, RelativeDateTime, Date, Time, today, Sunday + +from logilab.mtconverter import html_escape + +from cubicweb.interfaces import ICalendarViews +from cubicweb.common.utils import date_range +from cubicweb.common.selectors import interface_selector +from cubicweb.common.registerers import priority_registerer +from cubicweb.common.view import EntityView + +# Define some useful constants +ONE_MONTH = RelativeDateTime(months=1) +TODAY = today() +THIS_MONTH = TODAY.month +THIS_YEAR = TODAY.year +# mx.DateTime and ustrftime could be used to build WEEKDAYS +WEEKDAYS = [_("monday"), _("tuesday"), _("wednesday"), _("thursday"), + _("friday"), _("saturday"), _("sunday")] + +# used by i18n tools +MONTHNAMES = [ _('january'), _('february'), _('march'), _('april'), _('may'), + _('june'), _('july'), _('august'), _('september'), _('october'), + _('november'), _('december') + ] + +class _CalendarView(EntityView): + """base calendar view containing helpful methods to build calendar views""" + __registerer__ = priority_registerer + __selectors__ = (interface_selector,) + accepts_interfaces = (ICalendarViews,) + need_navigation = False + + # Navigation building methods / views #################################### + + PREV = u'<<  <' + NEXT = u'>  >>' + NAV_HEADER = u""" + +
%s%s
+""" % (PREV, NEXT) + + def nav_header(self, date, smallshift=3, bigshift=9): + """prints shortcut links to go to previous/next steps (month|week)""" + prev1 = date - RelativeDateTime(months=smallshift) + prev2 = date - RelativeDateTime(months=bigshift) + next1 = date + RelativeDateTime(months=smallshift) + next2 = date + RelativeDateTime(months=bigshift) + rql, vid = self.rset.printable_rql(), self.id + return self.NAV_HEADER % ( + html_escape(self.build_url(rql=rql, vid=vid, year=prev2.year, month=prev2.month)), + html_escape(self.build_url(rql=rql, vid=vid, year=prev1.year, month=prev1.month)), + html_escape(self.build_url(rql=rql, vid=vid, year=next1.year, month=next1.month)), + html_escape(self.build_url(rql=rql, vid=vid, year=next2.year, month=next2.month))) + + + # Calendar building methods ############################################## + + def build_calendars(self, schedule, begin, end): + """build several HTML calendars at once, one for each month + between begin and end + """ + return [self.build_calendar(schedule, date) + for date in date_range(begin, end, incr=ONE_MONTH)] + + def build_calendar(self, schedule, first_day): + """method responsible for building *one* HTML calendar""" + # FIXME iterates between [first_day-first_day.day_of_week ; + # last_day+6-last_day.day_of_week] + umonth = self.format_date(first_day, '%B %Y') # localized month name + rows = [] + current_row = [NO_CELL] * first_day.day_of_week + for daynum in xrange(0, first_day.days_in_month): + # build cell day + day = first_day + daynum + events = schedule.get(day) + if events: + events = [u'\n'.join(event) for event in events.values()] + current_row.append(CELL % (daynum+1, '\n'.join(events))) + else: + current_row.append(EMPTY_CELL % (daynum+1)) + # store & reset current row on Sundays + if day.day_of_week == Sunday: + rows.append(u'%s%s' % (WEEKNUM_CELL % day.iso_week[1], ''.join(current_row))) + current_row = [] + current_row.extend([NO_CELL] * (Sunday-day.day_of_week)) + rql = self.rset.printable_rql() + if day.day_of_week != Sunday: + rows.append(u'%s%s' % (WEEKNUM_CELL % day.iso_week[1], ''.join(current_row))) + url = self.build_url(rql=rql, vid='calendarmonth', + year=first_day.year, month=first_day.month) + monthlink = u'%s' % (html_escape(url), umonth) + return CALENDAR(self.req) % (monthlink, '\n'.join(rows)) + + def _mk_schedule(self, begin, end, itemvid='calendaritem'): + """private method that gathers information from resultset + and builds calendars according to it + + :param begin: begin of date range + :param end: end of date rangs + :param itemvid: which view to call to render elements in cells + + returns { day1 : { hour : [views] }, + day2 : { hour : [views] } ... } + """ + # put this here since all sub views are calling this method + self.req.add_css('cubicweb.calendar.css') + schedule = {} + for row in xrange(len(self.rset.rows)): + entity = self.entity(row) + infos = u'
' + infos += self.view(itemvid, self.rset, row=row) + infos += u'
' + for date in entity.matching_dates(begin, end): + day = Date(date.year, date.month, date.day) + time = Time(date.hour, date.minute, date.second) + schedule.setdefault(day, {}) + schedule[day].setdefault(time, []).append(infos) + return schedule + + + @staticmethod + def get_date_range(day=TODAY, shift=4): + """returns a couple (begin, end) + + is the first day of current_month - shift + is the last day of current_month + (shift+1) + """ + first_day_in_month = DateTime(day.year, day.month, 1) + begin = first_day_in_month - RelativeDateTime(months=shift) + end = (first_day_in_month + RelativeDateTime(months=shift+1)) - 1 + return begin, end + + + def _build_ampm_cells(self, daynum, events): + """create a view without any hourly details. + + :param daynum: day of the built cell + :param events: dictionnary with all events classified by hours""" + # split events according am/pm + am_events = [event for e_time, e_list in events.iteritems() + if 0 <= e_time.hour < 12 + for event in e_list] + pm_events = [event for e_time, e_list in events.iteritems() + if 12 <= e_time.hour < 24 + for event in e_list] + # format each am/pm cell + if am_events: + am_content = AMPM_CONTENT % ("amCell", "am", '\n'.join(am_events)) + else: + am_content = AMPM_EMPTY % ("amCell", "am") + if pm_events: + pm_content = AMPM_CONTENT % ("pmCell", "pm", '\n'.join(pm_events)) + else: + pm_content = AMPM_EMPTY % ("pmCell", "pm") + return am_content, pm_content + + + +class YearCalendarView(_CalendarView): + id = 'calendaryear' + title = _('calendar (year)') + + def call(self, year=THIS_YEAR, month=THIS_MONTH): + """this view renders a 3x3 calendars' table""" + year = int(self.req.form.get('year', year)) + month = int(self.req.form.get('month', month)) + center_date = DateTime(year, month) + begin, end = self.get_date_range(day=center_date) + schedule = self._mk_schedule(begin, end) + self.w(self.nav_header(center_date)) + calendars = tuple(self.build_calendars(schedule, begin, end)) + self.w(SMALL_CALENDARS_PAGE % calendars) + + +class SemesterCalendarView(_CalendarView): + """this view renders three semesters as three rows of six columns, + one column per month + """ + id = 'calendarsemester' + title = _('calendar (semester)') + + def call(self, year=THIS_YEAR, month=THIS_MONTH): + year = int(self.req.form.get('year', year)) + month = int(self.req.form.get('month', month)) + begin = DateTime(year, month) - RelativeDateTime(months=2) + end = DateTime(year, month) + RelativeDateTime(months=3) + schedule = self._mk_schedule(begin, end) + self.w(self.nav_header(DateTime(year, month), 1, 6)) + self.w(u'') + self.build_calendars(schedule, begin, end) + self.w(u'
') + self.w(self.nav_header(DateTime(year, month), 1, 6)) + + def build_calendars(self, schedule, begin, end): + self.w(u'') + rql = self.rset.printable_rql() + for cur_month in date_range(begin, end, incr=ONE_MONTH): + umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year) + url = self.build_url(rql=rql, vid=self.id, + year=cur_month.year, month=cur_month.month) + self.w(u'%s' % (html_escape(url), + umonth)) + self.w(u'') + _ = self.req._ + for day_num in xrange(31): + self.w(u'') + for cur_month in date_range(begin, end, incr=ONE_MONTH): + if day_num >= cur_month.days_in_month: + self.w(u'%s%s' % (NO_CELL, NO_CELL)) + else: + day = DateTime(cur_month.year, cur_month.month, day_num+1) + events = schedule.get(day) + self.w(u'%s %s\n' % (_(WEEKDAYS[day.day_of_week])[0].upper(), day_num+1)) + self.format_day_events(day, events) + self.w(u'') + + def format_day_events(self, day, events): + if events: + events = ['\n'.join(event) for event in events.values()] + self.w(WEEK_CELL % '\n'.join(events)) + else: + self.w(WEEK_EMPTY_CELL) + + +class MonthCalendarView(_CalendarView): + """this view renders a 3x1 calendars' table""" + id = 'calendarmonth' + title = _('calendar (month)') + + def call(self, year=THIS_YEAR, month=THIS_MONTH): + year = int(self.req.form.get('year', year)) + month = int(self.req.form.get('month', month)) + center_date = DateTime(year, month) + begin, end = self.get_date_range(day=center_date, shift=1) + schedule = self._mk_schedule(begin, end) + calendars = self.build_calendars(schedule, begin, end) + self.w(self.nav_header(center_date, 1, 3)) + self.w(BIG_CALENDARS_PAGE % tuple(calendars)) + self.w(self.nav_header(center_date, 1, 3)) + + +class WeekCalendarView(_CalendarView): + """this view renders a calendar for week events""" + id = 'calendarweek' + title = _('calendar (week)') + + def call(self, year=THIS_YEAR, week=TODAY.iso_week[1]): + year = int(self.req.form.get('year', year)) + week = int(self.req.form.get('week', week)) + day0 = DateTime(year) + first_day_of_week = (day0-day0.day_of_week) + 7*week + begin, end = first_day_of_week-7, first_day_of_week+14 + schedule = self._mk_schedule(begin, end, itemvid='calendarlargeitem') + self.w(self.nav_header(first_day_of_week)) + self.w(u'') + _weeks = [(first_day_of_week-7, first_day_of_week-1), + (first_day_of_week, first_day_of_week+6), + (first_day_of_week+7, first_day_of_week+13)] + self.build_calendar(schedule, _weeks) + self.w(u'
') + self.w(self.nav_header(first_day_of_week)) + + def build_calendar(self, schedule, weeks): + rql = self.rset.printable_rql() + _ = self.req._ + for monday, sunday in weeks: + umonth = self.format_date(monday, '%B %Y') + url = self.build_url(rql=rql, vid='calendarmonth', + year=monday.year, month=monday.month) + monthlink = '%s' % (html_escape(url), umonth) + self.w(u'%s %s (%s)' \ + % (_('week'), monday.iso_week[1], monthlink)) + for day in date_range(monday, sunday): + self.w(u'') + self.w(u'%s' % _(WEEKDAYS[day.day_of_week])) + self.w(u'%s' % (day.strftime('%Y-%m-%d'))) + events = schedule.get(day) + if events: + events = ['\n'.join(event) for event in events.values()] + self.w(WEEK_CELL % '\n'.join(events)) + else: + self.w(WEEK_EMPTY_CELL) + self.w(u'') + + def nav_header(self, date, smallshift=1, bigshift=3): + """prints shortcut links to go to previous/next steps (month|week)""" + prev1 = date - RelativeDateTime(weeks=smallshift) + prev2 = date - RelativeDateTime(weeks=bigshift) + next1 = date + RelativeDateTime(weeks=smallshift) + next2 = date + RelativeDateTime(weeks=bigshift) + rql, vid = self.rset.printable_rql(), self.id + return self.NAV_HEADER % ( + html_escape(self.build_url(rql=rql, vid=vid, year=prev2.year, week=prev2.iso_week[1])), + html_escape(self.build_url(rql=rql, vid=vid, year=prev1.year, week=prev1.iso_week[1])), + html_escape(self.build_url(rql=rql, vid=vid, year=next1.year, week=next1.iso_week[1])), + html_escape(self.build_url(rql=rql, vid=vid, year=next2.year, week=next2.iso_week[1]))) + + + +class AMPMYearCalendarView(YearCalendarView): + id = 'ampmcalendaryear' + title = _('am/pm calendar (year)') + + def build_calendar(self, schedule, first_day): + """method responsible for building *one* HTML calendar""" + umonth = self.format_date(first_day, '%B %Y') # localized month name + rows = [] # each row is: (am,pm), (am,pm) ... week_title + current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.day_of_week + rql = self.rset.printable_rql() + for daynum in xrange(0, first_day.days_in_month): + # build cells day + day = first_day + daynum + events = schedule.get(day) + if events: + current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events)) + else: + current_row.append((AMPM_DAY % (daynum+1), + AMPM_EMPTY % ("amCell", "am"), + AMPM_EMPTY % ("pmCell", "pm"))) + # store & reset current row on Sundays + if day.day_of_week == Sunday: + url = self.build_url(rql=rql, vid='ampmcalendarweek', + year=day.year, week=day.iso_week[1]) + weeklink = '%s' % (html_escape(url), + day.iso_week[1]) + current_row.append(WEEKNUM_CELL % weeklink) + rows.append(current_row) + current_row = [] + current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (Sunday-day.day_of_week)) + url = self.build_url(rql=rql, vid='ampmcalendarweek', + year=day.year, week=day.iso_week[1]) + weeklink = '%s' % (html_escape(url), day.iso_week[1]) + current_row.append(WEEKNUM_CELL % weeklink) + rows.append(current_row) + # build two rows for each week: am & pm + formatted_rows = [] + for row in rows: + week_title = row.pop() + day_row = [day for day, am, pm in row] + am_row = [am for day, am, pm in row] + pm_row = [pm for day, am, pm in row] + formatted_rows.append('%s%s'% (week_title, '\n'.join(day_row))) + formatted_rows.append(' %s'% '\n'.join(am_row)) + formatted_rows.append(' %s'% '\n'.join(pm_row)) + # tigh everything together + url = self.build_url(rql=rql, vid='ampmcalendarmonth', + year=first_day.year, month=first_day.month) + monthlink = '%s' % (html_escape(url), umonth) + return CALENDAR(self.req) % (monthlink, '\n'.join(formatted_rows)) + + + +class AMPMSemesterCalendarView(SemesterCalendarView): + """this view renders a 3x1 calendars' table""" + id = 'ampmcalendarsemester' + title = _('am/pm calendar (semester)') + + def build_calendars(self, schedule, begin, end): + self.w(u'') + rql = self.rset.printable_rql() + for cur_month in date_range(begin, end, incr=ONE_MONTH): + umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year) + url = self.build_url(rql=rql, vid=self.id, + year=cur_month.year, month=cur_month.month) + self.w(u'%s' % (html_escape(url), + umonth)) + self.w(u'') + _ = self.req._ + for day_num in xrange(31): + self.w(u'') + for cur_month in date_range(begin, end, incr=ONE_MONTH): + if day_num >= cur_month.days_in_month: + self.w(u'%s%s%s' % (NO_CELL, NO_CELL, NO_CELL)) + else: + day = DateTime(cur_month.year, cur_month.month, day_num+1) + events = schedule.get(day) + self.w(u'%s %s\n' % (_(WEEKDAYS[day.day_of_week])[0].upper(), + day_num+1)) + self.format_day_events(day, events) + self.w(u'') + + def format_day_events(self, day, events): + if events: + self.w(u'\n'.join(self._build_ampm_cells(day, events))) + else: + self.w(u'%s %s'% (AMPM_EMPTY % ("amCell", "am"), + AMPM_EMPTY % ("pmCell", "pm"))) + + +class AMPMMonthCalendarView(MonthCalendarView): + """this view renders a 3x1 calendars' table""" + id = 'ampmcalendarmonth' + title = _('am/pm calendar (month)') + + def build_calendar(self, schedule, first_day): + """method responsible for building *one* HTML calendar""" + umonth = self.format_date(first_day, '%B %Y') # localized month name + rows = [] # each row is: (am,pm), (am,pm) ... week_title + current_row = [(NO_CELL, NO_CELL, NO_CELL)] * first_day.day_of_week + rql = self.rset.printable_rql() + for daynum in xrange(0, first_day.days_in_month): + # build cells day + day = first_day + daynum + events = schedule.get(day) + if events: + current_row.append((AMPM_DAY % (daynum+1),) + self._build_ampm_cells(daynum, events)) + else: + current_row.append((AMPM_DAY % (daynum+1), + AMPM_EMPTY % ("amCell", "am"), + AMPM_EMPTY % ("pmCell", "pm"))) + # store & reset current row on Sundays + if day.day_of_week == Sunday: + url = self.build_url(rql=rql, vid='ampmcalendarweek', + year=day.year, week=day.iso_week[1]) + weeklink = '%s' % (html_escape(url), + day.iso_week[1]) + current_row.append(WEEKNUM_CELL % weeklink) + rows.append(current_row) + current_row = [] + current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (Sunday-day.day_of_week)) + url = self.build_url(rql=rql, vid='ampmcalendarweek', + year=day.year, week=day.iso_week[1]) + weeklink = '%s' % (html_escape(url), + day.iso_week[1]) + current_row.append(WEEKNUM_CELL % weeklink) + rows.append(current_row) + # build two rows for each week: am & pm + formatted_rows = [] + for row in rows: + week_title = row.pop() + day_row = [day for day, am, pm in row] + am_row = [am for day, am, pm in row] + pm_row = [pm for day, am, pm in row] + formatted_rows.append('%s%s'% (week_title, '\n'.join(day_row))) + formatted_rows.append(' %s'% '\n'.join(am_row)) + formatted_rows.append(' %s'% '\n'.join(pm_row)) + # tigh everything together + url = self.build_url(rql=rql, vid='ampmcalendarmonth', + year=first_day.year, month=first_day.month) + monthlink = '%s' % (html_escape(url), + umonth) + return CALENDAR(self.req) % (monthlink, '\n'.join(formatted_rows)) + + + +class AMPMWeekCalendarView(WeekCalendarView): + """this view renders a 3x1 calendars' table""" + id = 'ampmcalendarweek' + title = _('am/pm calendar (week)') + + def build_calendar(self, schedule, weeks): + rql = self.rset.printable_rql() + w = self.w + _ = self.req._ + for monday, sunday in weeks: + umonth = self.format_date(monday, '%B %Y') + url = self.build_url(rql=rql, vid='ampmcalendarmonth', + year=monday.year, month=monday.month) + monthlink = '%s' % (html_escape(url), umonth) + w(u'%s' % ( + WEEK_TITLE % (_('week'), monday.iso_week[1], monthlink))) + w(u'%s '% _(u'Date')) + for day in date_range(monday, sunday): + events = schedule.get(day) + style = day.day_of_week % 2 and "even" or "odd" + w(u'' % style) + if events: + hours = events.keys() + hours.sort() + w(AMPM_DAYWEEK % ( + len(hours), _(WEEKDAYS[day.day_of_week]), + self.format_date(day))) + w(AMPM_WEEK_CELL % ( + hours[0].hour, hours[0].minute, + '\n'.join(events[hours[0]]))) + w(u'') + for hour in hours[1:]: + w(u'%s'% ( + style, AMPM_WEEK_CELL % (hour.hour, hour.minute, + '\n'.join(events[hour])))) + else: + w(AMPM_DAYWEEK_EMPTY % ( + _(WEEKDAYS[day.day_of_week]), + self.format_date(day))) + w(WEEK_EMPTY_CELL) + w(u'') + + +SMALL_CALENDARS_PAGE = u""" + + + +
%s%s%s
%s%s%s
%s%s%s
+""" + +BIG_CALENDARS_PAGE = u""" + + + +
%s
%s
%s
+""" + +WEEKNUM_CELL = u'%s' + +def CALENDAR(req): + _ = req._ + WEEKNUM_HEADER = u'%s' % _('week') + CAL_HEADER = WEEKNUM_HEADER + u' \n'.join([u'%s' % _(day)[0].upper() + for day in WEEKDAYS]) + return u""" + + + %s + +%%s +
%%s
+""" % (CAL_HEADER,) + + +DAY_TEMPLATE = """%(daylabel)s%(dmydate)s%(dayschedule)s +""" + +NO_CELL = u'' +EMPTY_CELL = u'%s' +CELL = u'%s
%s
' + +AMPM_DAY = u'%d' +AMPM_EMPTY = u'%s' +AMPM_CONTENT = u'%s
%s
' + +WEEK_TITLE = u'%s %s (%s)' +WEEK_EMPTY_CELL = u' ' +WEEK_CELL = u'
%s
' + +AMPM_DAYWEEK_EMPTY = u'%s %s' +AMPM_DAYWEEK = u'%s %s' +AMPM_WEEK_CELL = u'
%02d:%02d - %s
'