[gen] Added a new calendar field, allowing to add a single (typed) event by day.
This commit is contained in:
parent
3bd66e3264
commit
93bde7a0f5
12 changed files with 523 additions and 19 deletions
49
gen/ui/widgets/calendar.js
Normal file
49
gen/ui/widgets/calendar.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
function askMonthView(hookId, objectUrl, fieldName, month) {
|
||||
// Sends an Ajax request for getting the view month of a calendar field
|
||||
var params = {'fieldName': fieldName, 'month': month};
|
||||
askAjaxChunk(hookId,'GET',objectUrl,'widgets/calendar','viewMonth', params);
|
||||
}
|
||||
|
||||
function openEventPopup(action, fieldName, day, spansDays) {
|
||||
/* 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
|
||||
(from p_spansDays) if the event spans more days, in order to propose a
|
||||
checkbox allowing to delete events for those successive days. */
|
||||
var prefix = fieldName + '_' + action + 'Event';
|
||||
var f = document.getElementById(prefix + 'Form');
|
||||
f.day.value = day;
|
||||
if (action == 'del') {
|
||||
var elem = document.getElementById(prefix + 'DelNextEvent');
|
||||
var cb = elem.getElementsByTagName('input');
|
||||
cb[0].checked = false;
|
||||
cb[1].value = 'False';
|
||||
if (spansDays == 'True') { elem.style.display = 'block' }
|
||||
else { elem.style.display = 'none' }
|
||||
}
|
||||
openPopup(prefix + 'Popup');
|
||||
}
|
||||
|
||||
function triggerCalendarEvent(action, hookId, fieldName, objectUrl) {
|
||||
/* 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');
|
||||
if (action == 'new') {
|
||||
// Check that eventSpan is empty or contains a valid number
|
||||
var spanNumber = f.eventSpan.value.replace(' ', '');
|
||||
if (spanNumber) {
|
||||
if (isNaN(parseInt(spanNumber))) {
|
||||
f.eventSpan.style.background = wrongTextInput;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
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,'widgets/calendar','viewMonth',params);
|
||||
}
|
163
gen/ui/widgets/calendar.pt
Normal file
163
gen/ui/widgets/calendar.pt
Normal file
|
@ -0,0 +1,163 @@
|
|||
<tal:comment replace="nothing">View macro</tal:comment>
|
||||
<div metal:define-macro="viewMonth"
|
||||
tal:define="fieldName request/fieldName;
|
||||
ajaxHookId python: contextObj.UID() + fieldName;
|
||||
month request/month;
|
||||
monthDayOne python: DateTime('%s/01' % month);
|
||||
today python: DateTime('00:00');
|
||||
todayMonth python: today.strftime('%Y/%m');
|
||||
grid python: contextObj.callField(fieldName, 'getMonthGrid', month);
|
||||
previousMonth python: contextObj.callField(fieldName, 'getSiblingMonth', month, 'previous');
|
||||
nextMonth python: contextObj.callField(fieldName, 'getSiblingMonth', month, 'next');
|
||||
widget python: contextObj.getAppyType(fieldName, asDict=True);
|
||||
mayEdit python: contextObj.allows(widget['writePermission']);
|
||||
objUrl contextObj/absolute_url"
|
||||
tal:attributes="id ajaxHookId">
|
||||
|
||||
<tal:comment replace="nothing">Month chooser</tal:comment>
|
||||
<div style="margin-bottom: 5px">
|
||||
<img style="cursor:pointer"
|
||||
tal:attributes="src string: $appUrl/ui/arrowLeftSimple.png;
|
||||
onclick python: 'askMonthView(\'%s\',\'%s\',\'%s\',\'%s\')' % (ajaxHookId,objUrl,fieldName,previousMonth)"/>
|
||||
<input type="button"
|
||||
tal:attributes="value python: _('today');
|
||||
onclick python: 'askMonthView(\'%s\',\'%s\',\'%s\',\'%s\')' % (ajaxHookId,objUrl,fieldName,todayMonth);
|
||||
disabled monthDayOne/isCurrentMonth"/>
|
||||
<img style="cursor:pointer"
|
||||
tal:attributes="src string: $appUrl/ui/arrowRightSimple.png;
|
||||
onclick python: 'askMonthView(\'%s\',\'%s\',\'%s\',\'%s\')' % (ajaxHookId,objUrl,fieldName,nextMonth)"/>
|
||||
<span tal:content="python: _('month_%s' % monthDayOne.aMonth())"></span>
|
||||
<span tal:content="python: month.split('/')[0]"></span>
|
||||
</div>
|
||||
|
||||
<tal:comment replace="nothing">Calendar month view</tal:comment>
|
||||
<table cellpadding="0" cellspacing="0" width="100%" class="list" style="font-size: 95%"
|
||||
tal:define="rowHeight python: int(widget['height']/float(len(grid)))">
|
||||
<tal:comment replace="nothing">1st row: names of days</tal:comment>
|
||||
<tr height="22px">
|
||||
<th tal:repeat="dayName python: contextObj.callField(fieldName, 'getNamesOfDays', contextObj)"
|
||||
tal:content="dayName" width="14%">
|
||||
</th>
|
||||
</tr>
|
||||
<tal:comment replace="nothing">The calendar in itself</tal:comment>
|
||||
<tr tal:repeat="row grid" valign="top" tal:attributes="height rowHeight">
|
||||
<tal:cell repeat="date row">
|
||||
<td tal:define="events python: contextObj.callField(fieldName, 'getEventsAt', contextObj, date);
|
||||
spansDays python: contextObj.callField(fieldName, 'hasEventsAt', contextObj, date+1, events);
|
||||
mayCreate python: mayEdit and not events;
|
||||
mayDelete python: mayEdit and events;"
|
||||
tal:attributes="style python: test(date.isCurrentDay(), 'font-weight:bold', 'font-weight:normal');
|
||||
class python: test(date < today, 'even', 'odd');
|
||||
onmouseover python: test(mayEdit, 'this.getElementsByTagName(\'img\')[0].style.visibility=\'visible\'', '');
|
||||
onmouseout python: test(mayEdit, 'this.getElementsByTagName(\'img\')[0].style.visibility=\'hidden\'', '')">
|
||||
<tal:day define="day date/day;
|
||||
dayString python: date.strftime('%Y/%m/%d')">
|
||||
<span tal:content="day"></span>
|
||||
<span tal:condition="python: day == 1"
|
||||
tal:content="python: _('month_%s_short' % date.aMonth())"></span>
|
||||
<tal:comment replace="nothing">Icon for adding an event</tal:comment>
|
||||
<img tal:condition="mayCreate" style="visibility:hidden; cursor:pointer"
|
||||
tal:attributes="src string: $appUrl/ui/plus.png;
|
||||
onclick python: 'openEventPopup(\'new\',\'%s\',\'%s\')' % (fieldName, dayString)"/>
|
||||
<tal:comment replace="nothing">Icon for deleting an event</tal:comment>
|
||||
<img tal:condition="mayDelete" style="visibility:hidden; cursor:pointer"
|
||||
tal:attributes="src string: $appUrl/ui/delete.png;
|
||||
onclick python: 'openEventPopup(\'del\',\'%s\',\'%s\',\'%s\')' % (fieldName, dayString, str(spansDays))"/>
|
||||
<tal:events condition="events">
|
||||
<tal:comment replace="nothing">A single event is allowed for the moment</tal:comment>
|
||||
<div tal:define="eventType python: events[0]['eventType']">
|
||||
<span style="color: grey"
|
||||
tal:content="python: _('%s_event_%s' % (widget['labelId'], eventType))"></span>
|
||||
</div>
|
||||
</tal:events>
|
||||
</tal:day>
|
||||
</td>
|
||||
</tal:cell>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<tal:comment replace="nothing">Popup for creating a calendar event</tal:comment>
|
||||
<div tal:define="prefix python: '%s_newEvent' % fieldName;
|
||||
popupId python: prefix + 'Popup'"
|
||||
tal:attributes="id popupId" class="popup" align="center">
|
||||
<form tal:attributes="id python: prefix + 'Form'" method="post">
|
||||
<input type="hidden" name="fieldName" tal:attributes="value fieldName"/>
|
||||
<input type="hidden" name="month" tal:attributes="value month"/>
|
||||
<input type="hidden" name="name" tal:attributes="value fieldName"/>
|
||||
<input type="hidden" name="action" value="Process"/>
|
||||
<input type="hidden" name="actionType" value="createEvent"/>
|
||||
<input type="hidden" name="day"/>
|
||||
|
||||
<div align="center" style="margin-bottom: 3px" tal:content="python: _('which_event')"></div>
|
||||
<select name="eventType">
|
||||
<option tal:repeat="eventType widget/eventTypes"
|
||||
tal:content="python: _('%s_event_%s' % (widget['labelId'], eventType))"
|
||||
tal:attributes="value eventType">
|
||||
</option>
|
||||
</select><br/><br/>
|
||||
<tal:comment replace="nothing">Span the event on several days</tal:comment>
|
||||
<div align="center" class="discreet" style="margin-bottom: 3px">
|
||||
<span tal:content="python: _('event_span')"></span>
|
||||
<input type="text" size="3" name="eventSpan"/>
|
||||
</div>
|
||||
<input type="button"
|
||||
tal:attributes="value python:_('object_save');
|
||||
onClick python: 'triggerCalendarEvent(\'new\',\'%s\',\'%s\',\'%s\')' % (ajaxHookId,fieldName,objUrl)"/>
|
||||
<input type="button"
|
||||
tal:attributes="value python:_('object_cancel');
|
||||
onclick python: 'closePopup(\'%s\')' % popupId"/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<tal:comment replace="nothing">Popup for deleting a calendar event</tal:comment>
|
||||
<div tal:define="prefix python: '%s_delEvent' % fieldName;
|
||||
popupId python: prefix + 'Popup'"
|
||||
tal:attributes="id popupId" class="popup" align="center">
|
||||
<form tal:attributes="id python: prefix + 'Form'" method="post">
|
||||
<input type="hidden" name="fieldName" tal:attributes="value fieldName"/>
|
||||
<input type="hidden" name="month" tal:attributes="value month"/>
|
||||
<input type="hidden" name="name" tal:attributes="value fieldName"/>
|
||||
<input type="hidden" name="action" value="Process"/>
|
||||
<input type="hidden" name="actionType" value="deleteEvent"/>
|
||||
<input type="hidden" name="day"/>
|
||||
|
||||
<div align="center" style="margin-bottom: 5px"
|
||||
tal:content="python: _('delete_confirm')"></div>
|
||||
|
||||
<tal:comment replace="nothing">Delete successive events?</tal:comment>
|
||||
<div class="discreet" style="margin-bottom: 10px"
|
||||
tal:attributes="id python: prefix + 'DelNextEvent'">
|
||||
<input type="checkbox" name="deleteNext_cb"
|
||||
tal:attributes="id python: prefix + '_cb';
|
||||
onClick python:'toggleCheckbox(\'%s_cb\', \'%s_hd\')' % (prefix, prefix);"/>
|
||||
<input type="hidden" tal:attributes="id python: prefix + '_hd'" name="deleteNext"/>
|
||||
<span tal:content="python: _('del_next_events')"/>
|
||||
</div>
|
||||
<input type="button"
|
||||
tal:attributes="value python:_('yes');
|
||||
onClick python: 'triggerCalendarEvent(\'del\',\'%s\',\'%s\',\'%s\')' % (ajaxHookId,fieldName,objUrl)"/>
|
||||
<input type="button"
|
||||
tal:attributes="value python:_('no');
|
||||
onclick python: 'closePopup(\'%s\')' % popupId"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<tal:comment replace="nothing">View macro</tal:comment>
|
||||
<metal:view define-macro="view"
|
||||
tal:define="now python: DateTime();
|
||||
dummy python: request.set('fieldName', widget['name']);
|
||||
dummy python: request.set('month', now.strftime('%Y/%m'))">
|
||||
<metal:call use-macro="app/ui/widgets/calendar/macros/viewMonth"/>
|
||||
</metal:view>
|
||||
|
||||
<tal:comment replace="nothing">Edit macro</tal:comment>
|
||||
<metal:edit define-macro="edit"></metal:edit>
|
||||
|
||||
<tal:comment replace="nothing">Cell macro</tal:comment>
|
||||
<metal:cell define-macro="cell">
|
||||
<metal:call use-macro="app/ui/widgets/calendar/macros/view"/>
|
||||
</metal:cell>
|
||||
|
||||
<tal:comment replace="nothing">Search macro</tal:comment>
|
||||
<metal:search define-macro="search"></metal:search>
|
Loading…
Add table
Add a link
Reference in a new issue