[gen] Calendar field: began work on the 'timeline' calendar view.

This commit is contained in:
Gaetan Delannay 2015-02-19 15:59:31 +01:00
parent 1f34156437
commit 302556192b
2 changed files with 75 additions and 72 deletions

View file

@ -14,59 +14,11 @@ class Calendar(Field):
jsFiles = {'view': ('calendar.js',)} jsFiles = {'view': ('calendar.js',)}
DateTime = DateTime DateTime = DateTime
# Month view for a calendar. Called by pxView, and directly from the UI, # Timeline view for a calendar
# via Ajax, when the user selects another month. pxViewTimeline = Px('''<p>Hello timeline</p>''')
# Month view for a calendar
pxViewMonth = Px(''' pxViewMonth = Px('''
<div var="ajaxHookId=zobj.id + field.name;
month=req['month'];
monthDayOne=field.DateTime('%s/01' % month);
today=field.DateTime('00:00');
grid=field.getMonthGrid(month);
allEventTypes=field.getEventTypes(zobj);
preComputed=field.getPreComputedInfo(zobj, monthDayOne, grid);
defaultDate=field.getDefaultDate(zobj);
defaultDateMonth=defaultDate.strftime('%Y/%m');
previousMonth=field.getSiblingMonth(month, 'previous');
nextMonth=field.getSiblingMonth(month, 'next');
mayEdit=zobj.mayEdit(field.writePermission);
objUrl=zobj.absolute_url();
startDate=field.getStartDate(zobj);
endDate=field.getEndDate(zobj);
otherCalendars=field.getOtherCalendars(zobj, preComputed)"
id=":ajaxHookId">
<script>:'var %s_maxEventLength = %d;' % \
(field.name, field.maxEventLength)</script>
<!-- Month chooser -->
<div style="margin-bottom: 5px"
var="fmt='%Y/%m/%d';
goBack=not startDate or (startDate.strftime(fmt) &lt; \
grid[0][0].strftime(fmt));
goForward=not endDate or (endDate.strftime(fmt) &gt; \
grid[-1][-1].strftime(fmt))">
<!-- Go to the previous month -->
<img class="clickable" if="goBack" src=":url('arrowLeft')"
onclick=":'askMonthView(%s,%s,%s,%s)' % \
(q(ajaxHookId),q(objUrl),q(field.name),q(previousMonth))"/>
<!-- Go back to the default date -->
<input type="button" if="goBack or goForward"
var="fmt='%Y/%m';
label=(defaultDate.strftime(fmt)==today.strftime(fmt)) and \
'today' or 'goto_source'"
value=":_(label)"
onclick=":'askMonthView(%s, %s, %s, %s)' % (q(ajaxHookId), \
q(objUrl), q(field.name), q(defaultDateMonth))"
disabled=":defaultDate.strftime(fmt)==monthDayOne.strftime(fmt)"/>
<!-- Go to the next month -->
<img class="clickable" if="goForward" src=":url('arrowRight')"
onclick=":'askMonthView(%s, %s, %s, %s)' % (q(ajaxHookId), \
q(objUrl), q(field.name), q(nextMonth))"/>
<span>:_('month_%s' % monthDayOne.aMonth())</span>
<span>:month.split('/')[0]</span>
</div>
<!-- Calendar month view -->
<table cellpadding="0" cellspacing="0" width="100%" class="list" <table cellpadding="0" cellspacing="0" width="100%" class="list"
style="font-size: 95%" style="font-size: 95%"
var="rowHeight=int(field.height/float(len(grid)))"> var="rowHeight=int(field.height/float(len(grid)))">
@ -104,7 +56,7 @@ class Calendar(Field):
<img class="clickable" style="visibility:hidden" <img class="clickable" style="visibility:hidden"
var="info=field.getApplicableEventsTypesAt(zobj, date, \ var="info=field.getApplicableEventsTypesAt(zobj, date, \
allEventTypes, preComputed, True)" allEventTypes, preComputed, True)"
if="info.eventTypes" src=":url('plus')" if="info and info.eventTypes" src=":url('plus')"
onclick=":'openEventPopup(%s, %s, %s, null, %s, %s)' % \ onclick=":'openEventPopup(%s, %s, %s, null, %s, %s)' % \
(q('new'), q(field.name), q(dayString), q(info.eventTypes),\ (q('new'), q(field.name), q(dayString), q(info.eventTypes),\
q(info.message))"/> q(info.message))"/>
@ -134,7 +86,8 @@ class Calendar(Field):
</table> </table>
<!-- Popup for creating a calendar event --> <!-- Popup for creating a calendar event -->
<div var="prefix='%s_newEvent' % field.name; <div if="allEventTypes"
var="prefix='%s_newEvent' % field.name;
popupId=prefix + 'Popup'" popupId=prefix + 'Popup'"
id=":popupId" class="popup" align="center"> id=":popupId" class="popup" align="center">
<form id=":prefix + 'Form'" method="post"> <form id=":prefix + 'Form'" method="post">
@ -198,13 +151,59 @@ class Calendar(Field):
<input type="button" value=":_('no')" <input type="button" value=":_('no')"
onclick=":'closePopup(%s)' % q(popupId)"/> onclick=":'closePopup(%s)' % q(popupId)"/>
</form> </form>
</div> </div>''')
</div>''')
pxView = pxCell = Px(''' pxView = pxCell = Px('''
<x var="defaultDate=field.getDefaultDate(zobj); <div var="defaultDate=field.getDefaultDate(zobj);
x=req.set('month', defaultDate.strftime('%Y/%m')); defaultDateMonth=defaultDate.strftime('%Y/%m');
x=req.set('fieldName', field.name)">:field.pxViewMonth</x>''') ajaxHookId=zobj.id + field.name;
month=req.get('month', defaultDate.strftime('%Y/%m'));
monthDayOne=field.DateTime('%s/01' % month);
render=req.get('render', field.render);
today=field.DateTime('00:00');
grid=field.getGrid(month, render);
allEventTypes=field.getEventTypes(zobj);
preComputed=field.getPreComputedInfo(zobj, monthDayOne, grid);
previousMonth=field.getSiblingMonth(month, 'previous');
nextMonth=field.getSiblingMonth(month, 'next');
mayEdit=zobj.mayEdit(field.writePermission);
objUrl=zobj.absolute_url();
startDate=field.getStartDate(zobj);
endDate=field.getEndDate(zobj);
otherCalendars=field.getOtherCalendars(zobj, preComputed)"
id=":ajaxHookId">
<script>:'var %s_maxEventLength = %d;' % \
(field.name, field.maxEventLength)</script>
<!-- Month chooser -->
<div style="margin-bottom: 5px"
var="fmt='%Y/%m/%d';
goBack=not startDate or (startDate.strftime(fmt) &lt; \
grid[0][0].strftime(fmt));
goForward=not endDate or (endDate.strftime(fmt) &gt; \
grid[-1][-1].strftime(fmt))">
<!-- Go to the previous month -->
<img class="clickable" if="goBack" src=":url('arrowLeft')"
onclick=":'askCalendar(%s,%s,%s,%s,%s)' % (q(ajaxHookId), \
q(objUrl), q(render), q(field.name), q(previousMonth))"/>
<!-- Go back to the default date -->
<input type="button" if="goBack or goForward"
var="fmt='%Y/%m';
label=(defaultDate.strftime(fmt)==today.strftime(fmt)) and \
'today' or 'goto_source'"
value=":_(label)"
onclick=":'askCalendar(%s,%s,%s,%s,%s)' % (q(ajaxHookId), \
q(objUrl), q(render), q(field.name), q(defaultDateMonth))"
disabled=":defaultDate.strftime(fmt)==monthDayOne.strftime(fmt)"/>
<!-- Go to the next month -->
<img class="clickable" if="goForward" src=":url('arrowRight')"
onclick=":'askCalendar(%s,%s,%s,%s,%s)' % (q(ajaxHookId), \
q(objUrl), q(render), q(field.name), q(nextMonth))"/>
<span>:_('month_%s' % monthDayOne.aMonth())</span>
<span>:month.split('/')[0]</span>
</div>
<x>:getattr(field, 'pxView%s' % render.capitalize())</x>
</div>''')
pxEdit = pxSearch = '' pxEdit = pxSearch = ''
@ -213,7 +212,7 @@ class Calendar(Field):
layouts=None, move=0, specificReadPermission=False, layouts=None, move=0, specificReadPermission=False,
specificWritePermission=False, width=None, height=300, specificWritePermission=False, width=None, height=300,
colspan=1, master=None, masterValue=None, focus=False, colspan=1, master=None, masterValue=None, focus=False,
mapping=None, label=None, maxEventLength=50, mapping=None, label=None, maxEventLength=50, render='month',
otherCalendars=None, additionalInfo=None, startDate=None, otherCalendars=None, additionalInfo=None, startDate=None,
endDate=None, defaultDate=None, preCompute=None, endDate=None, defaultDate=None, preCompute=None,
applicableEvents=None, view=None, xml=None, delete=True): applicableEvents=None, view=None, xml=None, delete=True):
@ -232,12 +231,17 @@ class Calendar(Field):
# of this event as it must be shown to the user. # of this event as it must be shown to the user.
self.eventTypes = eventTypes self.eventTypes = eventTypes
self.eventNameMethod = eventNameMethod self.eventNameMethod = eventNameMethod
if (type(eventTypes) == types.FunctionType) and not eventNameMethod: if callable(eventTypes) and not eventNameMethod:
raise Exception("When param 'eventTypes' is a method, you must " \ raise Exception("When param 'eventTypes' is a method, you must " \
"give another method in param 'eventNameMethod'.") "give another method in param 'eventNameMethod'.")
# It is not possible to create events that span more days than # It is not possible to create events that span more days than
# maxEventLength. # maxEventLength.
self.maxEventLength = maxEventLength self.maxEventLength = maxEventLength
# Various render modes exist. Default is the classical "month" view.
# It can also be "timeline": in this case, on the x axis, we have one
# column per day, and on the y axis, we have one row per calendar (this
# one and others as specified in "otherCalendars", see below).
self.render = render
# When displaying a given month for this agenda, one may want to # When displaying a given month for this agenda, one may want to
# pre-compute, once for the whole month, some information that will then # pre-compute, once for the whole month, some information that will then
# be given as arg for other methods specified in subsequent parameters. # be given as arg for other methods specified in subsequent parameters.
@ -325,10 +329,10 @@ class Calendar(Field):
res.append(obj.translate('day_%s%s' % (day, suffix))) res.append(obj.translate('day_%s%s' % (day, suffix)))
return res return res
def getMonthGrid(self, month): def getGrid(self, month, render):
'''Creates a list of lists of DateTime objects representing the calendar '''Creates a list of lists of DateTime objects representing the calendar
grid to render for a given p_month.''' grid to render for a given p_month.'''
# Month is a string "YYYY/mm". # Month is a string "YYYY/mm"
currentDay = DateTime('%s/01 UTC' % month) currentDay = DateTime('%s/01 UTC' % month)
currentMonth = currentDay.month() currentMonth = currentDay.month()
res = [[]] res = [[]]
@ -379,10 +383,8 @@ class Calendar(Field):
def getEventTypes(self, obj): def getEventTypes(self, obj):
'''Returns the (dynamic or static) event types as defined in '''Returns the (dynamic or static) event types as defined in
self.eventTypes.''' self.eventTypes.'''
if type(self.eventTypes) == types.FunctionType: if callable(self.eventTypes): return self.eventTypes(obj.appy())
return self.eventTypes(obj.appy()) return self.eventTypes
else:
return self.eventTypes
def getApplicableEventsTypesAt(self, obj, date, allEventTypes, preComputed, def getApplicableEventsTypesAt(self, obj, date, allEventTypes, preComputed,
forBrowser=False): forBrowser=False):
@ -393,6 +395,7 @@ class Calendar(Field):
contains a message explaining those event types are contains a message explaining those event types are
not applicable. not applicable.
''' '''
if not allEventTypes: return # There may be no event type at all
if not self.applicableEvents: if not self.applicableEvents:
eventTypes = allEventTypes eventTypes = allEventTypes
message = None message = None

View file

@ -8,10 +8,10 @@ function toggleVisibility(node, nodeType){
} }
} }
function askMonthView(hookId, objectUrl, fieldName, month) { function askCalendar(hookId, objectUrl, render, fieldName, month) {
// Sends an Ajax request for getting the view month of a calendar field // Sends an Ajax request for getting the calendar, at p_month
var params = {'month': month}; var params = {'month': month, 'render': render};
askAjaxChunk(hookId, 'GET', objectUrl, fieldName+':pxViewMonth', params); askAjaxChunk(hookId, 'GET', objectUrl, fieldName+':pxView', params);
} }
function openEventPopup(action, fieldName, day, spansDays, function openEventPopup(action, fieldName, day, spansDays,
@ -93,5 +93,5 @@ function triggerCalendarEvent(action, hookId, fieldName, objectUrl,
params[elems[i].name] = elems[i].value; params[elems[i].name] = elems[i].value;
} }
closePopup(prefix + 'Popup'); closePopup(prefix + 'Popup');
askAjaxChunk(hookId, 'POST', objectUrl, fieldName+':pxViewMonth', params); askAjaxChunk(hookId, 'POST', objectUrl, fieldName+':pxView', params);
} }