Projet

Général

Profil

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

Thomas Jund, 05 février 2021 16:00

Télécharger (10,6 ko)

Voir les différences:

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

 static/isere-cd38/_custom.scss                |  75 +++++
 .../forms/widgets/select--ens-calendar.html   | 282 ++++++++++++++++++
 2 files changed, 357 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

  
631
		&[data-status=open] {
632
			background-color: green;
633
		}
634
		&[data-status=partially-open] {
635
			background-color: $gold;
636
		}
637
		&[data-status=close] {
638
			background-color: red;
639
		}
640
	}
641
	div.gru-content &--next, div.gru-content &--prev {
642
		position: absolute;
643
		top: 0;
644
		margin: 0;
645
	}
646
	&--next {
647
		right: 0;
648
	}
649
	&--prev {
650
		left: 0;
651
	}
652
}
578 653

  
579 654

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

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

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

  
48
  // map $options
49
  const calendar_days = (function() {
50
    const options = $.makeArray($options);
51
    const json_datas = options.map(function(option, idx){
52
        if (!option.value) return;
53
        const day = {};
54
        day.label = option.text;
55
        day.day_number = option.dataset.daynumber;
56
        day.day = option.dataset.weekday;
57
        day.day_index = option.dataset.weekdayindex;
58
        day.week_number = option.dataset.weeknumber;
59
        day.month = option.dataset.month + " " + option.dataset.year;
60
        day.idx = idx;
61
        day.status = option.dataset.status;
62
        return day;
63
    });
64
    return json_datas;
65
  })();
66

  
67
  // render Calendar
68
  const calendar_layout = function() {
69

  
70
    // Return array of uniq key
71
    const list_of = function (arr, key) {
72
      return arr
73
        .map(function(day){
74
          if ( day ) {
75
            return day[key];
76
          }
77
        })
78
        .filter(function(day, idx, days) {
79
          return days.indexOf(day) === idx;
80
        });
81
    }
82

  
83
    const months = list_of(calendar_days, 'month');
84

  
85
    // Generate thead markup of month table
86
    const days_headers_tpl = function() {
87
      let days = '';
88
      const day = WEEKDAYS.forEach(function(el) {
89
        days += ('<th class="' + prefix + 'weekday">' + el.slice(0, 3) + '</th>');
90
      });
91
      return '<thead>'+
92
                '<tr class="' + prefix + 'weekdays">' + days + '</tr>' +
93
              '</thead>';
94
    };
95

  
96
    // Generate tbody markup of month table
97
    const days_body_tpl = function(month) {
98
      const day_tpl = function(day) {
99
        let day_markup = "";
100
        if (day) {
101
          const disabled = (day.status === "close") ? 'disabled' : "";
102
          day_markup += '<td class="' + prefix + 'day">' +
103
                          '<button ' +
104
                            'role="button"'+
105
                            'title="' + day.label + '"' +
106
                            'class="' + prefix + 'day-btn"' +
107
                            'data-option-idx="' + day.idx + '"' +
108
                            'data-dayweek-idx="' + day.day_index + '"' +
109
                            'data-status="' + day.status + '" ' +
110
                            'data-status="' + day.status + '"' +
111
                            disabled + '>' +
112
                            day.day_number +
113
                          '</button>' +
114
                        '</td>';
115
        } else {
116
          day_markup += '<td class="' + prefix +'day is-empty"></td>'
117
        }
118
        return day_markup;
119
      };
120

  
121
      const days_of_month = calendar_days.filter(function(day) {
122
        if (day)
123
          return day.month === month;
124
      });
125
      const weeks_of_month = list_of(days_of_month, "week_number");
126

  
127
      let weeks_markup = '';
128

  
129
      weeks_of_month.forEach(function(week_number) {
130
        let days_markup = "";
131
        const days_of_week = days_of_month.filter(function(day) {
132
          return day.week_number === week_number;
133
        });
134
        // empty days before
135
        const first_position = parseInt(days_of_week[0].day_index);
136
        for (let i = 1; i < first_position; i++) {
137
          days_markup += day_tpl();
138
        }
139
        // days of week
140
        days_of_week.forEach(function(day) {
141
          days_markup += day_tpl(day);
142
        });
143
        // empty days after
144
        const last_position = parseInt(days_of_week[days_of_week.length - 1].day_index);
145
        if (last_position)  {
146
          for (let i = last_position; i < 7; i++) {
147
            days_markup += day_tpl();
148
          }
149
        }
150
        // week raw
151
        weeks_markup += '<tr class="' + prefix + 'week">' + days_markup + '</tr>';
152
      });
153
      return '<tbody>' + weeks_markup +'</tbody>';
154
    };
155

  
156
    // render month
157
    const $month_tpl = function (month) {
158
      const $month_calendar = $('<div class="ens-calendar--month is-hidden">' +
159
          '<strong class="ens-calendar--head">' + month + '</strong>' +
160
          '<table>' +
161
            days_headers_tpl() +
162
            days_body_tpl(month) +
163
          '</table>' +
164
        '</div>');
165

  
166
      $month_calendars = $month_calendars.add($month_calendar);
167
      $month_day_btns = $month_calendar.find('.' + prefix + 'day-btn');
168
      $day_btns = $day_btns.add($month_day_btns);
169

  
170
      return $month_calendar;
171
    };
172

  
173
    // render calendar
174
    const render_calendar = function() {
175
      months.forEach(function(month){
176
        if (!month) return;
177
        $month_tpl(month).appendTo($calendar);
178
        $prev_btn.add($next_btn).appendTo($calendar);
179
      });
180
    };
181

  
182
    return render_calendar();
183
  };
