[gen] Calendar field: added a validation mechanism.
This commit is contained in:
parent
d1aec8d5e6
commit
09bf03f9bf
|
@ -2,7 +2,7 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
import types
|
||||
from appy import Object
|
||||
from appy.shared.utils import splitList, IterSub
|
||||
from appy.shared import utils as sutils
|
||||
from appy.gen import Field
|
||||
from appy.px import Px
|
||||
from DateTime import DateTime
|
||||
|
@ -33,6 +33,22 @@ class Timeslot:
|
|||
if not self.eventTypes: return True
|
||||
return eventType in self.eventTypes
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
class Validation:
|
||||
'''The validation process for a calendar consists in "converting" some event
|
||||
types being "wishes" to other event types being the corresponding
|
||||
validated events. This class holds information about this validation
|
||||
process. For more information, see the Calendar constructor, parameter
|
||||
"validation".'''
|
||||
def __init__(self, method, schema):
|
||||
# p_method holds a method that must return True if the currently logged
|
||||
# user can validate whish events.
|
||||
self.method = method
|
||||
# p_schema must hold a dict whose keys are the event types being wishes
|
||||
# and whose values are the event types being the corresponding validated
|
||||
# event types.
|
||||
self.schema = schema
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
class Other:
|
||||
'''Identifies a Calendar field that must be shown within another Calendar
|
||||
|
@ -104,9 +120,10 @@ class Calendar(Field):
|
|||
DateTime = DateTime
|
||||
# Access to Calendar utility classes via the Calendar class
|
||||
Timeslot = Timeslot
|
||||
Validation = Validation
|
||||
Other = Other
|
||||
Event = Event
|
||||
IterSub = IterSub
|
||||
IterSub = sutils.IterSub
|
||||
# Error messages
|
||||
TIMESLOT_USED = 'An event is already defined at this timeslot.'
|
||||
DAY_FULL = 'No more place for adding this event.'
|
||||
|
@ -155,6 +172,7 @@ class Calendar(Field):
|
|||
# Timeline view for a calendar
|
||||
pxViewTimeline = Px('''
|
||||
<table cellpadding="0" cellspacing="0" class="list timeline"
|
||||
id=":ajaxHookId + '_cal'"
|
||||
var="monthsInfos=field.getTimelineMonths(grid, zobj)">
|
||||
<!-- Column specifiers -->
|
||||
<colgroup>
|
||||
|
@ -202,14 +220,12 @@ class Calendar(Field):
|
|||
|
||||
# Popup for adding an event in the month view
|
||||
pxAddPopup = Px('''
|
||||
<div var="prefix='%s_newEvent' % field.name;
|
||||
popupId=prefix + 'Popup'"
|
||||
<div var="popupId=ajaxHookId + '_new'"
|
||||
id=":popupId" class="popup" align="center">
|
||||
<form id=":prefix + 'Form'" method="post">
|
||||
<form id=":popupId + 'Form'" method="post" action="/process">
|
||||
<input type="hidden" name="fieldName" value=":field.name"/>
|
||||
<input type="hidden" name="month" value=":month"/>
|
||||
<input type="hidden" name="name" value=":field.name"/>
|
||||
<input type="hidden" name="action" value="process"/>
|
||||
<input type="hidden" name="actionType" value="createEvent"/>
|
||||
<input type="hidden" name="day"/>
|
||||
|
||||
|
@ -236,9 +252,8 @@ class Calendar(Field):
|
|||
</div>
|
||||
<input type="button"
|
||||
value=":_('object_save')"
|
||||
onclick=":'triggerCalendarEvent(%s, %s, %s, %s, \
|
||||
%s_maxEventLength)' % (q('new'), q(ajaxHookId), \
|
||||
q(field.name), q(objUrl), field.name)"/>
|
||||
onclick=":'triggerCalendarEvent(%s, %s, %s_maxEventLength)' % \
|
||||
(q(ajaxHookId), q('new'), field.name)"/>
|
||||
<input type="button"
|
||||
value=":_('object_cancel')"
|
||||
onclick=":'closePopup(%s)' % q(popupId)"/>
|
||||
|
@ -247,14 +262,12 @@ class Calendar(Field):
|
|||
|
||||
# Popup for removing events in the month view
|
||||
pxDelPopup = Px('''
|
||||
<div var="prefix='%s_delEvent' % field.name;
|
||||
popupId=prefix + 'Popup'"
|
||||
<div var="popupId=ajaxHookId + '_del'"
|
||||
id=":popupId" class="popup" align="center">
|
||||
<form id=":prefix + 'Form'" method="post">
|
||||
<form id=":popupId + 'Form'" method="post" action="/process">
|
||||
<input type="hidden" name="fieldName" value=":field.name"/>
|
||||
<input type="hidden" name="month" value=":month"/>
|
||||
<input type="hidden" name="name" value=":field.name"/>
|
||||
<input type="hidden" name="action" value="process"/>
|
||||
<input type="hidden" name="actionType" value="deleteEvent"/>
|
||||
<input type="hidden" name="timeslot" value="main"/>
|
||||
<input type="hidden" name="day"/>
|
||||
|
@ -263,8 +276,8 @@ class Calendar(Field):
|
|||
|
||||
<!-- Delete successive events ? -->
|
||||
<div class="discreet" style="margin-bottom: 10px"
|
||||
id=":prefix + 'DelNextEvent'"
|
||||
var="cbId=prefix + '_cb'; hdId=prefix + '_hd'">
|
||||
id=":ajaxHookId + '_DelNextEvent'"
|
||||
var="cbId=popupId + '_cb'; hdId=popupId + '_hd'">
|
||||
<input type="checkbox" name="deleteNext_cb" id=":cbId"
|
||||
onClick=":'toggleCheckbox(%s, %s)' % (q(cbId), q(hdId))"/>
|
||||
<input type="hidden" id=":hdId" name="deleteNext"/>
|
||||
|
@ -272,8 +285,8 @@ class Calendar(Field):
|
|||
style="text-transform: none">:_('del_next_events')</label>
|
||||
</div>
|
||||
<input type="button" value=":_('yes')"
|
||||
onClick=":'triggerCalendarEvent(%s, %s, %s, %s)' % \
|
||||
(q('del'), q(ajaxHookId), q(field.name), q(objUrl))"/>
|
||||
onClick=":'triggerCalendarEvent(%s, %s)' % \
|
||||
(q(ajaxHookId), q('del'))"/>
|
||||
<input type="button" value=":_('no')"
|
||||
onclick=":'closePopup(%s)' % q(popupId)"/>
|
||||
</form>
|
||||
|
@ -282,7 +295,7 @@ class Calendar(Field):
|
|||
# Month view for a calendar
|
||||
pxViewMonth = Px('''
|
||||
<table cellpadding="0" cellspacing="0" width="100%" class="list"
|
||||
style="font-size: 95%"
|
||||
style="font-size: 95%" id=":ajaxHookId + '_cal'"
|
||||
var="rowHeight=int(field.height/float(len(grid)))">
|
||||
<!-- 1st row: names of days -->
|
||||
<tr height="22px">
|
||||
|
@ -321,23 +334,28 @@ 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(ajaxHookId), q('new'), q(dayString), q(info.eventTypes), \
|
||||
q(info.message), q(freeSlots))"/>
|
||||
</x>
|
||||
<!-- Icon for deleting event(s) -->
|
||||
<img if="mayDelete" class="clickable" style="visibility:hidden"
|
||||
src=":url(single and 'delete' or 'deleteMany')"
|
||||
onclick=":'openEventPopup(%s,%s,%s,%s,%s)' % (q('del'), \
|
||||
q(field.name), q(dayString), q('main'), q(spansDays))"/>
|
||||
onclick=":'openEventPopup(%s,%s,%s,%s,%s)' % (q(ajaxHookId), \
|
||||
q('del'), q(dayString), q('main'), q(spansDays))"/>
|
||||
<!-- Events -->
|
||||
<x if="events">
|
||||
<div for="event in events" style="color: grey">
|
||||
<!-- Checkbox for validating the event -->
|
||||
<input type="checkbox" checked="checked" class="smallbox"
|
||||
if="mayValidate and (event.eventType in field.validation.schema)"
|
||||
id=":'%s_%s_%s' % (date.strftime('%Y%m%d'), event.eventType, \
|
||||
event.timeslot)"/>
|
||||
<x>::event.getName(allEventNames)</x>
|
||||
<!-- Icon for delete this particular event -->
|
||||
<img if="mayDelete and not single" class="clickable"
|
||||
src=":url('delete')" style="visibility:hidden"
|
||||
onclick=":'openEventPopup(%s,%s,%s,%s)' % (q('del'), \
|
||||
q(field.name), q(dayString), q(event.timeslot))"/>
|
||||
onclick=":'openEventPopup(%s,%s,%s,%s)' % (q(ajaxHookId), \
|
||||
q('del'), q(dayString), q(event.timeslot))"/>
|
||||
</div>
|
||||
</x>
|
||||
<!-- Events from other calendars -->
|
||||
|
@ -384,12 +402,15 @@ class Calendar(Field):
|
|||
namesOfDays=field.getNamesOfDays(_);
|
||||
showTimeslots=len(field.timeslots) > 1;
|
||||
slotIds=[slot.id for slot in field.timeslots];
|
||||
slotIdsStr=','.join(slotIds)"
|
||||
slotIdsStr=','.join(slotIds);
|
||||
mayValidate=field.mayValidate(zobj)"
|
||||
id=":ajaxHookId">
|
||||
<script>:'var %s_maxEventLength = %d;' % \
|
||||
(field.name, field.maxEventLength)</script>
|
||||
<script>:field.getAjaxData(ajaxHookId, zobj, render=render, \
|
||||
month=defaultDateMonth)</script>
|
||||
|
||||
<!-- Month chooser -->
|
||||
<!-- Actions (month chooser, validation) -->
|
||||
<div style="margin-bottom: 5px"
|
||||
var="fmt='%Y/%m/%d';
|
||||
goBack=not startDate or (startDate.strftime(fmt) < \
|
||||
|
@ -398,23 +419,26 @@ class Calendar(Field):
|
|||
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))"/>
|
||||
onclick=":'askMonth(%s,%s)' % (q(ajaxHookId), 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))"
|
||||
onclick=":'askMonth(%s,%s)' % (q(ajaxHookId),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))"/>
|
||||
onclick=":'askMonth(%s,%s)' % (q(ajaxHookId), q(nextMonth))"/>
|
||||
<span>:_('month_%s' % monthDayOne.aMonth())</span>
|
||||
<span>:month.split('/')[0]</span>
|
||||
<!-- Validate button -->
|
||||
<input if="mayValidate" type="button" value=":_('validate_events')"
|
||||
class="buttonSmall button" style=":url('validate', bg=True)"
|
||||
var2="js='validateEvents(%s)' % q(ajaxHookId)"
|
||||
onclick=":'askConfirm(%s,%s,%s)' % (q('script'), q(js, False), \
|
||||
q(_('validate_events_confirm')))"/>
|
||||
</div>
|
||||
<x>:getattr(field, 'pxView%s' % render.capitalize())</x>
|
||||
</div>''')
|
||||
|
@ -430,7 +454,8 @@ class Calendar(Field):
|
|||
others=None, timelineName=None, additionalInfo=None,
|
||||
startDate=None, endDate=None, defaultDate=None, timeslots=None,
|
||||
colors=None, showUncolored=False, preCompute=None,
|
||||
applicableEvents=None, view=None, xml=None, delete=True):
|
||||
applicableEvents=None, validation=None, view=None, xml=None,
|
||||
delete=True):
|
||||
Field.__init__(self, validator, (0,1), default, show, page, group,
|
||||
layouts, move, False, True, False, specificReadPermission,
|
||||
specificWritePermission, width, height, None, colspan,
|
||||
|
@ -533,6 +558,12 @@ class Calendar(Field):
|
|||
# for explaining him why he can, for this day, only create events of a
|
||||
# sub-set of the possible event types (or even no event at all).
|
||||
self.applicableEvents = applicableEvents
|
||||
# A validation process can be associated to a Calendar event. It
|
||||
# consists in identifying validators and letting them "convert" event
|
||||
# types being wished to final, validated event types. If you want to
|
||||
# enable this, define a Validation instance (see the hereabove class)
|
||||
# in parameter "validation".
|
||||
self.validation = validation
|
||||
# May the user delete events in this calendar? If "delete" is a method,
|
||||
# it must accept an event type as single arg.
|
||||
self.delete = delete
|
||||
|
@ -717,17 +748,21 @@ class Calendar(Field):
|
|||
return ','.join(res)
|
||||
|
||||
def getEventsAt(self, obj, date):
|
||||
'''Returns the list of events that exist at some p_date (=day).'''
|
||||
'''Returns the list of events that exist at some p_date (=day). p_date
|
||||
can be a DateTime instance or a tuple (i_year, i_month, i_day).'''
|
||||
obj = obj.o # Ensure p_obj is not a wrapper
|
||||
if not hasattr(obj.aq_base, self.name): return
|
||||
years = getattr(obj, self.name)
|
||||
year = date.year()
|
||||
# Get year, month and name from p_date
|
||||
if isinstance(date, tuple):
|
||||
year, month, day = date
|
||||
else:
|
||||
year, month, day = date.year(), date.month(), date.day()
|
||||
# Dig into the oobtree
|
||||
if year not in years: return
|
||||
months = years[year]
|
||||
month = date.month()
|
||||
if month not in months: return
|
||||
days = months[month]
|
||||
day = date.day()
|
||||
if day not in days: return
|
||||
return days[day]
|
||||
|
||||
|
@ -865,7 +900,7 @@ class Calendar(Field):
|
|||
if isinstance(others, Other):
|
||||
others.getEventsAt(res, self, date, eventNames, isTimeline, colors)
|
||||
else:
|
||||
for other in IterSub(others):
|
||||
for other in sutils.IterSub(others):
|
||||
other.getEventsAt(res, self, date, eventNames,isTimeline,colors)
|
||||
return res
|
||||
|
||||
|
@ -888,7 +923,7 @@ class Calendar(Field):
|
|||
res[0].append(et)
|
||||
res[1][et] = self.getEventName(obj, et)
|
||||
if not others: return res
|
||||
for other in IterSub(others):
|
||||
for other in sutils.IterSub(others):
|
||||
eventTypes = other.field.getEventTypes(other.obj)
|
||||
if eventTypes:
|
||||
for et in eventTypes:
|
||||
|
@ -1126,5 +1161,48 @@ class Calendar(Field):
|
|||
m.month = text
|
||||
return res
|
||||
|
||||
def splitList(self, l, sub): return splitList(l, sub)
|
||||
def splitList(self, l, sub): return sutils.splitList(l, sub)
|
||||
def mayValidate(self, obj):
|
||||
'''May the currently logged user validate wish events ?'''
|
||||
if not self.validation: return
|
||||
return self.validation.method(obj.appy())
|
||||
|
||||
def getAjaxData(self, hook, zobj, **params):
|
||||
'''Initializes an AjaxData object on the DOM node corresponding to
|
||||
this calendar field.'''
|
||||
params = sutils.getStringDict(params)
|
||||
return "new AjaxData('%s', '%s:pxView', %s, null, '%s')" % \
|
||||
(hook, self.name, params, zobj.absolute_url())
|
||||
|
||||
def validateEvents(self, obj):
|
||||
'''Validate or discard events from the request.'''
|
||||
rq = obj.REQUEST.form
|
||||
counts = {'validated': 0, 'discarded': 0}
|
||||
for action in ('validated', 'discarded'):
|
||||
if not rq[action]: continue
|
||||
for info in rq[action].split(','):
|
||||
sdate, eventType, timeslot = info.split('_')
|
||||
# Get the events defined at that date
|
||||
date = int(sdate[:4]), int(sdate[4:6]), int(sdate[6:8])
|
||||
events = self.getEventsAt(obj, date)
|
||||
i = len(events) - 1
|
||||
while i >= 0:
|
||||
# Get the event at that timeslot
|
||||
event = events[i]
|
||||
if event.timeslot == timeslot:
|
||||
# We have found the event
|
||||
if event.eventType != eventType:
|
||||
raise Exception('Wrong event type')
|
||||
# Validate or discard it
|
||||
if action == 'validated':
|
||||
event.eventType = self.validation.schema[eventType]
|
||||
else:
|
||||
del events[i]
|
||||
counts[action] += 1
|
||||
i -= 1
|
||||
obj.log('%s:%s: %d event(s) validated and %d discarded.' % \
|
||||
(obj.id, self.name, counts['validated'], counts['discarded']))
|
||||
if not counts['validated'] and not counts['discarded']:
|
||||
return obj.translate('action_null')
|
||||
return obj.translate('validate_events_done', mapping=counts)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -1254,8 +1254,8 @@ class Ref(Field):
|
|||
(obj.id, self.name, code % ('objs', 'objs'), poss)
|
||||
|
||||
def getAjaxData(self, hook, zobj, **params):
|
||||
'''Initializes an AjaxData object on the DOM node corresponding to
|
||||
p_hook = the whole search result.'''
|
||||
'''Initializes an AjaxData object on the DOM node corresponding to this
|
||||
Ref field.'''
|
||||
# Complete params with default parameters
|
||||
params['ajaxHookId'] = hook;
|
||||
params['scope'] = hook.rsplit('_', 1)[-1]
|
||||
|
|
|
@ -727,6 +727,18 @@ msgstr ""
|
|||
msgid "timeslot_misfit"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr ""
|
||||
|
|
12
gen/tr/ar.po
12
gen/tr/ar.po
|
@ -727,6 +727,18 @@ msgstr ""
|
|||
msgid "timeslot_misfit"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr ""
|
||||
|
|
12
gen/tr/de.po
12
gen/tr/de.po
|
@ -727,6 +727,18 @@ msgstr ""
|
|||
msgid "timeslot_misfit"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr ""
|
||||
|
|
12
gen/tr/en.po
12
gen/tr/en.po
|
@ -728,6 +728,18 @@ msgstr "All day"
|
|||
msgid "timeslot_misfit"
|
||||
msgstr "Cannot create such an event in the ${slot} slot."
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr "Validate events"
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr "Inserted by ${userName}"
|
||||
|
|
12
gen/tr/es.po
12
gen/tr/es.po
|
@ -727,6 +727,18 @@ msgstr ""
|
|||
msgid "timeslot_misfit"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr ""
|
||||
|
|
12
gen/tr/fr.po
12
gen/tr/fr.po
|
@ -728,6 +728,18 @@ msgstr "Toute la journée"
|
|||
msgid "timeslot_misfit"
|
||||
msgstr "Impossible de créer ce type d'événement dans la plage horaire ${slot}."
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr "Valider les événements"
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr "Tous les événements sélectionnés seront confirmés, tandis que ceux qui sont désélectionnés seront rejetés. Le ou les utilisateurs concernés seront prévenus. Êtes-vous sûr?"
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr "${validated} événement(s) a (ont) été validé(s) et ${discarded} a (ont) été rejeté(s)."
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr "Inséré par ${userName}"
|
||||
|
|
12
gen/tr/it.po
12
gen/tr/it.po
|
@ -727,6 +727,18 @@ msgstr ""
|
|||
msgid "timeslot_misfit"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr ""
|
||||
|
|
12
gen/tr/nl.po
12
gen/tr/nl.po
|
@ -727,6 +727,18 @@ msgstr ""
|
|||
msgid "timeslot_misfit"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Validate events"
|
||||
msgid "validate_events"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "All the checked events will be confirmed, while the unchecked ones will be discarded. The concerned user(s) will be warned. Are you sure?"
|
||||
msgid "validate_events_confirm"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
|
||||
msgid "validate_events_done"
|
||||
msgstr ""
|
||||
|
||||
#. Default: "Inserted by ${userName}"
|
||||
msgid "history_insert"
|
||||
msgstr "Ingevuld door ${userName}"
|
||||
|
|
|
@ -198,3 +198,4 @@ td.search { padding-top: 8px }
|
|||
.highlight { background-color: yellow }
|
||||
.globalActions { margin-bottom: 4px }
|
||||
.objectActions { margin: 2px 0 }
|
||||
.smallbox { margin: 0 }
|
||||
|
|
|
@ -295,9 +295,10 @@ function askAjax(hook, form, params) {
|
|||
}
|
||||
else var mode = d.mode;
|
||||
// Get p_params if given. Note that they override anything else.
|
||||
if (params && ('mode' in params)) {
|
||||
mode = params['mode']; delete params['mode'] }
|
||||
if (params) { for (var key in params) d.params[key] = params[key]; }
|
||||
askAjaxChunk(hook, mode, d.url, d.px, d.params, d.beforeSend,
|
||||
evalInnerScripts);
|
||||
askAjaxChunk(hook,mode,d.url,d.px,d.params,d.beforeSend,evalInnerScripts);
|
||||
}
|
||||
|
||||
function askBunch(hookId, startNumber) {
|
||||
|
|
|
@ -8,11 +8,8 @@ function toggleVisibility(node, nodeType){
|
|||
}
|
||||
}
|
||||
|
||||
function askCalendar(hookId, objectUrl, render, fieldName, month) {
|
||||
// Sends an Ajax request for getting the calendar, at p_month
|
||||
var params = {'month': month, 'render': render};
|
||||
askAjaxChunk(hookId, 'GET', objectUrl, fieldName+':pxView', params);
|
||||
}
|
||||
// Sends an Ajax request for getting the calendar, at p_month
|
||||
function askMonth(hookId, month) {askAjax(hookId, null, {'month': month})}
|
||||
|
||||
function enableOptions(select, enabled, selectFirst, message){
|
||||
/* This function disables, in p_select, all options that are not in p_enabled.
|
||||
|
@ -46,7 +43,7 @@ function enableOptions(select, enabled, selectFirst, message){
|
|||
}
|
||||
}
|
||||
|
||||
function openEventPopup(action, fieldName, day, timeslot, spansDays,
|
||||
function openEventPopup(hookId, action, day, timeslot, spansDays,
|
||||
applicableEventTypes, message, freeSlots) {
|
||||
/* Opens the popup for creating (or deleting, depending on p_action) a
|
||||
calendar event at some p_day. When action is "del", we need to know the
|
||||
|
@ -57,13 +54,13 @@ function openEventPopup(action, fieldName, day, timeslot, spansDays,
|
|||
p_applicableEventTypes; p_message contains an optional message explaining
|
||||
why not applicable types are not applicable. When "new", p_freeSlots may
|
||||
list the available timeslots at p_day. */
|
||||
var prefix = fieldName + '_' + action + 'Event';
|
||||
var f = document.getElementById(prefix + 'Form');
|
||||
var popupId = hookId + '_' + action;
|
||||
var f = document.getElementById(popupId + 'Form');
|
||||
f.day.value = day;
|
||||
if (action == 'del') {
|
||||
if (f.timeslot) f.timeslot.value = timeslot;
|
||||
// Show or hide the checkbox for deleting the event for successive days
|
||||
var elem = document.getElementById(prefix + 'DelNextEvent');
|
||||
var elem = document.getElementById(hookId + '_DelNextEvent');
|
||||
var cb = elem.getElementsByTagName('input');
|
||||
cb[0].checked = false;
|
||||
cb[1].value = 'False';
|
||||
|
@ -78,15 +75,15 @@ function openEventPopup(action, fieldName, day, timeslot, spansDays,
|
|||
enableOptions(f.eventType, applicableEventTypes, false, message);
|
||||
if (f.timeslot) enableOptions(f.timeslot, freeSlots, true, 'Not free');
|
||||
}
|
||||
openPopup(prefix + 'Popup');
|
||||
openPopup(popupId);
|
||||
}
|
||||
|
||||
function triggerCalendarEvent(action, hookId, fieldName, objectUrl,
|
||||
maxEventLength) {
|
||||
function triggerCalendarEvent(hookId, action, maxEventLength) {
|
||||
/* Sends an Ajax request for triggering a calendar event (create or delete an
|
||||
event) and refreshing the view month. */
|
||||
var prefix = fieldName + '_' + action + 'Event';
|
||||
var f = document.getElementById(prefix + 'Form');
|
||||
var popupId = hookId + '_' + action;
|
||||
var formId = popupId + 'Form';
|
||||
var f = document.getElementById(formId);
|
||||
if (action == 'new') {
|
||||
// Check that an event span has been specified
|
||||
if (f.eventType.selectedIndex == 0) {
|
||||
|
@ -105,12 +102,25 @@ function triggerCalendarEvent(action, hookId, fieldName, objectUrl,
|
|||
}
|
||||
}
|
||||
}
|
||||
var elems = f.elements;
|
||||
var params = {};
|
||||
// Put form elements into "params"
|
||||
for (var i=0; i < elems.length; i++) {
|
||||
params[elems[i].name] = elems[i].value;
|
||||
}
|
||||
closePopup(prefix + 'Popup');
|
||||
askAjaxChunk(hookId, 'POST', objectUrl, fieldName+':pxView', params);
|
||||
closePopup(popupId);
|
||||
askAjax(hookId, formId);
|
||||
}
|
||||
|
||||
// Function for validating and discarding calendar events
|
||||
function validateEvents(hookId) {
|
||||
// Collect checkboxes from hookId and identify checked and unchecked ones
|
||||
var validated = [];
|
||||
var discarded = [];
|
||||
var node = document.getElementById(hookId + '_cal');
|
||||
var cbs = node.getElementsByTagName('input');
|
||||
for (var i=0; i<cbs.length; i++) {
|
||||
if (cbs[i].type != 'checkbox') continue;
|
||||
if (cbs[i].checked) validated.push(cbs[i].id);
|
||||
else discarded.push(cbs[i].id);
|
||||
}
|
||||
validated = validated.join()
|
||||
discarded = discarded.join()
|
||||
var params = {'action': 'validateEvents', 'validated': validated,
|
||||
'discarded': discarded, 'mode': 'POST'};
|
||||
askAjax(hookId, null, params);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue