New DateTimePicker
This commit is contained in:
parent
d798fdfa01
commit
9ac7b5c38c
4 changed files with 259 additions and 18 deletions
|
@ -4,17 +4,13 @@
|
||||||
|
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
{# DateTimePicker #}
|
{# DateTimePicker #}
|
||||||
<script src={% static 'vendor/datepicker/datetimepicker.js' %}></script>
|
<script src="{% static 'vendor/datetimepicker/picker.js' %}"></script>
|
||||||
<link rel="stylesheet" href="{% static 'vendor/datepicker/datetimepicker.css' %}">
|
<link rel="stylesheet" href="{% static 'vendor/datetimepicker/picker.css' %}">
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function($) {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
$('#id_start_date').datetimepicker({
|
new DateTimePicker('input[name=start_date]', {});
|
||||||
format: 'Y-m-d H:i'
|
new DateTimePicker('input[name=end_date]', {});
|
||||||
});
|
|
||||||
$('#id_end_date').datetimepicker({
|
|
||||||
format: 'Y-m-d H:i'
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -4,17 +4,13 @@
|
||||||
|
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
{# DateTimePicker #}
|
{# DateTimePicker #}
|
||||||
<script src={% static 'vendor/datepicker/datetimepicker.js' %}></script>
|
<script src="{% static 'vendor/datetimepicker/picker.js' %}"></script>
|
||||||
<link rel="stylesheet" href="{% static 'vendor/datepicker/datetimepicker.css' %}">
|
<link rel="stylesheet" href="{% static 'vendor/datetimepicker/picker.css' %}">
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function($) {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
$('#id_start_date').datetimepicker({
|
new DateTimePicker('input[name=start_date]', {});
|
||||||
format: 'Y-m-d H:i'
|
new DateTimePicker('input[name=end_date]', {});
|
||||||
});
|
|
||||||
$('#id_end_date').datetimepicker({
|
|
||||||
format: 'Y-m-d H:i'
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
29
shared/static/vendor/datetimepicker/picker.css
vendored
Normal file
29
shared/static/vendor/datetimepicker/picker.css
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
.date-tag {
|
||||||
|
height: 2em;
|
||||||
|
width: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-tag:not(.is-selected):hover {
|
||||||
|
background-color: #6681b2 !important;
|
||||||
|
color: white !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-selected {
|
||||||
|
background-color: #192131 !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-selected:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.out-range {
|
||||||
|
background-color: white;
|
||||||
|
color: #7a7a7a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.out-range:hover {
|
||||||
|
background-color: #;
|
||||||
|
color: #7a7a7a;
|
||||||
|
}
|
220
shared/static/vendor/datetimepicker/picker.js
vendored
Normal file
220
shared/static/vendor/datetimepicker/picker.js
vendored
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
const _days = {
|
||||||
|
'fr': ['Lun.', 'Mar.', 'Mer.', 'Jeu.', 'Ven.', 'Sam.', 'Dim.'],
|
||||||
|
'en': ['Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.', 'Sun.'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const _months = {
|
||||||
|
'fr': ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
|
||||||
|
'en': ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
||||||
|
}
|
||||||
|
|
||||||
|
function zero(value) {
|
||||||
|
return value < 10 ? `0${value}` : `${value}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function datesEqual(date1, date2) {
|
||||||
|
return (date1.getFullYear() == date2.getFullYear()) && (date1.getMonth() == date2.getMonth()) && (date1.getDate() == date2.getDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDefaults(obj, objDefaults) {
|
||||||
|
const keys = Object.keys(objDefaults);
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(obj, keys[i])) {
|
||||||
|
obj[keys[i]] = objDefaults[keys[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DateTimePicker {
|
||||||
|
constructor(selector, config) {
|
||||||
|
if (!selector) {
|
||||||
|
throw TypeError('Selector required to construct a DateTimePicker');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.target = document.querySelector(selector);
|
||||||
|
if (!this.target) {
|
||||||
|
throw Error(`The selector '{selector}' doesn't give any results`);
|
||||||
|
}
|
||||||
|
this.target.addEventListener('click', () => {
|
||||||
|
document.documentElement.classList.add('is-clipped');
|
||||||
|
this.modal.classList.add('is-active');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!['fr', 'en'].includes(config.lang)) {
|
||||||
|
config.lang = 'fr';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.config = setDefaults(config || {}, DateTimePicker.defaultConfig);
|
||||||
|
this.date = DateTimePicker.parseDate(this.target.value) || new Date();
|
||||||
|
// let _date = this.date || new Date();
|
||||||
|
this._selected = undefined;
|
||||||
|
|
||||||
|
// Création du modal
|
||||||
|
this.modal = document.createElement('div');
|
||||||
|
this.modal.classList.add('modal');
|
||||||
|
this.modal.innerHTML = (`<div class="modal-background"></div><div class="modal-card"><header class="modal-card-head"><div class="field is-grouped has-addons is-flex-grow-1"><div class="control"><a class="button"><span class="icon"><i class="fas fa-chevron-left"></i></span></a></div><div class="control is-expanded"><a class="button is-fullwidth"></a></div><div class="control"><a class="button"><span class="icon"><i class="fas fa-chevron-right"></i></span></a></div></div></header><section class="modal-card-body"><div class="columns is-centered"><div class="column is-narrow"></div></div></section><footer class="modal-card-foot"><div class="field is-horizontal is-flex-grow-1"><div class="field-label is-normal"><label class="label">Horaire :</label></div><div class="field-body"><div class="field has-addons"><div class="control"><div class="select is-left"><select><option>00</option><option>01</option><option>02</option><option>03</option><option>04</option><option>05</option><option>06</option><option>07</option><option>08</option><option>09</option><option>10</option><option>11</option><option>12</option><option>13</option><option>14</option><option>15</option><option>16</option><option>17</option><option>18</option><option>19</option><option>20</option><option>21</option><option>22</option><option>23</option></select></div></div><div class="control"><button class="button is-static has-text-primary"><b>h</b></button></div></div><div class="field has-addons"><div class="control"><div class="select"><select><option>00</option><option>05</option><option>10</option><option>15</option><option>20</option><option>25</option><option>30</option><option>35</option><option>40</option><option>45</option><option>50</option><option>55</option></select></div></div><div class="control"><button class="button is-static has-text-primary"><b>min</b></button></div></div><div class="field is-expanded"><button class="button is-primary is-fullwidth button-close">Valider</button></div></div></div></footer></div><button class="modal-close is-large" aria-label="close"></button>`);
|
||||||
|
let _controls = this.modal.querySelectorAll('header a.button');
|
||||||
|
this._leftArrow = _controls[0];
|
||||||
|
this._menu = _controls[1];
|
||||||
|
this._rightArrow = _controls[2];
|
||||||
|
|
||||||
|
this._rightArrow.addEventListener('click', () => {
|
||||||
|
if (this._beginning.getMonth() == 11) {
|
||||||
|
this._beginning.setFullYear(this._beginning.getFullYear() + 1, 0, 1);
|
||||||
|
} else {
|
||||||
|
this._beginning.setMonth(this._beginning.getMonth() + 1, 1);
|
||||||
|
}
|
||||||
|
this.showCalendarDays(this._beginning);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._leftArrow.addEventListener('click', () => {
|
||||||
|
if (this._beginning.getMonth() == 0) {
|
||||||
|
this._beginning.setFullYear(this._beginning.getFullYear() - 1, 11, 1);
|
||||||
|
} else {
|
||||||
|
this._beginning.setMonth(this._beginning.getMonth() - 1, 1);
|
||||||
|
}
|
||||||
|
this.showCalendarDays(this._beginning);
|
||||||
|
});
|
||||||
|
|
||||||
|
let _selects = this.modal.querySelectorAll('footer select');
|
||||||
|
this._hour = _selects[0];
|
||||||
|
this._minutes = _selects[1];
|
||||||
|
|
||||||
|
this._hour.addEventListener('change', () => {
|
||||||
|
this.date.setHours(this._hour.value);
|
||||||
|
this.updateTarget();
|
||||||
|
});
|
||||||
|
|
||||||
|
this._minutes.addEventListener('change', () => {
|
||||||
|
this.date.setMinutes(this._minutes.value);
|
||||||
|
this.updateTarget();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(this.modal);
|
||||||
|
|
||||||
|
this._beginning = new Date(this.date.getFullYear(), this.date.getMonth(), 1);
|
||||||
|
this.initTime();
|
||||||
|
this.showCalendarDays(this._beginning);
|
||||||
|
this.updateTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
showCalendarDays(_beginning) {
|
||||||
|
const days = _days[this.config.lang];
|
||||||
|
const months = _months[this.config.lang];
|
||||||
|
|
||||||
|
this._menu.innerHTML = `<b>${months[_beginning.getMonth()]} ${_beginning.getFullYear()}</b>`;
|
||||||
|
|
||||||
|
var _body = this.modal.querySelector('.modal-card section .column');
|
||||||
|
_body.innerHTML = (`
|
||||||
|
<table class="table has-text-centered is-narrow">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>${days[0]}</th>
|
||||||
|
<th>${days[1]}</th>
|
||||||
|
<th>${days[2]}</th>
|
||||||
|
<th>${days[3]}</th>
|
||||||
|
<th>${days[4]}</th>
|
||||||
|
<th>${days[5]}</th>
|
||||||
|
<th>${days[6]}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Création du tableau
|
||||||
|
const _dayLength = 86400000;
|
||||||
|
var day = new Date(_beginning.getTime() - _dayLength * ((_beginning.getDay() + 6) % 7));
|
||||||
|
|
||||||
|
var _tbody = _body.querySelector('tbody');
|
||||||
|
for (var i = 0; i < 6; i++) {
|
||||||
|
if (i == 0 || day.getMonth() <= _beginning.getMonth()) {
|
||||||
|
let row = document.createElement('tr');
|
||||||
|
for (var j = 0; j < 7; j++) {
|
||||||
|
let cell = document.createElement('td');
|
||||||
|
let _otherMonth = day.getMonth() != _beginning.getMonth();
|
||||||
|
|
||||||
|
cell.innerHTML = `<span class="tag is-large${_otherMonth ? ' is-white has-text-grey' : ''} date-tag">${day.getDate()}</span>`;
|
||||||
|
row.appendChild(cell);
|
||||||
|
|
||||||
|
let _tag = cell.firstChild;
|
||||||
|
if (datesEqual(day, new Date())) {
|
||||||
|
_tag.classList.add('is-primary', 'is-light');
|
||||||
|
}
|
||||||
|
if (datesEqual(day, this.date)) {
|
||||||
|
this._selected = _tag;
|
||||||
|
_tag.classList.add('is-selected');
|
||||||
|
}
|
||||||
|
_tag.dataset.date = DateTimePicker.dayValue(day);
|
||||||
|
|
||||||
|
_tag.addEventListener('click', () => {
|
||||||
|
this.date = DateTimePicker.parseDay(_tag.dataset.date);
|
||||||
|
this.date.setHours(this._hour.value, this._minutes.value);
|
||||||
|
|
||||||
|
if (this.date.getMonth() != this._beginning.getMonth()) {
|
||||||
|
this._beginning.setFullYear(this.date.getFullYear(), this.date.getMonth(), 1);
|
||||||
|
this.showCalendarDays(this._beginning);
|
||||||
|
} else {
|
||||||
|
if (this._selected != undefined) {
|
||||||
|
this._selected.classList.remove('is-selected');
|
||||||
|
}
|
||||||
|
_tag.classList.add('is-selected');
|
||||||
|
this._selected = _tag;
|
||||||
|
}
|
||||||
|
this.updateTarget();
|
||||||
|
});
|
||||||
|
|
||||||
|
day = new Date(day.getTime() + _dayLength);
|
||||||
|
}
|
||||||
|
_tbody.appendChild(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showCalendarMonths() {
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTarget() {
|
||||||
|
this.target.value = DateTimePicker.dateValue(this.date);
|
||||||
|
}
|
||||||
|
|
||||||
|
initTime() {
|
||||||
|
let hour = zero(this.date.getHours());
|
||||||
|
let _minutes = this.date.getMinutes();
|
||||||
|
let minutes = zero(_minutes - (_minutes % 5));
|
||||||
|
this._hour.value = hour;
|
||||||
|
this._minutes.value = minutes;
|
||||||
|
this.date.setMinutes(minutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static views = ['days', 'months', 'years'];
|
||||||
|
|
||||||
|
static defaultConfig = {
|
||||||
|
view: 'days',
|
||||||
|
showTime: false,
|
||||||
|
lang: 'fr',
|
||||||
|
}
|
||||||
|
|
||||||
|
static formatDT = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) (?<hour>\d{2}):(?<minutes>\d{2})/;
|
||||||
|
static formatD = /(?<year>\d{4})-(?<month>\d{1,2})-(?<day>\d{1,2})/;
|
||||||
|
|
||||||
|
static parseDate(value) {
|
||||||
|
const _vals = DateTimePicker.formatDT.exec(value);
|
||||||
|
return _vals === null ? undefined : new Date(_vals[1], _vals[2] - 1, _vals[3], _vals[4], _vals[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static parseDay(value) {
|
||||||
|
const _vals = DateTimePicker.formatD.exec(value);
|
||||||
|
return _vals === null ? undefined : new Date(_vals[1], _vals[2] - 1, _vals[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dateValue(value) {
|
||||||
|
let _real = new Date(value.getTime() - 60000 * value.getTimezoneOffset());
|
||||||
|
return _real.toISOString().replace('T', ' ').replace(/:\d{2}\.\d{3}Z/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
static dayValue(value) {
|
||||||
|
return `${value.getFullYear()}-${value.getMonth() + 1}-${value.getDate()}`
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue