Projet

Général

Profil

0001-isere-cd38-add-calendar-booking-template-50311.patch

Thomas Jund, 09 février 2021 12:03

Télécharger (11,9 ko)

Voir les différences:

Subject: [PATCH] isere-cd38: add calendar booking  template (#50311)

 static/isere-cd38/_custom.scss                |  91 +++++
 .../forms/widgets/select--ens-calendar.html   | 316 ++++++++++++++++++
 2 files changed, 407 insertions(+)
 create mode 100644 templates/variants/isere-cd38/qommon/forms/widgets/select--ens-calendar.html
static/isere-cd38/_custom.scss
575 575
	}
576 576
}
577 577

  
578
// ENS CALENDAR WIDGET
579
.ens-calendar {
580
	$max-btn-size: 4rem;
581
	display: flex;
582
	max-width: $max-btn-size * 7;
583
	position: relative;
584

  
585
	&, &--month {
586
		.is-hidden {
587
			display: none !important;
588
		}
589
	}
590

  
591
	table, thead, tbody {
592
		display: block;
593
	}
594

  
595
	&--month {
596
		flex: 0 0 100%;
597
	}
598

  
599
	&--head {
600
		min-height: 3rem;
601
		padding-left: 3rem;
602
		padding-right: 3rem;
603
		text-transform: uppercase;
604
		font-weight: 600;
605
		display: flex;
606
		align-items: center;
607
		justify-content: center;
608
	}
609

  
610
	&--weekday {
611
		text-transform: uppercase;
612
		font-weight: 500;
613
	}
614

  
615
	&--weekdays,
616
	&--week {
617
		display: flex;
618
	}
619
	&--weekday,
620
	&--day {
621
		flex: 1 1 0;
622
		padding: 0.15rem;
623
	}
624
	div.gru-content &--day-btn {
625
		margin: 0;
626
		display: block;
627
		width: 100%;
628
		padding-left: 0;
629
		padding-right: 0;
630
		background-color: white;
631
		border: 1px solid;
632

  
633
		&[data-status=open] {
634
			color: green;
635
			&:hover, &.on {
636
				background-color: green;
637
				color: white;
638
			}
639
		}
640
		&[data-status=partially-open] {
641
			color: #D66909;
642
			&:hover, &.on {
643
				background-color: #D66909;
644
				color: white;
645
			}
646
		}
647
		&[data-status=close] {
648
			color: red;
649
			background-color: white;
650
			border: 1px solid;
651
			&:hover, &.on {
652
				background-color: red;
653
				color: white;
654
			}
655
		}
656
	}
657
	div.gru-content &--next, div.gru-content &--prev {
658
		position: absolute;
659
		top: 0;
660
		margin: 0;
661
	}
662
	&--next {
663
		right: 0;
664
	}
665
	&--prev {
666
		left: 0;
667
	}
668
}
578 669

  
579 670

  
580 671
//
templates/variants/isere-cd38/qommon/forms/widgets/select--ens-calendar.html
1
{% extends "qommon/forms/widget.html" %}
2
{% load qommon i18n %}
3
{% block widget-control %}
4

  
5
<select
6
  id="form_{{widget.name}}"
7
  name="{{widget.name}}"
8
  {% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}"{% endfor %}
9
  style="display: none"
10
>
11
  <option value="">---</option>
12
  {% for option in widget.get_options %}
13
    {% with datetime=option.options.date|parse_datetime %}
14
    <option
15
        {% for attr in option.attrs.items %} {{attr.0}}="{{attr.1}}"{% endfor %}
16
        data-weeknumber="{{ option.options.date_weeknumber }}"
17
        data-daynumber="{{ option.options.date_number }}"
18
        data-weekdayindex="{{ option.options.date_weekdayindex }}"
19
        data-month="{{ option.options.date_month }}"
20
        data-status="{{ option.options.status }}"
21
      >
22
        {{ option.description }}
23
      </option>
24
    {% endwith %}
25
  {% endfor %}
