[views] improve JQueryDatePicker so that a date field can be defined as the min/max of an other one
authorErica Marco <erica.marco@logilab.fr>
Thu, 26 Mar 2015 11:13:12 +0100
changeset 11048 96d57cb8b644
parent 11042 079b32f4cd0d
child 11049 1f41697f2e26
[views] improve JQueryDatePicker so that a date field can be defined as the min/max of an other one closes #5169039
web/data/cubicweb.widgets.js
web/formwidgets.py
--- a/web/data/cubicweb.widgets.js	Tue Dec 22 18:25:37 2015 +0100
+++ b/web/data/cubicweb.widgets.js	Thu Mar 26 11:13:12 2015 +0100
@@ -25,6 +25,23 @@
     return null;
 }
 
+function renderJQueryDatePicker(subject, button_image, date_format, min_date, max_date){
+    $widget = cw.jqNode(subject);
+    $widget.datepicker({buttonImage: button_image, dateFormat: date_format,
+                        firstDay: 1, showOn: "button", buttonImageOnly: true,
+                        minDate: min_date, maxDate: max_date});
+    $widget.change(function(ev) {
+        maxOfId = $(this).data('max-of');
+        if (maxOfId) {
+            cw.jqNode(maxOfId).datepicker("option", "maxDate", this.value);
+        }
+        minOfId = $(this).data('min-of');
+        if (minOfId) {
+            cw.jqNode(minOfId).datepicker("option", "minDate", this.value);
+        }
+    });
+}
+
 /**
  * .. function:: buildWidgets(root)
  *
--- a/web/formwidgets.py	Tue Dec 22 18:25:37 2015 +0100
+++ b/web/formwidgets.py	Thu Mar 26 11:13:12 2015 +0100
@@ -679,15 +679,37 @@
 class JQueryDatePicker(FieldWidget):
     """Use jquery.ui.datepicker to define a date picker. Will return the date as
     a unicode string.
+
+    You can couple DatePickers by using the min_of and/or max_of parameters.
+    The DatePicker identified by the value of min_of(/max_of) will force the user to
+    choose a date anterior(/posterior) to this DatePicker.
+
+    example:
+    start and end are two JQueryDatePicker and start must always be before end
+        affk.set_field_kwargs(etype, 'start_date', widget=JQueryDatePicker(min_of='end_date'))
+        affk.set_field_kwargs(etype, 'end_date', widget=JQueryDatePicker(max_of='start_date'))
+    That way, on change of end(/start) value a new max(/min) will be set for start(/end)
+    The invalid dates will be gray colored in the datepicker
     """
     needs_js = ('jquery.ui.js', )
     needs_css = ('jquery.ui.css',)
     default_size = 10
 
-    def __init__(self, datestr=None, **kwargs):
+    def __init__(self, datestr=None, min_of=None, max_of=None, **kwargs):
         super(JQueryDatePicker, self).__init__(**kwargs)
+        self.min_of = min_of
+        self.max_of = max_of
         self.value = datestr
 
+    def attributes(self, form, field):
+        form._cw.add_js('cubicweb.widgets.js')
+        attrs = super(JQueryDatePicker, self).attributes(form, field)
+        if self.max_of:
+            attrs['data-max-of'] = '%s-subject:%s' % (self.max_of, form.edited_entity.eid)
+        if self.min_of:
+            attrs['data-min-of'] = '%s-subject:%s' % (self.min_of, form.edited_entity.eid)
+        return attrs
+
     def _render(self, form, field, renderer):
         req = form._cw
         if req.lang != 'en':
@@ -695,11 +717,19 @@
         domid = field.dom_id(form, self.suffix)
         # XXX find a way to understand every format
         fmt = req.property_value('ui.date-format')
-        fmt = fmt.replace('%Y', 'yy').replace('%m', 'mm').replace('%d', 'dd')
-        req.add_onload(u'cw.jqNode("%s").datepicker('
-                       '{buttonImage: "%s", dateFormat: "%s", firstDay: 1,'
-                       ' showOn: "button", buttonImageOnly: true})' % (
-                           domid, req.uiprops['CALENDAR_ICON'], fmt))
+        picker_fmt = fmt.replace('%Y', 'yy').replace('%m', 'mm').replace('%d', 'dd')
+        max_date = min_date = None
+        if self.min_of:
+            current = getattr(form.edited_entity, self.min_of)
+            if current is not None:
+                max_date = current.strftime(fmt)
+        if self.max_of:
+            current = getattr(form.edited_entity, self.max_of)
+            if current is not None:
+                min_date = current.strftime(fmt)
+        req.add_onload(u'renderJQueryDatePicker("%s", "%s", "%s", %s, %s);'
+                       % (domid, req.uiprops['CALENDAR_ICON'], picker_fmt, json_dumps(min_date),
+                          json_dumps(max_date)))
         return self._render_input(form, field)
 
     def _render_input(self, form, field):