Projet

Général

Profil

0001-fields-add-date-times-visualisation-to-item-fields-5.patch

Frédéric Péters, 11 janvier 2021 20:58

Télécharger (11,5 ko)

Voir les différences:

Subject: [PATCH 1/4] fields: add date/times visualisation to item fields
 (#50035)

 wcs/data_sources.py                           |  11 +-
 wcs/fields.py                                 |   4 +
 wcs/qommon/form.py                            |   2 +
 wcs/qommon/static/js/qommon.admin.js          |  12 +-
 .../forms/widgets/select-datetimes.html       | 189 ++++++++++++++++++
 5 files changed, 214 insertions(+), 4 deletions(-)
 create mode 100644 wcs/qommon/templates/qommon/forms/widgets/select-datetimes.html
wcs/data_sources.py
68 68
                options.append(OptGroup(_('Cards')))
69 69
                options.extend(cards_options)
70 70

  
71
            nds_options = [(x.slug, x.name, x.slug, {'data-type': x.type}) for x in NamedDataSource.select()]
71
            nds_options = [(
72
                x.slug, x.name, x.slug, {
73
                    'data-type': x.type,
74
                    'data-maybe-datetimes': 'true' if x.maybe_datetimes() else 'false'})
75
                for x in NamedDataSource.select()]
72 76
            nds_options.sort(key=lambda x: misc.simplify(x[1]))
73 77
            if nds_options:
74 78
                options.append(OptGroup(_('Manually Configured Data Sources')))
......
76 80

  
77 81
        if len(options) > 1:
78 82
            options.append(OptGroup(_('Generic Data Sources')))
79
        options.append(('json', _('JSON URL'), 'json'))
83
        options.append(('json', _('JSON URL'), 'json', {'data-maybe-datetimes': 'true'}))
80 84
        if allow_jsonp:
81 85
            options.append(('jsonp', _('JSONP URL'), 'jsonp'))
82 86
        if allow_geojson:
......
391 395
            return True
392 396
        return False
393 397

  
398
    def maybe_datetimes(self):
399
        return self.type == 'json' and 'datetimes' in (self.data_source.get('value') or '')
400

  
394 401
    def migrate(self):
395 402
        changed = False
396 403

  
wcs/fields.py
1572 1572
            kwargs['select2'] = True
1573 1573
        elif display_mode == 'map':
1574 1574
            self.widget_class = MapMarkerSelectionWidget
1575
        elif display_mode == 'datetimes':
1576
            # SingleSelectHintWidget with custom template
1577
            kwargs['template-name'] = 'qommon/forms/widgets/select-datetimes.html'
1575 1578

  
1576 1579
    def get_display_value(self, value):
1577 1580
        data_source = data_sources.get_object(self.data_source)
......
1689 1692
                   ('radio', _('Radio buttons'), 'radio'),
1690 1693
                   ('autocomplete', _('Autocomplete'), 'autocomplete'),
1691 1694
                   ('map', _('Map (requires geographical data)'), 'map'),
1695
                   ('datetimes', _('Date/times'), 'datetimes'),
1692 1696
                  ]
1693 1697
        form.add(RadiobuttonsWidget, 'display_mode',
1694 1698
                title=_('Display Mode'),
wcs/qommon/form.py
1858 1858
    def __init__(self, name, value=None, **kwargs):
1859 1859
        self.options_with_attributes = kwargs.pop('options_with_attributes', None)
1860 1860
        self.select2 = kwargs.pop('select2', None)
1861
        if 'template-name' in kwargs:
1862
            self.template_name = kwargs.pop('template-name')
1861 1863
        super(SingleSelectHintWidget, self).__init__(name, value=value, **kwargs)
1862 1864

  
1863 1865
    def add_media(self):
wcs/qommon/static/js/qommon.admin.js
256 256
    }
