From 85007ced67fbdec20b9dbd659737b4cfff63be79 Mon Sep 17 00:00:00 2001 From: Gaetan Delannay Date: Mon, 2 Mar 2015 12:19:19 +0100 Subject: [PATCH] [gen] Calendar widget: more work on timeslots. --- fields/calendar.py | 86 ++++++++++++++++++++++++++++++---------------- gen/ui/calendar.js | 65 +++++++++++++++++++++-------------- 2 files changed, 96 insertions(+), 55 deletions(-) diff --git a/fields/calendar.py b/fields/calendar.py index 4239947..c27e42c 100644 --- a/fields/calendar.py +++ b/fields/calendar.py @@ -81,6 +81,11 @@ class Event(Persistent): if self.timeslot != 'main': res += ' ' + self.timeslot return res + def sameAs(self, other): + '''Is p_self the same as p_other?''' + return (self.eventType == other.eventType) and \ + (self.timeslot == other.timeslot) + # ------------------------------------------------------------------------------ class Calendar(Field): '''This field allows to produce an agenda (monthly view) and view/edit @@ -182,10 +187,9 @@ class Calendar(Field): :field.pxTimelineLegend''') # Popup for adding an event in the month view - pxAddEvent = Px(''' + pxAddPopup = Px(''' - -
- :_('event_span') - -
-
+
+ :_('event_span') + +
@@ -299,18 +301,20 @@ class Calendar(Field): + var2="freeSlots=field.getFreeSlotsAt(date, events, slotIds,\ + slotIdsStr, True)" + onclick=":'openEventPopup(%s,%s,%s,null,null,%s,%s,%s)' % \ + (q('new'), q(field.name), q(dayString), q(info.eventTypes), \ + q(info.message), q(freeSlots))"/> + onclick=":'openEventPopup(%s,%s,%s,%s,%s)' % (q('del'), \ + q(field.name), q(dayString), q('main'), q(spansDays))"/>
@@ -318,8 +322,8 @@ class Calendar(Field): + onclick=":'openEventPopup(%s,%s,%s,%s)' % (q('del'), \ + q(field.name), q(dayString), q(event.timeslot))"/>
@@ -339,7 +343,7 @@ class Calendar(Field): - :field.pxAddEvent:field.pxDelEvent''') + :field.pxAddPopup:field.pxDelPopup''') pxView = pxCell = Px('''
@@ -658,8 +665,8 @@ class Calendar(Field): tooLate = endDate and not tooEarly and (date > endDate) return not tooEarly and not tooLate - def getApplicableEventsTypesAt(self, obj, date, eventTypes, preComputed, - forBrowser=False): + def getApplicableEventTypesAt(self, obj, date, eventTypes, preComputed, + forBrowser=False): '''Returns the event types that are applicable at a given p_date. More precisely, it returns an object with 2 attributes: * "events" is the list of applicable event types; @@ -681,6 +688,20 @@ class Calendar(Field): if not res.message: res.message = '' return res + def getFreeSlotsAt(self, date, events, slotIds, slotIdsStr, + forBrowser=False): + '''Gets the free timeslots in this calendar for some p_date. As a + precondition, we know that the day is not full (so timeslot "main" + cannot be taken). p_events are those already defined at p_date. + p_slotIds is the precomputed list of timeslot ids.''' + if not events: return forBrowser and slotIdsStr or slotIds + # Remove any taken slot + res = slotIds[1:] # "main" cannot be chosen: p_events is not empty + for event in events: res.remove(event.timeslot) + # Return the result + if not forBrowser: return res + return ','.join(res) + def getEventsAt(self, obj, date): '''Returns the list of events that exist at some p_date (=day).''' obj = obj.o # Ensure p_obj is not a wrapper. @@ -808,13 +829,18 @@ class Calendar(Field): i -= 1 return res - def hasEventsAt(self, obj, date, otherEvents): - '''Returns True if, at p_date, an event is found of the same type as - p_otherEvents.''' - if not otherEvents: return - events = self.getEventsAt(obj, date) + def hasEventsAt(self, obj, date, events): + '''Returns True if, at p_date, events are exactly of the same type as + p_events.''' if not events: return - return events[0].eventType == otherEvents[0].eventType + others = self.getEventsAt(obj, date) + if not others: return + if len(events) != len(others): return + i = 0 + while i < len(events): + if not events[i].sameAs(others[i]): return + i += 1 + return True def getOtherEventsAt(self, obj, date, others, eventNames, render, colors): '''Gets events that are defined in p_others at some p_date. If p_single @@ -925,12 +951,12 @@ class Calendar(Field): # Create and store the event events.append(Event(eventType, timeslot)) # Sort events in the order of timeslots - timeslots = [timeslot.id for timeslot in self.timeslots] + timeslots = [slot.id for slot in self.timeslots] if len(events) > 1: events.data.sort(key=lambda e: timeslots.index(e.timeslot)) events._p_changed = 1 # Span the event on the successive days if required - if handleEventSpan and eventSpan and (timeslot != 'main'): + if handleEventSpan and eventSpan: nbOfDays = min(int(eventSpan), self.maxEventLength) for i in range(nbOfDays): date = date + 1 diff --git a/gen/ui/calendar.js b/gen/ui/calendar.js index df0e739..aab9913 100644 --- a/gen/ui/calendar.js +++ b/gen/ui/calendar.js @@ -14,8 +14,40 @@ function askCalendar(hookId, objectUrl, render, fieldName, month) { askAjaxChunk(hookId, 'GET', objectUrl, fieldName+':pxView', params); } +function enableOptions(select, enabled, selectFirst, message){ + /* This function disables, in p_select, all options that are not in p_enabled. + p_enabled is a string containing a comma-separated list of option names. + If p_selectFirst is True, the first option from p_enabled will be selected + by default. p_message will be shown (as "title") for disabled options. */ + // Get p_enabled as a dict + var l = enabled.split(','); + var d = {}; + for (var i=0; i < l.length; i++) d[l[i]] = true; + // Remember if we have already selected the first enabled option + var isSelected = false; + var options = select.options; + // Disable options not being p_enabled + for (var i=0; i