|
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 |
|
-
|