257 257

  
258 258
    $('[type=radio][name=display_mode]').on('change', function() {
259
      // show everything
260
      $('select[name="data_source$type"] option').show();
261
      // then restrict
259 262
      if ($(this).val() == 'map') {
260 263
        $('input[name="data_mode"][value="data-source"]').click()
261 264
        $('select[name="data_source$type"] option:not([data-type="geojson"])').hide();
262 265
        if ($('select[name="data_source$type"] option:selected:visible').length == 0) {
263 266
          $('select[name="data_source$type"] option:visible').first().prop('selected', true);
264 267
        }
265
      } else {
266
        $('select[name="data_source$type"] option').show();
268
      }
269
      if ($(this).val() == 'datetimes') {
270
        $('input[name="data_mode"][value="data-source"]').click()
271
        $('select[name="data_source$type"] option:not([data-maybe-datetimes="true"])').hide();
272
        if ($('select[name="data_source$type"] option:selected:visible').length == 0) {
273
          $('select[name="data_source$type"] option:visible').first().prop('selected', true);
274
        }
267 275
      }
268 276
    });
269 277
    $('[type=radio][name=display_mode]:checked').trigger('change');
wcs/qommon/templates/qommon/forms/widgets/select-datetimes.html
1
{% extends "qommon/forms/widget.html" %}
2
{% load qommon i18n %}
3
{% block widget-control %}
4
<select style="display: none" id="form_{{widget.name}}" name="{{widget.name}}"
5
    {% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}"{% endfor %}>
6
  <option value="">---</option>
7
  {% for option in widget.get_options %}
8
    {% with datetime=option.options.datetime|parse_datetime %}
9
    <option{% for attr in option.attrs.items %} {{attr.0}}="{{attr.1}}"{% endfor %}
10
          data-weekday="{{ datetime|date:"l" }}"
11
          data-date="{{ datetime|date:"Y-m-d" }}"
12
          data-time="{{ datetime|date:"H:i" }}"
13
      >{{ option.description }}</option>
14
    {% endwith %}
15
  {% endfor %}