26
</select>
27
<div id="form_{{widget.name}}_calendar" class="ens-calendar is-hidden">
28
</div>
29

  
30
<script>
31
$(function() {
32
  const prefix = "ens-calendar--";
33
  const WEEKDAYS = ["{% trans "Monday" %}", "{% trans "Tuesday" %}",
34
                    "{% trans "Wednesday" %}", "{% trans "Thursday" %}",
35
                    "{% trans "Friday" %}", "{% trans "Saturday" %}",
36
                    "{% trans "Sunday" %}", ];
37

  
38

  
39

  
40
  const $select = $('#form_{{widget.name}}');
41
  let $options = $select.find('option');
42
  const $calendar = $('#form_{{widget.name}}_calendar');
43
  const $prev_btn = $('<button class="'  + prefix + 'prev" role="button">←</button>');
44
  const $next_btn = $('<button class="'  + prefix + 'next" role="button">→</button>');
45
  const activated_day_class = "on";
46

  
47
  let calendar_days;
48
  let $month_calendars;
49
  let $day_btns;
50
  let active_index = 0;
51

  
52
  // map available data
53
  // if static, data = $options
54
  // if live, data = json
55
  const define_calendar_days = function(data) {
56
    const is$ = data instanceof $;
57
    let days = data;
58
    if (is$) {
59
      days = $.makeArray($options);
60
    }
61
    const json_datas = days.map(function(day, idx){
62
      const date = {};
63
      date.value = (is$) ? day.value : day.id;
64
      date.label = (is$) ? day.text : day.details;
65
      date.number = (is$) ? day.dataset.daynumber : day.date_number ;
66
      date.weekdayindex = (is$) ? day.dataset.weekdayindex : day.date_weekdayindex;
67
      date.weeknumber = (is$) ? day.dataset.weeknumber : day.date_weeknumber;
68
      date.month = (is$) ? day.dataset.month : day.date_month;
69
      date.idx = (is$) ? idx : idx + 1;
70
      date.status = (is$) ? day.dataset.status : day.status;
71
      return date;
72
    }).filter(function(date){
73
      return date.value;
74
    });
75
    return json_datas;
76
  };
77

  
78
  // render Calendar
79
  const calendar_layout = function() {
80
    // Return array of uniq key
81
    const list_of = function (arr, key) {
82
      return arr
83
        .map(function(day){
84
          return day[key];
85
        })
86
        .filter(function(day, idx, days) {
87
          return days.indexOf(day) === idx;
88
        });
89
    }
90

  
91
    const months = list_of(calendar_days, 'month');
92

  
93
    // Generate thead markup of month table
94
    const days_headers_tpl = function() {
95
      let days = '';
96
      const day = WEEKDAYS.forEach(function(el) {
97
        days += ('<th class="' + prefix + 'weekday">' + el.slice(0, 3) + '</th>');
98
      });
99
      return '<thead>'+
100
                '<tr class="' + prefix + 'weekdays">' + days + '</tr>' +
101
              '</thead>';
102
    };
103

  
104
    // Generate tbody markup of month table
105
    const days_body_tpl = function(month) {
106

  
107
      const day_tpl = function(day) {
108
        let day_markup = "";
109
        if (day) {
110
          const disabled = (day.status === "close") ? 'disabled' : "";
111
          let selectedClass = "";
112
          if ($options[day.idx].selected) {
113
            selectedClass = activated_day_class;
114
            // Change active_index to display correct month
115
            active_index = months.indexOf(month);
116
          }
117
          day_markup += '<td class="' + prefix + 'day">' +
118
                          '<button ' +
119
                            'role="button"'+
120
                            'title="' + day.label + '"' +
121
                            'class="' + prefix + 'day-btn ' + selectedClass +'"' +
122
                            'data-option-idx="' + day.idx + '"' +
123
                            'data-status="' + day.status + '"' +
124
                            disabled + '>' +
125
                            day.number +
126
                          '</button>' +
127
                        '</td>';
128
        } else {
129
          day_markup += '<td class="' + prefix +'day is-empty"></td>'
130
        }
131
        return day_markup;
132
      };
133

  
134
      const days_of_month = calendar_days.filter(function(day) {
135
          return day.month === month;
136
      });
137
      const weeks_of_month = list_of(days_of_month, "weeknumber");
138

  
139
      let weeks_markup = '';
140

  
141
      weeks_of_month.forEach(function(weeknumber) {
142
        let days_markup = "";
143
        const days_of_week = days_of_month.filter(function(day) {
144
          return day.weeknumber === weeknumber;
145
        });
146
        // empty days before
147
        const first_position = parseInt(days_of_week[0].weekdayindex);
148
        for (let i = 1; i < first_position; i++) {
149
          days_markup += day_tpl();
150
        }
151
        // days of week
152
        days_of_week.forEach(function(day) {
153
          days_markup += day_tpl(day);
154
        });
155
        // empty days after
156
        const last_position = parseInt(days_of_week[days_of_week.length - 1].weekdayindex);
157
        if (last_position)  {
158
          for (let i = last_position; i < 7; i++) {
159
            days_markup += day_tpl();
160
          }
161
        }
162
        // week raw
163
        weeks_markup += '<tr class="' + prefix + 'week">' + days_markup + '</tr>';
164
      });
165
      return '<tbody>' + weeks_markup +'</tbody>';
166
    };
167

  
168
    // render month
169
    const $month_tpl = function (month) {
170
      const $month_calendar = $('<div class="ens-calendar--month is-hidden">' +
171
          '<strong class="ens-calendar--head">' + month + '</strong>' +
172
          '<table>' +
173
            days_headers_tpl() +
174
            days_body_tpl(month) +
175
          '</table>' +
176
        '</div>');
177

  
178
      $month_calendars = $month_calendars.add($month_calendar);
179
      $month_day_btns = $month_calendar.find('.' + prefix + 'day-btn');
180
      $day_btns = $day_btns.add($month_day_btns);
181

  
182
      return $month_calendar;
183
    };
184

  
185
    // render calendar
186
    const render_calendar = function() {
187
      $calendar.empty();
188
      months.forEach(function(month){
189
        $month_tpl(month).appendTo($calendar);
190
        $prev_btn.add($next_btn).appendTo($calendar);
191
      });
192
    };
193

  
194
    return render_calendar();
195
  };
196

  
197
  // Go to
198
  const goto = function(index) {
199
    $month_calendars.addClass('is-hidden');
200
    $prev_btn.add($next_btn).prop('disabled', null);
201
    max = $month_calendars.length - 1;
202

  
203
    switch (index) {
204
      case 0:
205
        $prev_btn.prop('disabled', true); break;
206
      case max :
207
        $next_btn.prop('disabled', true); break;
208
    }
209

  
210
    $month_calendars.eq(index).removeClass('is-hidden');
211
    active_index = index;
212
  };
213

  
214
  const init = function() {
215
    $calendar.addClass('is-hidden');
216
    $month_calendars = $();
217
    $day_btns = $();
218
    calendar_layout();
219
    goto(active_index);
220
    $calendar.removeClass('is-hidden');
221
    // events
222
    $prev_btn.click(function(e){
223
      e.preventDefault();
224
      goto(active_index - 1);
225
    });
226

  
227
    $next_btn.click(function(e){
228
      e.preventDefault();
229
      goto(active_index + 1);
230
    });
231

  
232
    $day_btns.click(function(e){
233
      e.preventDefault();
234
      $day_btns.removeClass(activated_day_class);
235
      $options.eq(this.dataset.optionIdx).prop('selected', true);
236
      $(this).addClass(activated_day_class);
237
    });
238
  };
239

  
240
  // if Static
241
  if ($options.length > 1) {
242
    calendar_days = define_calendar_days($options);
243
    init();
244
  }
245

  
246
  // if $select is filled live
247
  $select.on('wcs:options-change', function(ev, data) {
248
    if (!data) return;
249
    calendar_days = define_calendar_days(data.items);
250
    $('<option value=""></option>').prependTo($select);
251
    $options = $select.find('option');
252
    init();
253
  });
254

  
255
});
256
</script>
257
{% if request.quixote_request.is_in_backoffice %}
258
<style>
259
.ens-calendar.is-hidden,
260
.ens-calendar--month.is-hidden {
261
  display: none !important;
262
}
263
.ens-calendar {
264
  position: relative;
265
  width: 350px;
266
}
267
.ens-calendar--head {
268
  text-align: center;
269
  display: block;
270
  height: 3em;
271
  padding-left: 3em;
272
  padding-right: 3em;
273
}
274
.ens-calendar--day-btn[data-status=open] {
275
  color: green;
276
}
277
.ens-calendar--day-btn[data-status=open]:hover,
278
.ens-calendar--day-btn[data-status=open].on {
279
  background-color: green;
280
  color: white;
281
}
282
.ens-calendar--day-btn[data-status=partially-open] {
283
  color: orange;
284
}
285
.ens-calendar--day-btn[data-status=partially-open]:hover,
286
.ens-calendar--day-btn[data-status=partially-open]:on {
287
  background-color: orange;
288
  color: white;
289
}
290
.ens-calendar--day-btn[data-status=close] {
291
  color: red;
292
}
293
.ens-calendar--day-btn[data-status=close]:hover,
294
.ens-calendar--day-btn[data-status=close].on {
295
  background-color: red;
296
  color: white;
297
}
298

  
299
.ens-calendar--next, .ens-calendar--prev {
300
  position: absolute;
301
  top: 0;
302
  margin: 0;
303
}
304
.ens-calendar--next {
305
  right: 0;
306
}
307
.ens-calendar--prev {
308
  left: 0;
309
}
310
</style>
311
{% endif %}
312
{% endblock %}
313

  
314
{% block widget-hint %}
315
{% if widget.hint %}<div class="hint">{{widget.hint}}</div>{% endif %}
316
{% endblock %}
0
-