319 lines
9.3 KiB
HTML
319 lines
9.3 KiB
HTML
{% extends "qommon/forms/widget.html" %}
|
|
{% load qommon i18n %}
|
|
{% block widget-control %}
|
|
|
|
<select
|
|
id="form_{{widget.name}}"
|
|
name="{{widget.name}}"
|
|
{% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}"{% endfor %}
|
|
style="display: none"
|
|
>
|
|
<option value="">---</option>
|
|
{% for option in widget.get_options %}
|
|
{% with datetime=option.options.date|parse_datetime %}
|
|
<option
|
|
{% for attr in option.attrs.items %} {{attr.0}}="{{attr.1}}"{% endfor %}
|
|
data-weeknumber="{{ option.options.date_weeknumber }}"
|
|
data-daynumber="{{ option.options.date_number }}"
|
|
data-weekdayindex="{{ option.options.date_weekdayindex }}"
|
|
data-month="{{ option.options.date_month }}"
|
|
data-status="{{ option.options.status }}"
|
|
>
|
|
{{ option.description }}
|
|
</option>
|
|
{% endwith %}
|
|
{% endfor %}
|
|
</select>
|
|
<div id="form_{{widget.name}}_calendar" class="ens-calendar is-hidden">
|
|
</div>
|
|
|
|
<script>
|
|
$(function() {
|
|
const prefix = "ens-calendar--";
|
|
const WEEKDAYS = ["{% trans "Monday" %}", "{% trans "Tuesday" %}",
|
|
"{% trans "Wednesday" %}", "{% trans "Thursday" %}",
|
|
"{% trans "Friday" %}", "{% trans "Saturday" %}",
|
|
"{% trans "Sunday" %}", ];
|
|
|
|
|
|
|
|
const $select = $('#form_{{widget.name}}');
|
|
let $options = $select.find('option');
|
|
const $calendar = $('#form_{{widget.name}}_calendar');
|
|
const $prev_btn = $('<button class="' + prefix + 'prev" role="button">←</button>');
|
|
const $next_btn = $('<button class="' + prefix + 'next" role="button">→</button>');
|
|
const activated_day_class = "on";
|
|
|
|
let calendar_days;
|
|
let $month_calendars;
|
|
let $day_btns;
|
|
let active_index = 0;
|
|
|
|
// map available data
|
|
// if static, data = $options
|
|
// if live, data = json
|
|
const define_calendar_days = function(data) {
|
|
const is$ = data instanceof $;
|
|
let days = data;
|
|
if (is$) {
|
|
days = $.makeArray($options);
|
|
}
|
|
const json_datas = days.map(function(day, idx){
|
|
const date = {};
|
|
date.value = (is$) ? day.value : day.id;
|
|
date.label = (is$) ? day.text : day.details;
|
|
date.number = (is$) ? day.dataset.daynumber : day.date_number ;
|
|
date.weekdayindex = parseInt((is$) ? day.dataset.weekdayindex : day.date_weekdayindex);
|
|
// French weekdayindex : sunday == 7 instead 0
|
|
date.weekdayindex = (date.weekdayindex == 0) ? 7 : date.weekdayindex;
|
|
date.weeknumber = (is$) ? day.dataset.weeknumber : day.date_weeknumber;
|
|
date.month = (is$) ? day.dataset.month : day.date_month;
|
|
date.idx = (is$) ? idx : idx + 1;
|
|
date.status = (is$) ? day.dataset.status : day.status;
|
|
return date;
|
|
}).filter(function(date){
|
|
return date.value;
|
|
});
|
|
return json_datas;
|
|
};
|
|
|
|
// render Calendar
|
|
const calendar_layout = function() {
|
|
// Return array of uniq key
|
|
const list_of = function (arr, key) {
|
|
return arr
|
|
.map(function(day){
|
|
return day[key];
|
|
})
|
|
.filter(function(day, idx, days) {
|
|
return days.indexOf(day) === idx;
|
|
});
|
|
}
|
|
|
|
const months = list_of(calendar_days, 'month');
|
|
|
|
// Generate thead markup of month table
|
|
const days_headers_tpl = function() {
|
|
let days = '';
|
|
const day = WEEKDAYS.forEach(function(el) {
|
|
days += ('<th class="' + prefix + 'weekday">' + el.slice(0, 3) + '</th>');
|
|
});
|
|
return '<thead>'+
|
|
'<tr class="' + prefix + 'weekdays">' + days + '</tr>' +
|
|
'</thead>';
|
|
};
|
|
|
|
// Generate tbody markup of month table
|
|
const days_body_tpl = function(month) {
|
|
|
|
const day_tpl = function(day) {
|
|
let day_markup = "";
|
|
if (day) {
|
|
const disabled = (day.status === "close") ? 'disabled' : "";
|
|
let selectedClass = "";
|
|
if ($options[day.idx].selected) {
|
|
selectedClass = activated_day_class;
|
|
// Change active_index to display correct month
|
|
active_index = months.indexOf(month);
|
|
}
|
|
day_markup += '<td class="' + prefix + 'day">' +
|
|
'<button ' +
|
|
'role="button"'+
|
|
'title="' + day.label + '"' +
|
|
'class="' + prefix + 'day-btn ' + selectedClass +'"' +
|
|
'data-option-idx="' + day.idx + '"' +
|
|
'data-status="' + day.status + '"' +
|
|
disabled + '>' +
|
|
day.number +
|
|
'</button>' +
|
|
'</td>';
|
|
} else {
|
|
day_markup += '<td class="' + prefix +'day is-empty"></td>'
|
|
}
|
|
return day_markup;
|
|
};
|
|
|
|
const days_of_month = calendar_days.filter(function(day) {
|
|
return day.month === month;
|
|
});
|
|
const weeks_of_month = list_of(days_of_month, "weeknumber");
|
|
|
|
let weeks_markup = '';
|
|
|
|
weeks_of_month.forEach(function(weeknumber) {
|
|
let days_markup = "";
|
|
const days_of_week = days_of_month.filter(function(day) {
|
|
return day.weeknumber === weeknumber;
|
|
});
|
|
// empty days before
|
|
const first_position = days_of_week[0].weekdayindex;
|
|
for (let i = 1; i < first_position; i++) {
|
|
days_markup += day_tpl();
|
|
}
|
|
// days of week
|
|
days_of_week.forEach(function(day) {
|
|
days_markup += day_tpl(day);
|
|
});
|
|
// empty days after
|
|
const last_position = days_of_week[days_of_week.length - 1].weekdayindex;
|
|
for (let i = last_position; i < 7; i++) {
|
|
days_markup += day_tpl();
|
|
}
|
|
// week raw
|
|
weeks_markup += '<tr class="' + prefix + 'week">' + days_markup + '</tr>';
|
|
});
|
|
return '<tbody>' + weeks_markup +'</tbody>';
|
|
};
|
|
|
|
// render month
|
|
const $month_tpl = function (month) {
|
|
const $month_calendar = $('<div class="ens-calendar--month is-hidden">' +
|
|
'<strong class="ens-calendar--head">' + month + '</strong>' +
|
|
'<table>' +
|
|
days_headers_tpl() +
|
|
days_body_tpl(month) +
|
|
'</table>' +
|
|
'</div>');
|
|
|
|
$month_calendars = $month_calendars.add($month_calendar);
|
|
$month_day_btns = $month_calendar.find('.' + prefix + 'day-btn');
|
|
$day_btns = $day_btns.add($month_day_btns);
|
|
|
|
return $month_calendar;
|
|
};
|
|
|
|
// render calendar
|
|
const render_calendar = function() {
|
|
$calendar.empty();
|
|
months.forEach(function(month){
|
|
$month_tpl(month).appendTo($calendar);
|
|
$prev_btn.add($next_btn).appendTo($calendar);
|
|
});
|
|
};
|
|
|
|
return render_calendar();
|
|
};
|
|
|
|
// Go to
|
|
const goto = function(index) {
|
|
$month_calendars.addClass('is-hidden');
|
|
$prev_btn.add($next_btn).prop('disabled', null);
|
|
max = $month_calendars.length - 1;
|
|
|
|
switch (index) {
|
|
case 0:
|
|
$prev_btn.prop('disabled', true); break;
|
|
case max :
|
|
$next_btn.prop('disabled', true); break;
|
|
}
|
|
|
|
$month_calendars.eq(index).removeClass('is-hidden');
|
|
active_index = index;
|
|
};
|
|
|
|
const init = function() {
|
|
$calendar.addClass('is-hidden');
|
|
$month_calendars = $();
|
|
$day_btns = $();
|
|
calendar_layout();
|
|
goto(active_index);
|
|
$calendar.removeClass('is-hidden');
|
|
// events
|
|
$prev_btn.click(function(e){
|
|
e.preventDefault();
|
|
goto(active_index - 1);
|
|
});
|
|
|
|
$next_btn.click(function(e){
|
|
e.preventDefault();
|
|
goto(active_index + 1);
|
|
});
|
|
|
|
$day_btns.click(function(e){
|
|
e.preventDefault();
|
|
$day_btns.removeClass(activated_day_class);
|
|
$options.eq(this.dataset.optionIdx).prop('selected', true);
|
|
$select.trigger('wcs:change');
|
|
$(this).addClass(activated_day_class);
|
|
});
|
|
};
|
|
|
|
// if Static
|
|
if ($options.length > 1) {
|
|
calendar_days = define_calendar_days($options);
|
|
init();
|
|
}
|
|
|
|
// if $select is filled live
|
|
$select.on('wcs:options-change', function(ev, data) {
|
|
if (!data) return;
|
|
calendar_days = define_calendar_days(data.items);
|
|
$('<option value=""></option>').prependTo($select);
|
|
$options = $select.find('option');
|
|
init();
|
|
$select.trigger('wcs:change');
|
|
});
|
|
|
|
});
|
|
</script>
|
|
{% if request.quixote_request.is_in_backoffice %}
|
|
<style>
|
|
.ens-calendar.is-hidden,
|
|
.ens-calendar--month.is-hidden {
|
|
display: none !important;
|
|
}
|
|
.ens-calendar {
|
|
position: relative;
|
|
width: 350px;
|
|
}
|
|
.ens-calendar--head {
|
|
text-align: center;
|
|
display: block;
|
|
height: 3em;
|
|
padding-left: 3em;
|
|
padding-right: 3em;
|
|
}
|
|
.ens-calendar--day-btn[data-status=open] {
|
|
color: green;
|
|
}
|
|
.ens-calendar--day-btn[data-status=open]:hover,
|
|
.ens-calendar--day-btn[data-status=open].on {
|
|
background-color: green;
|
|
color: white;
|
|
}
|
|
.ens-calendar--day-btn[data-status=partially-open] {
|
|
color: orange;
|
|
}
|
|
.ens-calendar--day-btn[data-status=partially-open]:hover,
|
|
.ens-calendar--day-btn[data-status=partially-open].on {
|
|
background-color: orange;
|
|
color: white;
|
|
}
|
|
.ens-calendar--day-btn[data-status=close] {
|
|
color: red;
|
|
}
|
|
.ens-calendar--day-btn[data-status=close]:hover,
|
|
.ens-calendar--day-btn[data-status=close].on {
|
|
background-color: red;
|
|
color: white;
|
|
}
|
|
|
|
.ens-calendar--next, .ens-calendar--prev {
|
|
position: absolute;
|
|
top: 0;
|
|
margin: 0;
|
|
}
|
|
.ens-calendar--next {
|
|
right: 0;
|
|
}
|
|
.ens-calendar--prev {
|
|
left: 0;
|
|
}
|
|
</style>
|
|
{% endif %}
|
|
{% endblock %}
|
|
|
|
{% block widget-hint %}
|
|
{% if widget.hint %}<div class="hint">{{widget.hint}}</div>{% endif %}
|
|
{% endblock %}
|