16
</select>
17
<div id="form_{{widget.name}}_table" class="meetings_table">
18
</div>
19
<script>
20
$(function() {
21
  var WEEKDAYS = ["{% trans "Sunday" %}", "{% trans "Monday" %}",
22
                  "{% trans "Tuesday" %}", "{% trans "Wednesday" %}",
23
                  "{% trans "Thursday" %}", "{% trans "Friday" %}",
24
                  "{% trans "Saturday" %}"];
25
  var $select = $('#form_{{widget.name}}');
26
  var $table = $('#form_{{widget.name}}_table');
27
  var column_count = 5;
28

  
29
  function fill_with_items(items) {
30
    $select.empty();
31
    $('<option value=""></option>').appendTo($select);
32
    for (var i=0; i<items.length; i++) {
33
      var $option = $('<option></option>', {value: items[i].id, text: items[i].text});
34
      if (items[i].disabled) {
35
          $option.prop('disabled', true);
36
      }
37
      var date = new Date(items[i].datetime);
38
      $option.attr('data-weekday', WEEKDAYS[date.getDay()]);
39
      $option.attr('data-date', items[i].datetime.slice(0, 10));
40
      $option.attr('data-time', items[i].datetime.slice(11, 16));
41
      $option.appendTo($select);
42
    }
43
  }
44

  
45
  $select.on('wcs:options-change', function(ev, data) {
46
    if (data !== undefined) {
47
      fill_with_items(data.items);
48
    }
49
  $table.empty();
50
  var options = $select.find('option');
51
  var current_date = null;
52
  var current_day_div = null;
53
  var current_offset = 0;
54
  var nb_days = 0;
55

  
56
  for (var i=0; i<options.length; i++) {
57
    var $option = $(options[i]);
58
    if ($option.attr('value') == '') continue;
59
    var option_date = $option.data('date');
60
    if (option_date !== current_date) {
61
      var day_label = $option.text().split(' ', 3).join(' ');
62
      if (Intl && Intl.DateTimeFormat) {
63
        // create day label from actual date, this works for event agendas.
64
        var date = new Date(option_date);
65
        var month = new Intl.DateTimeFormat('fr', {month: 'long'}).format(date);
66
        day_label = date.getDate() + ' ' + month + ' ' + date.getFullYear();
67
      }
68
      var weekday = $option.data('weekday');
69
      nb_days += 1;
70
      current_day_div = $('<div><div class="head">' + weekday + '<br>' + day_label + '</div></div>');
71
      current_day_div.appendTo($('#form_{{widget.name}}_table'));
72
      current_date = option_date;
73
    }
74
    var day_time = $option.data('time');
75
    var option_span = $('<span class="selectable" data-idx="' + i + '">' + day_time + '</span>').appendTo(current_day_div);
76
    if ($option.attr('disabled')) {
77
      $(option_span).addClass('disabled').removeClass('selectable');
78
    }
79
    if ($option.attr('selected')) {
80
      current_offset = nb_days - 1;
81
      $(option_span).addClass('on');
82
    }
83
  }
84
  var go_prev = $('<button class="prev">←</button>');
85
  var go_next = $('<button class="next">→</button>');
86
  go_prev.prependTo($('#form_{{widget.name}}_table'));
87
  go_next.appendTo($('#form_{{widget.name}}_table'));
88
  go_prev.on('click', function() {
89
    current_offset = Math.max(0, current_offset - 1);
90
    display(current_offset);
91
    return false;
92
  });
93
  go_next.on('click', function() {
94
    current_offset = Math.min(current_offset + 1, Math.max(0, nb_days-column_count));
95
    display(current_offset);
96
    return false;
97
  });
98

  
99
  function display(offset) {
100
    $('#form_{{widget.name}}_table > div').each(function(idx, elem) {
101
      if (idx >= offset && idx < offset+column_count) {
102
        $(elem).show();
103
      } else {
104
        $(elem).hide();
105
      }
106
    });
107
    if (go_prev.next().is(':visible')) {
108
      go_prev.prop('disabled', true);
109
    } else {
110
      go_prev.prop('disabled', null);
111
    }
112
    if (go_next.prev().is(':visible')) {
113
      go_next.prop('disabled', true);
114
    } else {
115
      go_next.prop('disabled', null);
116
    }
117
    current_offset = offset;
118
  }
119

  
120
  function set_layout() {
121
    if ($select.parents('form').width() > 600) {
122
      // desktop layout
123
      column_count = 5;
124
      $table.removeClass('mobile');
125
    } else {
126
      // mobile layout
127
      column_count = 1;
128
      $table.addClass('mobile');
129
    }
130
    display(current_offset);
131
    t1 = new Date();
132
  }
133
  set_layout();
134
  var layout_change_timeout_id = null;
135
  $(window).on('resize', function() {
136
    clearTimeout(layout_change_timeout_id);
137
    layout_change_timeout_id = setTimeout(set_layout, 200);
138
  });
139

  
140
  $('#form_{{widget.name}}_table span.selectable').on('click', function() {
141
   $('#form_{{widget.name}}_table span').removeClass('on');
142
   $(this).addClass('on');
143
   $('#form_{{widget.name}}').val($(options[$(this).data('idx')]).attr('value'));
144
  });
145
});
146
  $select.trigger('wcs:options-change');
147
});
148
</script>
149
{% if request.quixote_request.is_in_backoffice %}
150
<style>
151
div.meetings_table {
152
  margin-top: 1ex;
153
  display: flex;
154
  width: 100%;
155
}
156

  
157
div.meetings_table > div {
158
  flex: 0 1 auto;
159
  width: 20%;
160
  text-align: center;
161
  display: none;
162
}
163

  
164
div.meetings_table div span {
165
  display: block;
166
  cursor: pointer;
167
  padding: 0.3ex 0;
168
}
169

  
170
div.meetings_table div span.disabled {
171
  opacity: 0.3;
172
  cursor: not-allowed;
173
}
174

  
175
div.meetings_table div span.selectable.on {
176
  background: #215D9C;
177
  color: white;
178
}
179

  
180
div.meetings_table div.head {
181
  padding-bottom: 1ex;
182
}
183
</style>
184
{% endif %}
185
{% endblock %}
186

  
187
{% block widget-hint %}
188
{% if widget.hint %}<div class="hint">{{widget.hint}}</div>{% endif %}
189
{% endblock %}
0
-