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('''
@@ -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