# HG changeset patch # User sylvain.thenault@logilab.fr # Date 1241536410 -7200 # Node ID 7ff9f0726ee47ca3cde3d8ee54f675bd49a9a409 # Parent 04a215f2ff439c4681070c456e13a0884baba1f4# Parent 1f16db872f920f715c70e096571411a1901039dc merge diff -r 04a215f2ff43 -r 7ff9f0726ee4 cwconfig.py --- a/cwconfig.py Tue May 05 17:12:53 2009 +0200 +++ b/cwconfig.py Tue May 05 17:13:30 2009 +0200 @@ -677,7 +677,7 @@ return join(self.instance_data_dir(), self.appid) def init_cubes(self, cubes): - assert self._cubes is None + assert self._cubes is None, self._cubes self._cubes = self.reorder_cubes(cubes) # load cubes'__init__.py file first for cube in cubes: diff -r 04a215f2ff43 -r 7ff9f0726ee4 server/serverctl.py --- a/server/serverctl.py Tue May 05 17:12:53 2009 +0200 +++ b/server/serverctl.py Tue May 05 17:13:30 2009 +0200 @@ -139,6 +139,8 @@ return in_memory_cnx(config, login, pwd) except AuthenticationError: print 'wrong user/password' + # reset cubes else we'll have an assertion error on next retry + config._cubes = None login, pwd = manager_userpasswd() # repository specific command handlers ######################################## diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/data/cubicweb.preferences.js --- a/web/data/cubicweb.preferences.js Tue May 05 17:12:53 2009 +0200 +++ b/web/data/cubicweb.preferences.js Tue May 05 17:13:30 2009 +0200 @@ -4,7 +4,7 @@ * move me in a more appropriate place */ -function toggleVisibility(elemId) { +function toggleVisibility(elemId, cookiename) { _clearPreviousMessages(); jqNode(elemId).toggleClass('hidden'); asyncRemoteExec('set_cookie', cookiename, diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/form.py --- a/web/form.py Tue May 05 17:12:53 2009 +0200 +++ b/web/form.py Tue May 05 17:13:30 2009 +0200 @@ -20,7 +20,7 @@ from cubicweb.web.controller import NAV_FORM_PARAMETERS from cubicweb.web.formfields import (Field, StringField, RelationField, HiddenInitialValueField) -from cubicweb.web.formrenderers import FormRenderer +from cubicweb.web import formrenderers from cubicweb.web import formwidgets as fwdgs class FormViewMixIn(object): @@ -220,6 +220,7 @@ __registry__ = 'forms' __select__ = yes() + renderer_cls = formrenderers.FormRenderer is_subform = False # attributes overrideable through __init__ @@ -319,7 +320,7 @@ """render this form, using the renderer given in args or the default FormRenderer() """ - renderer = values.pop('renderer', FormRenderer()) + renderer = values.pop('renderer', self.renderer_cls()) return renderer.render(self, values) def form_build_context(self, rendervalues=None): diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/formrenderers.py --- a/web/formrenderers.py Tue May 05 17:12:53 2009 +0200 +++ b/web/formrenderers.py Tue May 05 17:13:30 2009 +0200 @@ -328,7 +328,7 @@ super(EntityFormRenderer, self).render_buttons(w, form) def relations_form(self, w, form): - srels_by_cat = form.srelations_by_category(('generic', 'metadata'), 'add') + srels_by_cat = form.srelations_by_category('generic', 'add') if not srels_by_cat: return u'' req = form.req diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/views/baseviews.py --- a/web/views/baseviews.py Tue May 05 17:12:53 2009 +0200 +++ b/web/views/baseviews.py Tue May 05 17:13:30 2009 +0200 @@ -16,7 +16,7 @@ from rql import nodes -from logilab.mtconverter import TransformError, html_escape +from logilab.mtconverter import TransformError, html_escape, xml_escape from cubicweb import NoSelectableObject from cubicweb.selectors import yes, empty_rset @@ -338,7 +338,7 @@ highlighted = '%s' % searched for attr in entity.e_schema.indexable_attributes(): try: - value = html_escape(entity.printable_value(attr, format='text/plain').lower()) + value = xml_escape(entity.printable_value(attr, format='text/plain').lower()) except TransformError, ex: continue except: diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/views/boxes.py --- a/web/views/boxes.py Tue May 05 17:12:53 2009 +0200 +++ b/web/views/boxes.py Tue May 05 17:13:30 2009 +0200 @@ -136,10 +136,10 @@ eschema = entity.e_schema for rschema, teschema, x in self.add_related_schemas(entity): if x == 'subject': - label = 'add %s %s %s %s' % (eschema, rschema, teschema, x) + label = '%s %s %s %s' % (eschema, rschema, teschema, x) url = self.linkto_url(entity, rschema, teschema, 'object') else: - label = 'add %s %s %s %s' % (teschema, rschema, eschema, x) + label = '%s %s %s %s' % (teschema, rschema, eschema, x) url = self.linkto_url(entity, rschema, teschema, 'subject') actions.append(self.mk_action(_(label), url)) return actions diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/views/cwproperties.py --- a/web/views/cwproperties.py Tue May 05 17:12:53 2009 +0200 +++ b/web/views/cwproperties.py Tue May 05 17:13:30 2009 +0200 @@ -50,7 +50,7 @@ def make_togglable_link(nodeid, label, cookiename): """builds a HTML link that switches the visibility & remembers it""" - action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \ + action = u"javascript: toggleVisibility('%s', '%s')" % \ (nodeid, cookiename) return u'%s' % (action, label) diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/views/editforms.py --- a/web/views/editforms.py Tue May 05 17:12:53 2009 +0200 +++ b/web/views/editforms.py Tue May 05 17:13:30 2009 +0200 @@ -18,7 +18,7 @@ from cubicweb.utils import make_uid from cubicweb.view import EntityView from cubicweb.common import tags -from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs +from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton from cubicweb.web.formrenderers import (FormRenderer, EntityFormRenderer, @@ -228,19 +228,21 @@ """fetch and render the form""" # make a copy of entity to avoid altering the entity in the # request's cache. + entity.complete() self.newentity = copy(entity) self.copying = self.newentity.eid - self.newentity.eid = None + self.initialize_varmaker() + self.newentity.eid = self.varmaker.next() self.w(u'\n' % self.req._('Please note that this is only a shallow copy')) - super(CopyFormView, self).render_form(entity) + super(CopyFormView, self).render_form(self.newentity) del self.newentity def init_form(self, form, entity): """customize your form before rendering here""" super(CopyFormView, self).init_form(form, entity) if entity.eid == self.newentity.eid: - form.form_add_hidden('__cloned_eid', self.copying, eidparam=True) + form.form_add_hidden(eid_param('__cloned_eid', entity.eid), self.copying) def submited_message(self): """return the message that will be displayed on successful edition""" diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/views/massmailing.py --- a/web/views/massmailing.py Tue May 05 17:12:53 2009 +0200 +++ b/web/views/massmailing.py Tue May 05 17:13:30 2009 +0200 @@ -13,7 +13,8 @@ from cubicweb.view import EntityView from cubicweb.web import stdmsgs from cubicweb.web.action import Action -from cubicweb.web.form import FieldsForm, FormRenderer, FormViewMixIn +from cubicweb.web.form import FieldsForm, FormViewMixIn +from cubicweb.web.formrenderers import FormRenderer from cubicweb.web.formfields import StringField from cubicweb.web.formwidgets import CheckBox, TextInput, AjaxWidget, ImgButton diff -r 04a215f2ff43 -r 7ff9f0726ee4 web/views/old_calendar.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/old_calendar.py Tue May 05 17:13:30 2009 +0200 @@ -0,0 +1,543 @@ +"""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 datetime import datetime, date, time, timedelta +#from datetime import datetime, RelativeDateTime, date, time, Sunday + +from logilab.mtconverter import html_escape + +from cubicweb.interfaces import ICalendarViews +from cubicweb.utils import date_range +from cubicweb.selectors import implements +from cubicweb.view import EntityView + +# Define some useful constants +#ONE_MONTH = RelativeDateTime(months=1) +ONE_MONTH = timedelta(days=31) +TODAY = date.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""" + __select__ = implements(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.isocalendar()[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.isocalendar()[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.isocalendar()[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.isocalendar()[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.isocalendar()[1])), + html_escape(self.build_url(rql=rql, vid=vid, year=prev1.year, week=prev1.isocalendar()[1])), + html_escape(self.build_url(rql=rql, vid=vid, year=next1.year, week=next1.isocalendar()[1])), + html_escape(self.build_url(rql=rql, vid=vid, year=next2.year, week=next2.isocalendar()[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.isocalendar()[1]) + weeklink = '%s' % (html_escape(url), + day.isocalendar()[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.isocalendar()[1]) + weeklink = '%s' % (html_escape(url), day.isocalendar()[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.isocalendar()[1]) + weeklink = '%s' % (html_escape(url), + day.isocalendar()[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.isocalendar()[1]) + weeklink = '%s' % (html_escape(url), + day.isocalendar()[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.isocalendar()[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
'