[gen] Calendar field: more work on multi-events and validation within timeline calendars.
This commit is contained in:
parent
93b2740906
commit
bcf2952980
|
@ -93,6 +93,10 @@ class Other:
|
||||||
info.name = eventNames[eventType]
|
info.name = eventNames[eventType]
|
||||||
res.append(info)
|
res.append(info)
|
||||||
|
|
||||||
|
def mayValidate(self):
|
||||||
|
'''Is validation enabled for this other calendar?'''
|
||||||
|
return self.field.mayValidate(self.obj)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
class Event(Persistent):
|
class Event(Persistent):
|
||||||
'''An event as will be stored in the database'''
|
'''An event as will be stored in the database'''
|
||||||
|
@ -159,19 +163,15 @@ class Calendar(Field):
|
||||||
# Legend for a timeline calendar
|
# Legend for a timeline calendar
|
||||||
pxTimelineLegend = Px('''
|
pxTimelineLegend = Px('''
|
||||||
<table align="center" class="discreet"
|
<table align="center" class="discreet"
|
||||||
var="legendTypes=[et for et in allEventTypes if et in colors]">
|
var="items=field.getLegendItems(allEventTypes, allEventNames, \
|
||||||
<tr for="row in field.splitList(legendTypes, 4)">
|
colors, url, _)">
|
||||||
<x for="eventType in row">
|
<tr for="row in field.splitList(items, 4)">
|
||||||
<td> <!-- A colored cell (as mono-cell sub-table) -->
|
<x for="item in row">
|
||||||
<table>
|
<td><table> <!-- A colored cell (as mono-cell sub-table) -->
|
||||||
<tr height="9px">
|
<tr height="9px"><td width="9px" style=":item.style"> </td></tr>
|
||||||
<td width="9px"
|
</table></td>
|
||||||
style=":'background-color: %s' % colors[eventType]"> </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
<!-- The event name -->
|
<!-- The event name -->
|
||||||
<td>:allEventNames[eventType]</td>
|
<td width="115px">:item.name</td>
|
||||||
</x>
|
</x>
|
||||||
</tr>
|
</tr>
|
||||||
</table>''')
|
</table>''')
|
||||||
|
@ -201,7 +201,8 @@ class Calendar(Field):
|
||||||
<!-- Other calendars -->
|
<!-- Other calendars -->
|
||||||
<x for="otherGroup in others">
|
<x for="otherGroup in others">
|
||||||
<tr for="other in otherGroup"
|
<tr for="other in otherGroup"
|
||||||
var2="tlName=field.getTimelineName(other)">
|
var2="tlName=field.getTimelineName(other);
|
||||||
|
mayValidate=mayValidate and other.mayValidate()">
|
||||||
<td class="tlLeft">::tlName</td>
|
<td class="tlLeft">::tlName</td>
|
||||||
<!-- A cell in this other calendar -->
|
<!-- A cell in this other calendar -->
|
||||||
<x for="date in grid"
|
<x for="date in grid"
|
||||||
|
@ -211,7 +212,7 @@ class Calendar(Field):
|
||||||
var2="events=field.getOtherEventsAt(zobj, date, other, \
|
var2="events=field.getOtherEventsAt(zobj, date, other, \
|
||||||
allEventNames, render, colors)"
|
allEventNames, render, colors)"
|
||||||
style=":field.getCellStyle(zobj, date, render, \
|
style=":field.getCellStyle(zobj, date, render, \
|
||||||
events)">::field.getTimelineCell(events)</td>
|
events)">::field.getTimelineCell(date, other, events, mayValidate)</td>
|
||||||
</x>
|
</x>
|
||||||
<td class="tlRight">::tlName</td>
|
<td class="tlRight">::tlName</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -682,11 +683,63 @@ class Calendar(Field):
|
||||||
return '<a href="%s">%s</a>' % (other.obj.url, other.obj.title)
|
return '<a href="%s">%s</a>' % (other.obj.url, other.obj.title)
|
||||||
return self.timelineName(self, other)
|
return self.timelineName(self, other)
|
||||||
|
|
||||||
def getTimelineCell(self, events):
|
def getTimelineCell(self, date, other, events, mayValidate):
|
||||||
'''Gets the content of a cell in a timeline calendar.'''
|
'''Gets the content of a cell in a timeline calendar'''
|
||||||
# Currently a single event is allowed
|
if events and mayValidate:
|
||||||
if not events or not events[0].symbol: return ''
|
# If at least one event from p_events is in the validation schema,
|
||||||
return events[0].symbol
|
# propose a unique checkbox, that will allow to validate or not all
|
||||||
|
# validable events at p_date.
|
||||||
|
for info in events:
|
||||||
|
if info.event.eventType in other.field.validation.schema:
|
||||||
|
return '<input type="checkbox" checked="checked" class="smallbox"/>'
|
||||||
|
return ''
|
||||||
|
# When there are multiple events, a background image is already shown
|
||||||
|
if not events or (len(events) > 1): return ''
|
||||||
|
# A single event: if not colored, show a symbol
|
||||||
|
return events[0].symbol or ''
|
||||||
|
|
||||||
|
def getLegendItems(self, allEventTypes, allEventNames, colors, url, _):
|
||||||
|
'''Gets information needed to produce the legend for a timeline.'''
|
||||||
|
# Produce one legend item by event type shown and colored
|
||||||
|
res = []
|
||||||
|
for eventType in allEventTypes:
|
||||||
|
if eventType not in colors: continue
|
||||||
|
res.append(Object(name=allEventNames[eventType],
|
||||||
|
style='background-color: %s' % colors[eventType]))
|
||||||
|
# Add the background indicating that several events are hidden behind
|
||||||
|
# the timeline cell
|
||||||
|
res.append(Object(name=_('several_events'),
|
||||||
|
style=url('angled', bg=True)))
|
||||||
|
return res
|
||||||
|
|
||||||
|
def getTimelineMonths(self, grid, obj):
|
||||||
|
'''Given the p_grid of dates, this method returns the list of
|
||||||
|
corresponding months.'''
|
||||||
|
res = []
|
||||||
|
for date in grid:
|
||||||
|
if not res:
|
||||||
|
# Get the month correspoding to the first day in the grid
|
||||||
|
m = Object(month=date.aMonth(), colspan=1, year=date.year())
|
||||||
|
res.append(m)
|
||||||
|
else:
|
||||||
|
# Augment current month' colspan or create a new one
|
||||||
|
current = res[-1]
|
||||||
|
if date.aMonth() == current.month:
|
||||||
|
current.colspan += 1
|
||||||
|
else:
|
||||||
|
m = Object(month=date.aMonth(), colspan=1, year=date.year())
|
||||||
|
res.append(m)
|
||||||
|
# Replace month short names by translated names whose format may vary
|
||||||
|
# according to colspan (a higher colspan allow us to produce a longer
|
||||||
|
# month name).
|
||||||
|
for m in res:
|
||||||
|
text = '%s %d' % (obj.translate('month_%s' % m.month), m.year)
|
||||||
|
if m.colspan < 6:
|
||||||
|
# Short version: a single letter with an acronym
|
||||||
|
m.month = '<acronym title="%s">%s</acronym>' % (text, text[0])
|
||||||
|
else:
|
||||||
|
m.month = text
|
||||||
|
return res
|
||||||
|
|
||||||
def getAdditionalInfoAt(self, obj, date, preComputed):
|
def getAdditionalInfoAt(self, obj, date, preComputed):
|
||||||
'''If the user has specified a method in self.additionalInfo, we call
|
'''If the user has specified a method in self.additionalInfo, we call
|
||||||
|
@ -1144,7 +1197,13 @@ class Calendar(Field):
|
||||||
def getCellStyle(self, obj, date, render, events):
|
def getCellStyle(self, obj, date, render, events):
|
||||||
'''Gets the cell style to apply to the cell corresponding to p_date.'''
|
'''Gets the cell style to apply to the cell corresponding to p_date.'''
|
||||||
if render != 'timeline': return '' # Currently, for timelines only
|
if render != 'timeline': return '' # Currently, for timelines only
|
||||||
if not events or (len(events) > 1): return ''
|
if not events: return ''
|
||||||
|
elif len(events) > 1:
|
||||||
|
# Return a special background indicating that several events are
|
||||||
|
# hidden behing this cell.
|
||||||
|
return 'background-image: url(%s/ui/angled.png)' % \
|
||||||
|
obj.getTool().getSiteUrl()
|
||||||
|
else:
|
||||||
event = events[0]
|
event = events[0]
|
||||||
return event.bgColor and ('background-color: %s' % event.bgColor) or ''
|
return event.bgColor and ('background-color: %s' % event.bgColor) or ''
|
||||||
|
|
||||||
|
@ -1163,35 +1222,6 @@ class Calendar(Field):
|
||||||
res.append('cellDashed')
|
res.append('cellDashed')
|
||||||
return ' '.join(res)
|
return ' '.join(res)
|
||||||
|
|
||||||
def getTimelineMonths(self, grid, obj):
|
|
||||||
'''Given the p_grid of dates, this method returns the list of
|
|
||||||
corresponding months.'''
|
|
||||||
res = []
|
|
||||||
for date in grid:
|
|
||||||
if not res:
|
|
||||||
# Get the month correspoding to the first day in the grid
|
|
||||||
m = Object(month=date.aMonth(), colspan=1, year=date.year())
|
|
||||||
res.append(m)
|
|
||||||
else:
|
|
||||||
# Augment current month' colspan or create a new one
|
|
||||||
current = res[-1]
|
|
||||||
if date.aMonth() == current.month:
|
|
||||||
current.colspan += 1
|
|
||||||
else:
|
|
||||||
m = Object(month=date.aMonth(), colspan=1, year=date.year())
|
|
||||||
res.append(m)
|
|
||||||
# Replace month short names by translated names whose format may vary
|
|
||||||
# according to colspan (a higher colspan allow us to produce a longer
|
|
||||||
# month name).
|
|
||||||
for m in res:
|
|
||||||
text = '%s %d' % (obj.translate('month_%s' % m.month), m.year)
|
|
||||||
if m.colspan < 6:
|
|
||||||
# Short version: a single letter with an acronym
|
|
||||||
m.month = '<acronym title="%s">%s</acronym>' % (text, text[0])
|
|
||||||
else:
|
|
||||||
m.month = text
|
|
||||||
return res
|
|
||||||
|
|
||||||
def splitList(self, l, sub): return sutils.splitList(l, sub)
|
def splitList(self, l, sub): return sutils.splitList(l, sub)
|
||||||
def mayValidate(self, obj):
|
def mayValidate(self, obj):
|
||||||
'''May the currently logged user validate wish events ?'''
|
'''May the currently logged user validate wish events ?'''
|
||||||
|
|
|
@ -715,6 +715,10 @@ msgstr ""
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -715,6 +715,10 @@ msgstr ""
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -715,6 +715,10 @@ msgstr ""
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -716,6 +716,10 @@ msgstr "Extend the event on the following number of days (leave blank to create
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr "Also delete successive events of the same type."
|
msgstr "Also delete successive events of the same type."
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr "Several events"
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr "Timeslot"
|
msgstr "Timeslot"
|
||||||
|
|
|
@ -715,6 +715,10 @@ msgstr ""
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -716,6 +716,10 @@ msgstr "Étendre l'événement sur le nombre de jours suivants (laissez vide pou
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr "Supprimer aussi les événements successifs de même type"
|
msgstr "Supprimer aussi les événements successifs de même type"
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr "Plusieurs événements"
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr "Plage horaire"
|
msgstr "Plage horaire"
|
||||||
|
|
|
@ -715,6 +715,10 @@ msgstr ""
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -715,6 +715,10 @@ msgstr "Het event uitbreiden naar de volgende dagen (leeg laten om een event aan
|
||||||
msgid "del_next_events"
|
msgid "del_next_events"
|
||||||
msgstr "Verwijder ook alle opeenvolgende events van hetzelfde type"
|
msgstr "Verwijder ook alle opeenvolgende events van hetzelfde type"
|
||||||
|
|
||||||
|
#. Default: "Several events"
|
||||||
|
msgid "several_events"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Timeslot"
|
#. Default: "Timeslot"
|
||||||
msgid "timeslot"
|
msgid "timeslot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
BIN
gen/ui/angled.png
Normal file
BIN
gen/ui/angled.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 209 B |
Loading…
Reference in a new issue