184

  
185
  // Go to
186
  const goto = function(index) {
187
    $month_calendars.addClass('is-hidden');
188
    $prev_btn.add($next_btn).prop('disabled', null);
189
    max = $month_calendars.length - 1;
190

  
191
    switch (index) {
192
      case 0:
193
        $prev_btn.prop('disabled', true); break;
194
      case max :
195
        $next_btn.prop('disabled', true); break;
196
    }
197

  
198
    $month_calendars.eq(index).removeClass('is-hidden');
199
    active_index = index;
200
  };
201

  
202
  const init = (function() {
203
    calendar_layout();
204
    goto(active_index);
205
    $calendar.removeClass('is-hidden');
206

  
207
    // events
208
    $prev_btn.click(function(e){
209
      e.preventDefault();
210
      goto(active_index - 1);
211
    });
212

  
213
    $next_btn.click(function(e){
214
      e.preventDefault();
215
      goto(active_index + 1);
216
    });
217

  
218
    $day_btns.click(function(e){
219
      e.preventDefault();
220
      $options.eq(this.dataset.optionIdx).prop('selected', true);
221
    });
222

  
223
  })();
224
});
225
</script>
226
{% if request.quixote_request.is_in_backoffice %}
227
<style>
228
.ens-calendar.is-hidden,
229
.ens-calendar--month.is-hidden {
230
  display: none !important;
231
}
232
.ens-calendar {
233
  position: relative;
234
  width: 350px;
235
}
236
.ens-calendar--head {
237
  text-align: center;
238
  display: block;
239
  height: 3em;
240
  padding-left: 3em;
241
  padding-right: 3em;
242
}
243
.ens-calendar--day-btn[data-status=open] {
244
  color: green;
245
}
246
.ens-calendar--day-btn[data-status=open]:hover {
247
  background-color: green;
248
  color: white;
249
}
250
.ens-calendar--day-btn[data-status=partially-open] {
251
  color: orange;
252
}
253
.ens-calendar--day-btn[data-status=partially-open]:hover {
254
  background-color: orange;
255
  color: white;
256
}
257
.ens-calendar--day-btn[data-status=close] {
258
  color: red;
259
}
260
.ens-calendar--day-btn[data-status=close]:hover {
261
  background-color: red;
262
  color: white;
263
}
264

  
265
.ens-calendar--next, .ens-calendar--prev {
266
  position: absolute;
267
  top: 0;
268
  margin: 0;
269
}
270
.ens-calendar--next {
271
  right: 0;
272
}
273
.ens-calendar--prev {
274
  left: 0;
275
}
276
</style>
277
{% endif %}
278
{% endblock %}
279

  
280
{% block widget-hint %}
281
{% if widget.hint %}<div class="hint">{{widget.hint}}</div>{% endif %}
282
{% endblock %}
0
-