equal
deleted
inserted
replaced
27 _("friday"), _("saturday"), _("sunday")) |
27 _("friday"), _("saturday"), _("sunday")) |
28 MONTHNAMES = ( _('january'), _('february'), _('march'), _('april'), _('may'), |
28 MONTHNAMES = ( _('january'), _('february'), _('march'), _('april'), _('may'), |
29 _('june'), _('july'), _('august'), _('september'), _('october'), |
29 _('june'), _('july'), _('august'), _('september'), _('october'), |
30 _('november'), _('december') |
30 _('november'), _('december') |
31 ) |
31 ) |
32 |
32 |
33 # Calendar views ############################################################## |
33 # Calendar views ############################################################## |
34 |
34 |
35 |
35 |
36 class iCalView(EntityView): |
36 class iCalView(EntityView): |
37 """A calendar view that generates a iCalendar file (RFC 2445) |
37 """A calendar view that generates a iCalendar file (RFC 2445) |
97 if dates: |
97 if dates: |
98 if task.start and task.stop: |
98 if task.start and task.stop: |
99 self.w('<br/>' % self.req._('from %(date)s' % {'date': self.format_date(task.start)})) |
99 self.w('<br/>' % self.req._('from %(date)s' % {'date': self.format_date(task.start)})) |
100 self.w('<br/>' % self.req._('to %(date)s' % {'date': self.format_date(task.stop)})) |
100 self.w('<br/>' % self.req._('to %(date)s' % {'date': self.format_date(task.stop)})) |
101 self.w('<br/>to %s'%self.format_date(task.stop)) |
101 self.w('<br/>to %s'%self.format_date(task.stop)) |
102 |
102 |
103 class CalendarLargeItemView(CalendarItemView): |
103 class CalendarLargeItemView(CalendarItemView): |
104 id = 'calendarlargeitem' |
104 id = 'calendarlargeitem' |
105 |
105 |
106 |
106 |
107 class _TaskEntry(object): |
107 class _TaskEntry(object): |
108 def __init__(self, task, color, index=0): |
108 def __init__(self, task, color, index=0): |
109 self.task = task |
109 self.task = task |
110 self.color = color |
110 self.color = color |
111 self.index = index |
111 self.index = index |
114 def in_working_hours(self): |
114 def in_working_hours(self): |
115 """predicate returning True is the task is in working hours""" |
115 """predicate returning True is the task is in working hours""" |
116 if self.task.start.hour > 7 and self.task.stop.hour < 20: |
116 if self.task.start.hour > 7 and self.task.stop.hour < 20: |
117 return True |
117 return True |
118 return False |
118 return False |
119 |
119 |
120 def is_one_day_task(self): |
120 def is_one_day_task(self): |
121 task = self.task |
121 task = self.task |
122 return task.start and task.stop and task.start.isocalendar() == task.stop.isocalendar() |
122 return task.start and task.stop and task.start.isocalendar() == task.stop.isocalendar() |
123 |
123 |
|
124 |
124 class OneMonthCal(EntityView): |
125 class OneMonthCal(EntityView): |
125 """At some point, this view will probably replace ampm calendars""" |
126 """At some point, this view will probably replace ampm calendars""" |
126 id = 'onemonthcal' |
127 id = 'onemonthcal' |
127 __select__ = implements(ICalendarable) |
128 __select__ = implements(ICalendarable) |
128 need_navigation = False |
129 need_navigation = False |
177 else: |
178 else: |
178 the_dates = date_range(max(tstart, firstday), |
179 the_dates = date_range(max(tstart, firstday), |
179 min(tstop, lastday)) |
180 min(tstop, lastday)) |
180 if not the_dates: |
181 if not the_dates: |
181 continue |
182 continue |
182 |
183 |
183 for d in the_dates: |
184 for d in the_dates: |
184 d_tasks = dates.setdefault((d.year, d.month, d.day), {}) |
185 d_tasks = dates.setdefault((d.year, d.month, d.day), {}) |
185 t_users = d_tasks.setdefault(task, set()) |
186 t_users = d_tasks.setdefault(task, set()) |
186 t_users.add( user ) |
187 t_users.add( user ) |
187 if len(d_tasks) > task_max: |
188 if len(d_tasks) > task_max: |
240 curdate.year, html_escape(nextlink))) |
241 curdate.year, html_escape(nextlink))) |
241 |
242 |
242 # output header |
243 # output header |
243 self.w(u'<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>' % |
244 self.w(u'<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>' % |
244 tuple(self.req._(day) for day in WEEKDAYS)) |
245 tuple(self.req._(day) for day in WEEKDAYS)) |
245 |
246 |
246 # build calendar |
247 # build calendar |
247 for mdate, task_rows in zip(month_dates, days): |
248 for mdate, task_rows in zip(month_dates, days): |
248 if mdate.weekday() == 0: |
249 if mdate.weekday() == 0: |
249 self.w(u'<tr>') |
250 self.w(u'<tr>') |
250 self._build_calendar_cell(mdate, task_rows, curdate) |
251 self._build_calendar_cell(mdate, task_rows, curdate) |
270 if celldate == date.today(): |
271 if celldate == date.today(): |
271 classes += " today" |
272 classes += " today" |
272 self.w(u'<td class="cell%s">' % classes) |
273 self.w(u'<td class="cell%s">' % classes) |
273 self.w(u'<div class="calCellTitle%s">' % classes) |
274 self.w(u'<div class="calCellTitle%s">' % classes) |
274 self.w(u'<div class="day">%s</div>' % celldate.day) |
275 self.w(u'<div class="day">%s</div>' % celldate.day) |
275 |
276 |
276 if len(self.rset.column_types(0)) == 1: |
277 if len(self.rset.column_types(0)) == 1: |
277 etype = list(self.rset.column_types(0))[0] |
278 etype = list(self.rset.column_types(0))[0] |
278 url = self.build_url(vid='creation', etype=etype, |
279 url = self.build_url(vid='creation', etype=etype, |
279 schedule=True, |
280 schedule=True, |
280 start=self.format_date(celldate), stop=self.format_date(celldate), |
281 start=self.format_date(celldate), stop=self.format_date(celldate), |
312 """At some point, this view will probably replace ampm calendars""" |
313 """At some point, this view will probably replace ampm calendars""" |
313 id = 'oneweekcal' |
314 id = 'oneweekcal' |
314 __select__ = implements(ICalendarable) |
315 __select__ = implements(ICalendarable) |
315 need_navigation = False |
316 need_navigation = False |
316 title = _('one week') |
317 title = _('one week') |
317 |
318 |
318 def call(self): |
319 def call(self): |
319 self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.calendar.js') ) |
320 self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.calendar.js') ) |
320 self.req.add_css('cubicweb.calendar.css') |
321 self.req.add_css('cubicweb.calendar.css') |
321 # XXX: restrict directly with RQL |
322 # XXX: restrict directly with RQL |
322 _today = datetime.today() |
323 _today = datetime.today() |
325 else: |
326 else: |
326 year = _today.year |
327 year = _today.year |
327 if 'week' in self.req.form: |
328 if 'week' in self.req.form: |
328 week = int(self.req.form['week']) |
329 week = int(self.req.form['week']) |
329 else: |
330 else: |
330 week = _today.isocalendar()[1] |
331 week = _today.isocalendar()[1] |
331 # week - 1 since we get week number > 0 while we want it to start from 0 |
332 # week - 1 since we get week number > 0 while we want it to start from 0 |
332 first_day_of_week = todate(strptime('%s-%s-1' % (year, week - 1), '%Y-%U-%w')) |
333 first_day_of_week = todate(strptime('%s-%s-1' % (year, week - 1), '%Y-%U-%w')) |
333 lastday = first_day_of_week + timedelta(6) |
334 lastday = first_day_of_week + timedelta(6) |
334 firstday = first_day_of_week |
335 firstday = first_day_of_week |
335 dates = [[] for i in range(7)] |
336 dates = [[] for i in range(7)] |
357 if tstart and tstop: |
358 if tstart and tstop: |
358 the_dates = date_range(max(tstart, firstday), |
359 the_dates = date_range(max(tstart, firstday), |
359 min(tstop, lastday)) |
360 min(tstop, lastday)) |
360 if not the_dates: |
361 if not the_dates: |
361 continue |
362 continue |
362 |
363 |
363 if task not in task_colors: |
364 if task not in task_colors: |
364 task_colors[task] = colors[next_color_index] |
365 task_colors[task] = colors[next_color_index] |
365 next_color_index = (next_color_index+1) % len(colors) |
366 next_color_index = (next_color_index+1) % len(colors) |
366 |
367 |
367 for d in the_dates: |
368 for d in the_dates: |
368 day = d.weekday() |
369 day = d.weekday() |
369 task_descr = _TaskEntry(task, task_colors[task]) |
370 task_descr = _TaskEntry(task, task_colors[task]) |
370 dates[day].append(task_descr) |
371 dates[day].append(task_descr) |
371 |
372 |
372 self.w(u'<div id="oneweekcalid">') |
373 self.w(u'<div id="oneweekcalid">') |
373 # build schedule |
374 # build schedule |
374 self.w(u'<table class="omcalendar" id="week">') |
375 self.w(u'<table class="omcalendar" id="week">') |
375 prevlink, nextlink = self._prevnext_links(first_day_of_week) # XXX |
376 prevlink, nextlink = self._prevnext_links(first_day_of_week) # XXX |
376 self.w(u'<tr><th class="transparent"></th>') |
377 self.w(u'<tr><th class="transparent"></th>') |
389 if wdate.isocalendar() == _today.isocalendar(): |
390 if wdate.isocalendar() == _today.isocalendar(): |
390 self.w(u'<th class="today">%s<br/>%s</th>' % (self.req._(day), self.format_date(wdate))) |
391 self.w(u'<th class="today">%s<br/>%s</th>' % (self.req._(day), self.format_date(wdate))) |
391 else: |
392 else: |
392 self.w(u'<th>%s<br/>%s</th>' % (self.req._(day), self.format_date(wdate))) |
393 self.w(u'<th>%s<br/>%s</th>' % (self.req._(day), self.format_date(wdate))) |
393 self.w(u'</tr>') |
394 self.w(u'</tr>') |
394 |
395 |
395 # build week calendar |
396 # build week calendar |
396 self.w(u'<tr>') |
397 self.w(u'<tr>') |
397 self.w(u'<td style="width:5em;">') # column for hours |
398 self.w(u'<td style="width:5em;">') # column for hours |
398 extra = "" |
399 extra = "" |
399 for h in range(8, 20): |
400 for h in range(8, 20): |
400 self.w(u'<div class="hour" %s>'%extra) |
401 self.w(u'<div class="hour" %s>'%extra) |
401 self.w(u'%02d:00'%h) |
402 self.w(u'%02d:00'%h) |
402 self.w(u'</div>') |
403 self.w(u'</div>') |
403 self.w(u'</td>') |
404 self.w(u'</td>') |
404 |
405 |
405 for i, day in enumerate(WEEKDAYS): |
406 for i, day in enumerate(WEEKDAYS): |
406 wdate = first_day_of_week + timedelta(i) |
407 wdate = first_day_of_week + timedelta(i) |
407 classes = "" |
408 classes = "" |
408 if wdate.isocalendar() == _today.isocalendar(): |
409 if wdate.isocalendar() == _today.isocalendar(): |
409 classes = " today" |
410 classes = " today" |
421 else: |
422 else: |
422 extra = "" |
423 extra = "" |
423 self.w(u'<div class="columndiv"%s>'% extra) |
424 self.w(u'<div class="columndiv"%s>'% extra) |
424 for h in range(8, 20): |
425 for h in range(8, 20): |
425 self.w(u'<div class="hourline" style="top:%sex;">'%((h-7)*8)) |
426 self.w(u'<div class="hourline" style="top:%sex;">'%((h-7)*8)) |
426 self.w(u'</div>') |
427 self.w(u'</div>') |
427 if dates[i]: |
428 if dates[i]: |
428 self._build_calendar_cell(wdate, dates[i]) |
429 self._build_calendar_cell(wdate, dates[i]) |
429 self.w(u'</div>') |
430 self.w(u'</div>') |
430 self.w(u'</td>') |
431 self.w(u'</td>') |
431 self.w(u'</tr>') |
432 self.w(u'</tr>') |
432 self.w(u'</table></div>') |
433 self.w(u'</table></div>') |
433 self.w(u'<div id="coord"></div>') |
434 self.w(u'<div id="coord"></div>') |
434 self.w(u'<div id="debug"> </div>') |
435 self.w(u'<div id="debug"> </div>') |
435 |
436 |
436 def _build_calendar_cell(self, date, task_descrs): |
437 def _build_calendar_cell(self, date, task_descrs): |
437 inday_tasks = [t for t in task_descrs if t.is_one_day_task() and t.in_working_hours()] |
438 inday_tasks = [t for t in task_descrs if t.is_one_day_task() and t.in_working_hours()] |
438 wholeday_tasks = [t for t in task_descrs if not t.is_one_day_task()] |
439 wholeday_tasks = [t for t in task_descrs if not t.is_one_day_task()] |
439 inday_tasks.sort(key=lambda t:t.task.start) |
440 inday_tasks.sort(key=lambda t:t.task.start) |
440 sorted_tasks = [] |
441 sorted_tasks = [] |
472 if task.stop: |
473 if task.stop: |
473 if date < todate(task.stop) < date + ONEDAY: |
474 if date < todate(task.stop) < date + ONEDAY: |
474 stop_hour = min(20, task.stop.hour) |
475 stop_hour = min(20, task.stop.hour) |
475 if stop_hour < 20: |
476 if stop_hour < 20: |
476 stop_min = task.stop.minute |
477 stop_min = task.stop.minute |
477 |
478 |
478 height = 100.0*(stop_hour+stop_min/60.0-start_hour-start_min/60.0)/(20-8) |
479 height = 100.0*(stop_hour+stop_min/60.0-start_hour-start_min/60.0)/(20-8) |
479 top = 100.0*(start_hour+start_min/60.0-8)/(20-8) |
480 top = 100.0*(start_hour+start_min/60.0-8)/(20-8) |
480 left = width*task_desc.index |
481 left = width*task_desc.index |
481 style = "height: %s%%; width: %s%%; top: %s%%; left: %s%%; " % \ |
482 style = "height: %s%%; width: %s%%; top: %s%%; left: %s%%; " % \ |
482 (height, width, top, left) |
483 (height, width, top, left) |
502 self.w(u'end') |
503 self.w(u'end') |
503 self.w(u'</div>') |
504 self.w(u'</div>') |
504 self.w(u'</div>') |
505 self.w(u'</div>') |
505 self.w(u'</div>') |
506 self.w(u'</div>') |
506 |
507 |
507 |
508 |
508 def _prevnext_links(self, curdate): |
509 def _prevnext_links(self, curdate): |
509 prevdate = curdate - timedelta(7) |
510 prevdate = curdate - timedelta(7) |
510 nextdate = curdate + timedelta(7) |
511 nextdate = curdate + timedelta(7) |
511 rql = self.rset.printable_rql() |
512 rql = self.rset.printable_rql() |
512 prevlink = ajax_replace_url('oneweekcalid', rql, 'oneweekcal', |
513 prevlink = ajax_replace_url('oneweekcalid', rql, 'oneweekcal', |