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