@wernfried/daterangepicker 4.19.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API_Doc.md +249 -174
- package/README.md +134 -131
- package/dist/esm/daterangepicker.js +623 -495
- package/dist/esm/daterangepicker.min.js +1 -2
- package/dist/global/daterangepicker.js +644 -492
- package/dist/global/daterangepicker.min.js +1 -2
- package/package.json +3 -3
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { DateTime, Duration, Info, Settings } from "luxon";
|
|
2
|
-
import { $ } from "jquery";
|
|
3
2
|
class DateRangePicker {
|
|
4
3
|
#startDate = null;
|
|
5
4
|
#endDate = null;
|
|
6
5
|
constructor(element, options, cb) {
|
|
6
|
+
if (typeof element === "string" && document.querySelectorAll(element).length > 1)
|
|
7
|
+
throw new RangeError(`Option 'element' must match to one element only`);
|
|
7
8
|
this.parentEl = "body";
|
|
8
|
-
this.element =
|
|
9
|
+
this.element = element instanceof HTMLElement ? element : document.querySelector(element);
|
|
10
|
+
this.isInputText = this.element instanceof HTMLInputElement && this.element.type === "text";
|
|
9
11
|
this.#startDate = DateTime.now().startOf("day");
|
|
10
12
|
this.#endDate = DateTime.now().plus({ day: 1 }).startOf("day");
|
|
11
13
|
this.minDate = null;
|
|
@@ -23,7 +25,7 @@ class DateRangePicker {
|
|
|
23
25
|
this.showWeekNumbers = false;
|
|
24
26
|
this.showISOWeekNumbers = false;
|
|
25
27
|
this.showCustomRangeLabel = true;
|
|
26
|
-
this.showLabel =
|
|
28
|
+
this.showLabel = !this.isInputText;
|
|
27
29
|
this.timePicker = false;
|
|
28
30
|
const usesMeridiems = new Intl.DateTimeFormat(DateTime.now().locale, { hour: "numeric" }).resolvedOptions();
|
|
29
31
|
this.timePicker24Hour = !usesMeridiems.hour12;
|
|
@@ -35,8 +37,8 @@ class DateRangePicker {
|
|
|
35
37
|
this.isInvalidTime = null;
|
|
36
38
|
this.isCustomDate = null;
|
|
37
39
|
this.onOutsideClick = "apply";
|
|
38
|
-
this.opens = this.element.
|
|
39
|
-
this.drops = this.element.
|
|
40
|
+
this.opens = this.element?.classList.contains("pull-right") ? "left" : "right";
|
|
41
|
+
this.drops = this.element?.classList.contains("dropup") ? "up" : "down";
|
|
40
42
|
this.buttonClasses = "btn btn-sm";
|
|
41
43
|
this.applyButtonClasses = "btn-primary";
|
|
42
44
|
this.cancelButtonClasses = "btn-default";
|
|
@@ -61,6 +63,8 @@ class DateRangePicker {
|
|
|
61
63
|
firstDay: Info.getStartOfWeek(),
|
|
62
64
|
durationFormat: null
|
|
63
65
|
};
|
|
66
|
+
if (this.element == null)
|
|
67
|
+
return;
|
|
64
68
|
this.callback = function() {
|
|
65
69
|
};
|
|
66
70
|
this.isShowing = false;
|
|
@@ -68,7 +72,17 @@ class DateRangePicker {
|
|
|
68
72
|
this.rightCalendar = {};
|
|
69
73
|
if (typeof options !== "object" || options === null)
|
|
70
74
|
options = {};
|
|
71
|
-
|
|
75
|
+
let dataOptions = {};
|
|
76
|
+
const data = Array.from(this.element.attributes).filter((x) => x.name.startsWith("data-"));
|
|
77
|
+
for (let item of data) {
|
|
78
|
+
const name = item.name.replace(/^data-/g, "").replace(/-([a-z])/g, function(str) {
|
|
79
|
+
return str[1].toUpperCase();
|
|
80
|
+
});
|
|
81
|
+
let ts = DateTime.fromISO(item.value);
|
|
82
|
+
const isDate = ["startDate", "endDate", "minDate", "maxDate", "initalMonth"].includes(name);
|
|
83
|
+
dataOptions[name] = ts.isValid && isDate ? ts : JSON.parse(item.value);
|
|
84
|
+
}
|
|
85
|
+
options = { ...dataOptions, ...options };
|
|
72
86
|
if (typeof options.singleDatePicker === "boolean")
|
|
73
87
|
this.singleDatePicker = options.singleDatePicker;
|
|
74
88
|
if (!this.singleDatePicker && typeof options.singleMonthView === "boolean") {
|
|
@@ -76,9 +90,14 @@ class DateRangePicker {
|
|
|
76
90
|
} else {
|
|
77
91
|
this.singleMonthView = false;
|
|
78
92
|
}
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
if (!(options.externalStyle === null)) {
|
|
94
|
+
const bodyStyle = window.getComputedStyle(document.body);
|
|
95
|
+
if (bodyStyle && typeof bodyStyle[Symbol.iterator] === "function" && [...bodyStyle].some((x) => x.startsWith("--bulma-")))
|
|
96
|
+
this.externalStyle = "bulma";
|
|
97
|
+
}
|
|
98
|
+
if (typeof options.template === "string" || options.template instanceof HTMLElement) {
|
|
99
|
+
this.container = typeof options.template === "string" ? createElementFromHTML(options.template) : options.template;
|
|
100
|
+
} else {
|
|
82
101
|
let template = [
|
|
83
102
|
'<div class="daterangepicker">',
|
|
84
103
|
'<div class="ranges"></div>',
|
|
@@ -87,22 +106,19 @@ class DateRangePicker {
|
|
|
87
106
|
"<thead></thead>",
|
|
88
107
|
"<tbody></tbody>",
|
|
89
108
|
"<tfoot>",
|
|
90
|
-
'<tr class="calendar-time start-time"></tr>'
|
|
91
|
-
|
|
92
|
-
if (this.singleMonthView)
|
|
93
|
-
template.push('<tr class="calendar-time end-time"></tr>');
|
|
94
|
-
template.push(...[
|
|
109
|
+
'<tr class="calendar-time start-time"></tr>',
|
|
110
|
+
this.singleMonthView ? '<tr class="calendar-time end-time"></tr>' : "",
|
|
95
111
|
"</tfoot>",
|
|
96
112
|
"</table>",
|
|
97
113
|
"</div>"
|
|
98
|
-
]
|
|
114
|
+
];
|
|
99
115
|
template.push(...[
|
|
100
116
|
'<div class="drp-calendar right">',
|
|
101
117
|
'<table class="calendar-table">',
|
|
102
118
|
"<thead></thead>",
|
|
103
119
|
"<tbody></tbody>",
|
|
104
120
|
"<tfoot>",
|
|
105
|
-
'<tr class="calendar-time end-time"></tr>',
|
|
121
|
+
this.singleMonthView ? "" : '<tr class="calendar-time end-time"></tr>',
|
|
106
122
|
"</tfoot>",
|
|
107
123
|
"</table>",
|
|
108
124
|
"</div>"
|
|
@@ -129,9 +145,10 @@ class DateRangePicker {
|
|
|
129
145
|
}
|
|
130
146
|
template.push("</div></div>");
|
|
131
147
|
options.template = template.join("");
|
|
148
|
+
this.container = createElementFromHTML(options.template);
|
|
132
149
|
}
|
|
133
|
-
this.parentEl =
|
|
134
|
-
this.
|
|
150
|
+
this.parentEl = document.querySelector(typeof options.parentEl === "string" ? options.parentEl : this.parentEl);
|
|
151
|
+
this.parentEl.appendChild(this.container);
|
|
135
152
|
if (typeof options.timePicker === "boolean")
|
|
136
153
|
this.timePicker = options.timePicker;
|
|
137
154
|
if (this.timePicker)
|
|
@@ -172,7 +189,7 @@ class DateRangePicker {
|
|
|
172
189
|
if (["string", "object", "function"].includes(typeof options.locale.durationFormat) && options.locale.durationFormat != null)
|
|
173
190
|
this.locale.durationFormat = options.locale.durationFormat;
|
|
174
191
|
}
|
|
175
|
-
this.container.
|
|
192
|
+
this.container.classList.add(this.locale.direction);
|
|
176
193
|
for (let key2 of [
|
|
177
194
|
"timePicker24Hour",
|
|
178
195
|
"showWeekNumbers",
|
|
@@ -238,10 +255,6 @@ class DateRangePicker {
|
|
|
238
255
|
}
|
|
239
256
|
}
|
|
240
257
|
if (this.timePicker) {
|
|
241
|
-
if (typeof options.timePickerSeconds === "boolean")
|
|
242
|
-
this.timePickerStepSize = Duration.fromObject({ [options.timePickerSeconds ? "seconds" : "minutes"]: 1 });
|
|
243
|
-
if (typeof options.timePickerIncrement === "number")
|
|
244
|
-
this.timePickerStepSize = Duration.fromObject({ minutes: options.timePickerIncrement });
|
|
245
258
|
if (["string", "object", "number"].includes(typeof options.timePickerStepSize)) {
|
|
246
259
|
let duration;
|
|
247
260
|
if (Duration.isDuration(options.timePickerStepSize) && options.timePickerStepSize.isValid) {
|
|
@@ -308,19 +321,18 @@ class DateRangePicker {
|
|
|
308
321
|
}
|
|
309
322
|
}
|
|
310
323
|
}
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
if (val != "") {
|
|
324
|
+
if (this.isInputText) {
|
|
325
|
+
if (this.element.value != "") {
|
|
314
326
|
const format = typeof this.locale.format === "string" ? this.locale.format : DateTime.parseFormatForOpts(this.locale.format);
|
|
315
327
|
if (this.singleDatePicker && typeof options.startDate === "undefined") {
|
|
316
|
-
const start = DateTime.fromFormat(
|
|
328
|
+
const start = DateTime.fromFormat(this.element.value, format, { locale: DateTime.now().locale });
|
|
317
329
|
if (start.isValid) {
|
|
318
330
|
this.#startDate = start;
|
|
319
331
|
} else {
|
|
320
|
-
console.error(`Value "${
|
|
332
|
+
console.error(`Value "${this.element.value}" in <input> is not a valid string: ${start.invalidExplanation}`);
|
|
321
333
|
}
|
|
322
334
|
} else if (!this.singleDatePicker && typeof options.startDate === "undefined" && typeof options.endDate === "undefined") {
|
|
323
|
-
const split =
|
|
335
|
+
const split = this.element.value.split(this.locale.separator);
|
|
324
336
|
if (split.length === 2) {
|
|
325
337
|
const start = DateTime.fromFormat(split[0], format, { locale: DateTime.now().locale });
|
|
326
338
|
const end = DateTime.fromFormat(split[1], format, { locale: DateTime.now().locale });
|
|
@@ -331,7 +343,7 @@ class DateRangePicker {
|
|
|
331
343
|
console.error(`Value in <input> is not a valid string: ${start.invalidExplanation} - ${end.invalidExplanation}`);
|
|
332
344
|
}
|
|
333
345
|
} else {
|
|
334
|
-
console.error(`Value "${
|
|
346
|
+
console.error(`Value "${this.element.value}" in <input> is not a valid string`);
|
|
335
347
|
}
|
|
336
348
|
}
|
|
337
349
|
}
|
|
@@ -347,8 +359,6 @@ class DateRangePicker {
|
|
|
347
359
|
this.#startDate = this.#startDate.startOf("day");
|
|
348
360
|
this.#endDate = this.#endDate.endOf("day");
|
|
349
361
|
}
|
|
350
|
-
if (options.warnings !== void 0)
|
|
351
|
-
console.warn(`Option 'warnings' not used anymore. Listen to event 'violated.daterangepicker'`);
|
|
352
362
|
if (!this.#startDate && this.initalMonth) {
|
|
353
363
|
this.#endDate = null;
|
|
354
364
|
if (this.timePicker)
|
|
@@ -356,7 +366,7 @@ class DateRangePicker {
|
|
|
356
366
|
} else {
|
|
357
367
|
const violations = this.validateInput(null, false);
|
|
358
368
|
if (violations != null) {
|
|
359
|
-
let vio = violations.startDate
|
|
369
|
+
let vio = violations.startDate;
|
|
360
370
|
if (vio.length > 0) {
|
|
361
371
|
if (vio.some((x) => x.reason.startsWith("isInvalid"))) {
|
|
362
372
|
console.error(`Value of startDate "${this.#startDate}" violates ${vio.find((x) => x.reason.startsWith("isInvalid")).reason}`);
|
|
@@ -368,7 +378,7 @@ class DateRangePicker {
|
|
|
368
378
|
}
|
|
369
379
|
}
|
|
370
380
|
if (!this.singleDatePicker) {
|
|
371
|
-
vio = violations.endDate.
|
|
381
|
+
vio = violations.endDate.filter((x) => x.new != null);
|
|
372
382
|
if (vio.length > 0) {
|
|
373
383
|
if (vio.some((x) => x.reason.startsWith("isInvalid"))) {
|
|
374
384
|
console.error(`Value of endDate "${this.#endDate}" violates ${vio.find((x) => x.reason.startsWith("isInvalid")).reason}`);
|
|
@@ -382,19 +392,27 @@ class DateRangePicker {
|
|
|
382
392
|
}
|
|
383
393
|
}
|
|
384
394
|
}
|
|
385
|
-
if (
|
|
395
|
+
if (this.singleDatePicker) {
|
|
396
|
+
if (typeof options.altInput === "string") {
|
|
397
|
+
const el = document.querySelector(options.altInput);
|
|
398
|
+
this.altInput = el instanceof HTMLInputElement && el.type === "text" ? el : null;
|
|
399
|
+
} else if (options.altInput instanceof HTMLElement) {
|
|
400
|
+
this.altInput = options.altInput instanceof HTMLInputElement && options.altInput.type === "text" ? options.altInput : null;
|
|
401
|
+
}
|
|
402
|
+
} else if (!this.singleDatePicker && Array.isArray(options.altInput) && options.altInput.length === 2) {
|
|
403
|
+
this.altInput = [];
|
|
404
|
+
for (let item of options.altInput) {
|
|
405
|
+
const el = typeof item === "string" ? document.querySelector(item) : item;
|
|
406
|
+
if (el instanceof HTMLInputElement && el.type === "text")
|
|
407
|
+
this.altInput.push(el);
|
|
408
|
+
}
|
|
409
|
+
if (this.altInput.length !== 2)
|
|
410
|
+
this.altInput = null;
|
|
411
|
+
} else if (options.altInput != null) {
|
|
412
|
+
console.warn(`Option 'altInput' ${JSON.stringify(options.altInput)} is not valid`);
|
|
413
|
+
}
|
|
414
|
+
if (options.altInput && ["function", "string"].includes(typeof options.altFormat))
|
|
386
415
|
this.altFormat = options.altFormat;
|
|
387
|
-
if (typeof options.altInput === "string" || Array.isArray(options.altInput)) {
|
|
388
|
-
if (this.singleDatePicker && typeof options.altInput === "string") {
|
|
389
|
-
this.altInput = $(options.altInput).is("input:text") ? options.altInput : null;
|
|
390
|
-
} else if (!this.singleDatePicker && Array.isArray(options.altInput) && options.altInput.length === 2) {
|
|
391
|
-
this.altInput = options.altInput.every((x) => typeof x === "string" && $(x).is("input:text")) ? options.altInput : null;
|
|
392
|
-
} else {
|
|
393
|
-
const note = `Value of "altInput" must be ` + (this.singleDatePicker ? "a string" : "an array of two string elements");
|
|
394
|
-
console.error(`Option 'altInput' ${JSON.stringify(options.altInput)} is not valid
|
|
395
|
-
`, note);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
416
|
if (typeof options.opens === "string") {
|
|
399
417
|
if (["left", "right", "center"].includes(options.opens))
|
|
400
418
|
this.opens = options.opens;
|
|
@@ -402,10 +420,10 @@ class DateRangePicker {
|
|
|
402
420
|
console.error(`Option 'options.opens' must be 'left', 'right' or 'center'`);
|
|
403
421
|
}
|
|
404
422
|
if (typeof options.drops === "string") {
|
|
405
|
-
if (["
|
|
423
|
+
if (["up", "down", "auto"].includes(options.drops))
|
|
406
424
|
this.drops = options.drops;
|
|
407
425
|
else
|
|
408
|
-
console.error(`Option 'options.drops' must be '
|
|
426
|
+
console.error(`Option 'options.drops' must be 'up', 'down' or 'auto'`);
|
|
409
427
|
}
|
|
410
428
|
if (Array.isArray(options.buttonClasses)) {
|
|
411
429
|
this.buttonClasses = options.buttonClasses.join(" ");
|
|
@@ -452,63 +470,68 @@ class DateRangePicker {
|
|
|
452
470
|
}
|
|
453
471
|
if (start == null || end == null)
|
|
454
472
|
continue;
|
|
455
|
-
options.ranges[range] = [start, end];
|
|
456
473
|
var elem = document.createElement("textarea");
|
|
457
474
|
elem.innerHTML = range;
|
|
458
475
|
this.ranges[elem.value] = [start, end];
|
|
459
476
|
}
|
|
460
477
|
var list = "<ul>";
|
|
461
|
-
for (let range in this.ranges)
|
|
462
|
-
list +=
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + "</li>";
|
|
466
|
-
}
|
|
478
|
+
for (let range in this.ranges)
|
|
479
|
+
list += `<li data-range-key="${range}">${range}</li>`;
|
|
480
|
+
if (this.showCustomRangeLabel)
|
|
481
|
+
list += `<li data-range-key="${this.locale.customRangeLabel}">${this.locale.customRangeLabel}</li>`;
|
|
467
482
|
list += "</ul>";
|
|
468
|
-
this.container.
|
|
469
|
-
this.container.
|
|
483
|
+
this.container.querySelector(".ranges").prepend(createElementFromHTML(list));
|
|
484
|
+
this.container.classList.add("show-ranges");
|
|
470
485
|
}
|
|
471
486
|
if (typeof cb === "function")
|
|
472
487
|
this.callback = cb;
|
|
473
|
-
if (!this.timePicker)
|
|
474
|
-
this.container.
|
|
475
|
-
|
|
488
|
+
if (!this.timePicker)
|
|
489
|
+
this.container.querySelectorAll(".calendar-time").forEach((el) => {
|
|
490
|
+
el.style.display = "none";
|
|
491
|
+
});
|
|
476
492
|
if (this.timePicker && this.autoApply)
|
|
477
493
|
this.autoApply = false;
|
|
478
494
|
if (this.autoApply)
|
|
479
|
-
this.container.
|
|
495
|
+
this.container.classList.add("auto-apply");
|
|
480
496
|
if (this.singleDatePicker || this.singleMonthView) {
|
|
481
|
-
this.container.
|
|
482
|
-
this.container.
|
|
483
|
-
this.container.
|
|
484
|
-
this.container.
|
|
497
|
+
this.container.classList.add("single");
|
|
498
|
+
this.container.querySelector(".drp-calendar.left").classList.add("single");
|
|
499
|
+
this.container.querySelector(".drp-calendar.left").style.display = "";
|
|
500
|
+
this.container.querySelector(".drp-calendar.right").style.display = "none";
|
|
485
501
|
if (!this.timePicker && this.autoApply)
|
|
486
|
-
this.container.
|
|
502
|
+
this.container.classList.add("auto-apply");
|
|
487
503
|
}
|
|
488
|
-
if (
|
|
489
|
-
this.container.
|
|
490
|
-
this.container.
|
|
491
|
-
this.container.
|
|
504
|
+
if (this.singleDatePicker || !Object.keys(this.ranges).length || this.alwaysShowCalendars)
|
|
505
|
+
this.container.classList.add("show-calendar");
|
|
506
|
+
this.container.classList.add(`opens${this.opens}`);
|
|
507
|
+
this.container.querySelectorAll(".applyBtn, .cancelBtn").forEach((el) => {
|
|
508
|
+
el.classList.add(...this.buttonClasses.split(" "));
|
|
509
|
+
});
|
|
492
510
|
if (this.applyButtonClasses.length)
|
|
493
|
-
this.container.
|
|
511
|
+
this.container.querySelector(".applyBtn").classList.add(...this.applyButtonClasses.split(" "));
|
|
494
512
|
if (this.cancelButtonClasses.length)
|
|
495
|
-
this.container.
|
|
496
|
-
this.container.
|
|
497
|
-
this.container.
|
|
498
|
-
this.
|
|
499
|
-
this.
|
|
500
|
-
this.
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
513
|
+
this.container.querySelector(".cancelBtn").classList.add(...this.cancelButtonClasses.split(" "));
|
|
514
|
+
this.container.querySelector(".applyBtn").innerHTML = this.locale.applyLabel;
|
|
515
|
+
this.container.querySelector(".cancelBtn").innerHTML = this.locale.cancelLabel;
|
|
516
|
+
this.addListener(".drp-calendar", "click", ".prev", this.clickPrev.bind(this));
|
|
517
|
+
this.addListener(".drp-calendar", "click", ".next", this.clickNext.bind(this));
|
|
518
|
+
this.addListener(".drp-calendar", "mousedown", "td.available", this.clickDate.bind(this));
|
|
519
|
+
this.addListener(".drp-calendar", "mouseenter", "td.available", this.hoverDate.bind(this));
|
|
520
|
+
this.addListener(".drp-calendar", "change", "select.yearselect,select.monthselect", this.monthOrYearChanged.bind(this));
|
|
521
|
+
this.addListener(".drp-calendar", "change", "select.hourselect,select.minuteselect,select.secondselect,select.ampmselect", this.timeChanged.bind(this));
|
|
522
|
+
this.addListener(".ranges", "click", "li", this.clickRange.bind(this));
|
|
523
|
+
this.addListener(".ranges", "mouseenter", "li", this.hoverRange.bind(this));
|
|
524
|
+
this.addListener(".ranges", "mouseleave", "li", this.leaveRange.bind(this));
|
|
525
|
+
this.addListener(".drp-buttons", "click", "button.applyBtn", this.clickApply.bind(this));
|
|
526
|
+
this.addListener(".drp-buttons", "click", "button.cancelBtn", this.clickCancel.bind(this));
|
|
527
|
+
if (this.element.matches("input") || this.element.matches("button")) {
|
|
528
|
+
this.element.addEventListener("click", this.#showProxy);
|
|
529
|
+
this.element.addEventListener("focus", this.#showProxy);
|
|
530
|
+
this.element.addEventListener("keyup", this.#elementChangedProxy);
|
|
531
|
+
this.element.addEventListener("keydown", this.#keydownProxy);
|
|
509
532
|
} else {
|
|
510
|
-
this.element.
|
|
511
|
-
this.element.
|
|
533
|
+
this.element.addEventListener("click", this.#toggleProxy);
|
|
534
|
+
this.element.addEventListener("keydown", this.#toggleProxy);
|
|
512
535
|
}
|
|
513
536
|
this.updateElement();
|
|
514
537
|
}
|
|
@@ -542,14 +565,14 @@ class DateRangePicker {
|
|
|
542
565
|
* `minDate`, `maxDate`, `minSpan`, `maxSpan`, `invalidDate` and `invalidTime` constraints.<br>
|
|
543
566
|
* Event is only triggered when date string is valid and date value is changing<br>
|
|
544
567
|
* @event
|
|
545
|
-
* @name "violate
|
|
546
|
-
* @
|
|
547
|
-
* @
|
|
548
|
-
* @
|
|
549
|
-
* @
|
|
568
|
+
* @name "violate"
|
|
569
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
570
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
571
|
+
* @property {InputViolation} event.violation - The daterangepicker object
|
|
572
|
+
* @property {NewDate} event.newDate - Object of corrected date values
|
|
573
|
+
* @property {boolean} event.cancelable=true - By calling `event.preventDefault()` the `newDate` values will apply
|
|
550
574
|
* @example
|
|
551
|
-
*
|
|
552
|
-
* $('#picker').daterangepicker({
|
|
575
|
+
* daterangepicker('#picker', {
|
|
553
576
|
* startDate: DateTime.now(),
|
|
554
577
|
* // allow only dates from current year
|
|
555
578
|
* minDate: DateTime.now().startOf('year'),
|
|
@@ -558,126 +581,154 @@ class DateRangePicker {
|
|
|
558
581
|
* locale: {
|
|
559
582
|
* format: DateTime.DATETIME_SHORT
|
|
560
583
|
* }
|
|
561
|
-
* }).
|
|
562
|
-
* newDate.startDate = DateTime.now().minus({ days: 3 }).startOf('day');
|
|
563
|
-
*
|
|
584
|
+
* }).addEventListener('violate', (ev) => {
|
|
585
|
+
* ev.newDate.startDate = DateTime.now().minus({ days: 3 }).startOf('day');
|
|
586
|
+
* ev.preventDefault();
|
|
564
587
|
* });
|
|
565
588
|
*
|
|
566
589
|
* // Try to set date outside permitted range at <input> elemet
|
|
567
|
-
*
|
|
590
|
+
* const input = document.querySelector('#picker');
|
|
591
|
+
* input.value = DateTime.now().minus({ years: 10 })).toLocaleString(DateTime.DATETIME_SHORT)
|
|
592
|
+
* input.dispatchEvent(new Event('keyup'));
|
|
568
593
|
|
|
569
594
|
* // Try to set date outside permitted range by code
|
|
570
|
-
* const drp =
|
|
595
|
+
* const drp = getDateRangePicker('#picker');
|
|
596
|
+
* drp.setStartDate(DateTime.now().minus({ years: 10 });
|
|
571
597
|
*
|
|
572
598
|
* // -> Calendar selects and shows "today - 3 days"
|
|
573
599
|
*/
|
|
574
|
-
onViolate: { type: "violate
|
|
600
|
+
onViolate: { type: "violate", param: (violation, newDate) => {
|
|
601
|
+
return { ...violation, ...{ cancelable: true } };
|
|
602
|
+
} },
|
|
575
603
|
/**
|
|
576
604
|
* Emitted before the calendar time picker is rendered.
|
|
577
605
|
* @event
|
|
578
|
-
* @name "beforeRenderCalendar
|
|
579
|
-
* @
|
|
606
|
+
* @name "beforeRenderCalendar"
|
|
607
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
608
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
580
609
|
*/
|
|
581
|
-
onBeforeRenderTimePicker: { type: "beforeRenderTimePicker
|
|
610
|
+
onBeforeRenderTimePicker: { type: "beforeRenderTimePicker" },
|
|
582
611
|
/**
|
|
583
612
|
* Emitted before the calendar is rendered. Useful to remove any manually added elements.
|
|
584
613
|
* @event
|
|
585
|
-
* @name "beforeRenderCalendar
|
|
586
|
-
* @
|
|
614
|
+
* @name "beforeRenderCalendar"
|
|
615
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
616
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
587
617
|
*/
|
|
588
|
-
onBeforeRenderCalendar: { type: "beforeRenderCalendar
|
|
618
|
+
onBeforeRenderCalendar: { type: "beforeRenderCalendar" },
|
|
589
619
|
/**
|
|
590
620
|
* Emitted when the picker is shown
|
|
591
621
|
* @event
|
|
592
|
-
* @name "show
|
|
593
|
-
* @
|
|
622
|
+
* @name "show"
|
|
623
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
624
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
594
625
|
*/
|
|
595
|
-
onShow: { type: "show
|
|
626
|
+
onShow: { type: "show" },
|
|
596
627
|
/**
|
|
597
|
-
* Emitted before the picker will hide.
|
|
628
|
+
* Emitted before the picker will hide.
|
|
598
629
|
* @event
|
|
599
|
-
* @name "beforeHide
|
|
600
|
-
* @
|
|
601
|
-
* @
|
|
630
|
+
* @name "beforeHide"
|
|
631
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
632
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
633
|
+
* @property {boolean} event.cancelable=true - Hide is canceled by calling `event.preventDefault()`
|
|
602
634
|
*/
|
|
603
|
-
onBeforeHide: { type: "beforeHide
|
|
635
|
+
onBeforeHide: { type: "beforeHide", param: { cancelable: true } },
|
|
604
636
|
/**
|
|
605
637
|
* Emitted when the picker is hidden
|
|
606
638
|
* @event
|
|
607
|
-
* @name "hide
|
|
608
|
-
* @
|
|
639
|
+
* @name "hide"
|
|
640
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
641
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
609
642
|
*/
|
|
610
|
-
onHide: { type: "hide
|
|
643
|
+
onHide: { type: "hide" },
|
|
611
644
|
/**
|
|
612
645
|
* Emitted when the calendar(s) are shown.
|
|
613
646
|
* Only useful when {@link #Ranges|Ranges} are used.
|
|
614
647
|
* @event
|
|
615
|
-
* @name "showCalendar
|
|
616
|
-
* @
|
|
648
|
+
* @name "showCalendar"
|
|
649
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
650
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
617
651
|
*/
|
|
618
|
-
onShowCalendar: { type: "showCalendar
|
|
652
|
+
onShowCalendar: { type: "showCalendar" },
|
|
619
653
|
/**
|
|
620
654
|
* Emitted when the calendar(s) are hidden. Only used when {@link #Ranges|Ranges} are used.
|
|
621
655
|
* @event
|
|
622
|
-
* @name "hideCalendar
|
|
623
|
-
* @
|
|
656
|
+
* @name "hideCalendar"
|
|
657
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
658
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
624
659
|
*/
|
|
625
|
-
onHideCalendar: { type: "hideCalendar
|
|
660
|
+
onHideCalendar: { type: "hideCalendar" },
|
|
626
661
|
/**
|
|
627
662
|
* Emitted when user clicks outside the picker. Use option `onOutsideClick` to define the default action, then you may not need to handle this event.
|
|
628
663
|
* @event
|
|
629
|
-
* @name "outsideClick
|
|
630
|
-
* @
|
|
664
|
+
* @name "outsideClick"
|
|
665
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
666
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
631
667
|
*/
|
|
632
|
-
onOutsideClick: { type: "outsideClick
|
|
668
|
+
onOutsideClick: { type: "outsideClick" },
|
|
633
669
|
/**
|
|
634
|
-
* Emitted when the date changed. Does not trigger when time is changed, use {@link #event_timeChange
|
|
670
|
+
* Emitted when the date changed. Does not trigger when time is changed, use {@link #event_timeChange|"timeChange"} to handle it
|
|
635
671
|
* @event
|
|
636
|
-
* @name "dateChange
|
|
637
|
-
* @
|
|
638
|
-
* @
|
|
672
|
+
* @name "dateChange"
|
|
673
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
674
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
675
|
+
* @property {string} side - Either `'start'` or `'end'` indicating whether `startDate` or `endDate` was changed. `null` for singleDatePicker
|
|
639
676
|
*/
|
|
640
|
-
onDateChange: { type: "dateChange
|
|
677
|
+
onDateChange: { type: "dateChange", param: (side) => {
|
|
678
|
+
return side;
|
|
679
|
+
} },
|
|
641
680
|
/**
|
|
642
681
|
* Emitted when the time changed. Does not trigger when date is changed
|
|
643
682
|
* @event
|
|
644
|
-
* @name "timeChange
|
|
645
|
-
* @
|
|
646
|
-
* @
|
|
683
|
+
* @name "timeChange"
|
|
684
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
685
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
686
|
+
* @property {string} side - Either `'start'` or `'end'` indicating whether `startDate` or `endDate` was changed. `null` for singleDatePicker
|
|
647
687
|
*/
|
|
648
|
-
onTimeChange: { type: "timeChange
|
|
688
|
+
onTimeChange: { type: "timeChange", param: (side) => {
|
|
689
|
+
return side;
|
|
690
|
+
} },
|
|
649
691
|
/**
|
|
650
692
|
* Emitted when the `Apply` button is clicked, or when a predefined {@link #Ranges|Ranges} is clicked
|
|
651
693
|
* @event
|
|
652
|
-
* @name "apply
|
|
653
|
-
* @
|
|
694
|
+
* @name "apply"
|
|
695
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
696
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
654
697
|
*/
|
|
655
|
-
onApply: { type: "apply
|
|
698
|
+
onApply: { type: "apply" },
|
|
656
699
|
/**
|
|
657
700
|
* Emitted when the `Cancel` button is clicked
|
|
658
701
|
* @event
|
|
659
|
-
* @name "cancel
|
|
660
|
-
* @
|
|
702
|
+
* @name "cancel"
|
|
703
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
704
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
661
705
|
*/
|
|
662
|
-
onCancel: { type: "cancel
|
|
706
|
+
onCancel: { type: "cancel" },
|
|
663
707
|
/**
|
|
664
708
|
* Emitted when the date is changed through `<input>` element. Event is only triggered when date string is valid and date value has changed
|
|
665
709
|
* @event
|
|
666
|
-
* @name "inputChange
|
|
667
|
-
* @
|
|
710
|
+
* @name "inputChange"
|
|
711
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
712
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
668
713
|
*/
|
|
669
|
-
onInputChange: { type: "inputChange
|
|
714
|
+
onInputChange: { type: "inputChange" },
|
|
670
715
|
/**
|
|
671
716
|
* Emitted after month view changed, for example by click on 'prev' or 'next'
|
|
672
717
|
* @event
|
|
673
|
-
* @name "monthViewChange
|
|
674
|
-
* @
|
|
675
|
-
* @
|
|
676
|
-
* @
|
|
718
|
+
* @name "monthViewChange"
|
|
719
|
+
* @property {DateRangePickerEvent} event - The Event object
|
|
720
|
+
* @property {DateRangePicker} event.picker - The daterangepicker object
|
|
721
|
+
* @property {external:DateTime} left - The first day of month in left-hand calendar
|
|
722
|
+
* @property {external:DateTime} right - The first day of month in left-hand calendar or `null` for singleDatePicker
|
|
677
723
|
*/
|
|
678
724
|
onMonthViewChange: {
|
|
679
|
-
type: "monthViewChange
|
|
680
|
-
param: (left, right) =>
|
|
725
|
+
type: "monthViewChange",
|
|
726
|
+
param: (left, right) => {
|
|
727
|
+
return {
|
|
728
|
+
left: this.leftCalendar.month.startOf("month"),
|
|
729
|
+
right: this.singleMonthView || this.singleDatePicker ? null : this.rightCalendar.month.startOf("month")
|
|
730
|
+
};
|
|
731
|
+
}
|
|
681
732
|
}
|
|
682
733
|
};
|
|
683
734
|
/**
|
|
@@ -686,16 +737,27 @@ class DateRangePicker {
|
|
|
686
737
|
get events() {
|
|
687
738
|
return this.#events;
|
|
688
739
|
}
|
|
740
|
+
#outsideClickProxy = this.outsideClick.bind(this);
|
|
741
|
+
#onResizeProxy = this.move.bind(this);
|
|
742
|
+
#dropdownClickWrapper = (e) => {
|
|
743
|
+
const match = e.target.closest('[data-toggle="dropdown"]');
|
|
744
|
+
if (match && document.contains(match))
|
|
745
|
+
this.#outsideClickProxy(e);
|
|
746
|
+
};
|
|
747
|
+
#showProxy = this.show.bind(this);
|
|
748
|
+
#elementChangedProxy = this.elementChanged.bind(this);
|
|
749
|
+
#keydownProxy = this.keydown.bind(this);
|
|
750
|
+
#toggleProxy = this.toggle.bind(this);
|
|
689
751
|
/* #region Set startDate/endDate */
|
|
690
752
|
/**
|
|
691
753
|
* Sets the date range picker's currently selected start date to the provided date.<br>
|
|
692
754
|
* `startDate` must be a `luxon.DateTime` or `Date` or `string` according to {@link ISO-8601} or a string matching `locale.format`.<br>
|
|
693
|
-
* Invalid date values are handled by {@link #DateRangePicker+
|
|
755
|
+
* Invalid date values are handled by {@link #DateRangePicker+violate|violate} Event
|
|
694
756
|
* @param {external:DateTime|external:Date|string} startDate - startDate to be set. In case of ranges, the current `endDate` is used.
|
|
695
757
|
* @param {boolean} updateView=true - If `true`, then calendar UI is updated to new value. Otherwise only internal values are set.
|
|
696
758
|
* @returns {InputViolation} - Object of violations or `null` if no violation have been found
|
|
697
759
|
* @example
|
|
698
|
-
* const drp =
|
|
760
|
+
* const drp = getDateRangePicker('#picker');
|
|
699
761
|
* drp.setStartDate(DateTime.now().startOf('hour'));
|
|
700
762
|
*/
|
|
701
763
|
setStartDate(startDate, updateView = true) {
|
|
@@ -728,12 +790,12 @@ class DateRangePicker {
|
|
|
728
790
|
/**
|
|
729
791
|
* Sets the date range picker's currently selected start date to the provided date.<br>
|
|
730
792
|
* `endDate` must be a `luxon.DateTime` or `Date` or `string` according to {@link ISO-8601} or a string matching `locale.format`.<br>
|
|
731
|
-
* Invalid date values are handled by {@link #DateRangePicker+
|
|
793
|
+
* Invalid date values are handled by {@link #DateRangePicker+violate|violate} Event
|
|
732
794
|
* @param {external:DateTime|external:Date|string} endDate - endDate to be set. In case of ranges, the current `startDate` is used.
|
|
733
795
|
* @param {boolean} updateView=true - If `true`, then calendar UI is updated to new value. Otherwise only internal values are set.
|
|
734
796
|
* @returns {InputViolation} - Object of violations or `null` if no violation have been found
|
|
735
797
|
* @example
|
|
736
|
-
* const drp =
|
|
798
|
+
* const drp = getDateRangePicker('#picker');
|
|
737
799
|
* drp.setEndDate(DateTime.now().startOf('hour'));
|
|
738
800
|
*/
|
|
739
801
|
setEndDate(endDate, updateView = true) {
|
|
@@ -742,13 +804,13 @@ class DateRangePicker {
|
|
|
742
804
|
/**
|
|
743
805
|
* Sets the date range picker's currently selected start date to the provided date.<br>
|
|
744
806
|
* `startDate` and `endDate` must be a `luxon.DateTime` or `Date` or `string` according to {@link ISO-8601} or a string matching `locale.format`.<br>
|
|
745
|
-
* Invalid date values are handled by {@link #DateRangePicker+
|
|
807
|
+
* Invalid date values are handled by {@link #DateRangePicker+violate|violate} Event
|
|
746
808
|
* @param {external:DateTime|external:Date|string} startDate - startDate to be set
|
|
747
809
|
* @param {external:DateTime|external:Date|string} endDate - endDate to be set
|
|
748
810
|
* @param {boolean} updateView=true - If `true`, then calendar UI is updated to new value. Otherwise only internal values are set.
|
|
749
811
|
* @returns {InputViolation} - Object of violations or `null` if no violation have been found
|
|
750
812
|
* @example
|
|
751
|
-
* const drp =
|
|
813
|
+
* const drp = getDateRangePicker('#picker');
|
|
752
814
|
* drp.setRange(DateTime.now().startOf('hour'), DateTime.now().endOf('day'));
|
|
753
815
|
*/
|
|
754
816
|
setRange(startDate, endDate, updateView = true) {
|
|
@@ -841,45 +903,49 @@ class DateRangePicker {
|
|
|
841
903
|
if (this.#endDate)
|
|
842
904
|
text += this.formatDate(this.#endDate);
|
|
843
905
|
}
|
|
844
|
-
this.container.
|
|
906
|
+
this.container.querySelector(".drp-selected").innerHTML = text;
|
|
845
907
|
}
|
|
846
908
|
if (this.singleDatePicker || this.locale.durationFormat == null)
|
|
847
909
|
return;
|
|
848
910
|
if (!this.#endDate) {
|
|
849
|
-
this.container.
|
|
911
|
+
this.container.querySelector(".drp-duration-label").innerHTML = "";
|
|
850
912
|
return;
|
|
851
913
|
}
|
|
852
914
|
if (typeof this.locale.durationFormat === "function") {
|
|
853
|
-
this.container.
|
|
915
|
+
this.container.querySelector(".drp-duration-label").innerHTML = this.locale.durationFormat(this.#startDate, this.#endDate);
|
|
854
916
|
} else {
|
|
855
917
|
let duration = this.#endDate.plus({ milliseconds: 1 }).diff(this.#startDate).rescale().set({ milliseconds: 0 });
|
|
856
918
|
if (!this.timePicker)
|
|
857
919
|
duration = duration.set({ seconds: 0, minutes: 0, hours: 0 });
|
|
858
920
|
duration = duration.removeZeros();
|
|
859
921
|
if (typeof this.locale.durationFormat === "object") {
|
|
860
|
-
this.container.
|
|
922
|
+
this.container.querySelector(".drp-duration-label").innerHTML = duration.toHuman(this.locale.durationFormat);
|
|
861
923
|
} else {
|
|
862
|
-
this.container.
|
|
924
|
+
this.container.querySelector(".drp-duration-label").innerHTML = duration.toFormat(this.locale.durationFormat);
|
|
863
925
|
}
|
|
864
926
|
}
|
|
865
927
|
}
|
|
866
928
|
/**
|
|
867
929
|
* @typedef InputViolation
|
|
868
930
|
* @type {Object}
|
|
869
|
-
* @
|
|
870
|
-
* @property {
|
|
871
|
-
* @property {Array} violations - The constraints which violates the input
|
|
872
|
-
* @property {Array} reason - The type/reson of violation
|
|
931
|
+
* @typedef {object} Violation
|
|
932
|
+
* @property {string} reason - The type/reason of violation
|
|
873
933
|
* @property {external:DateTime} old - Old value startDate/endDate
|
|
874
934
|
* @property {external:DateTime} new? - Corrected value of startDate/endDate if existing
|
|
935
|
+
* @typedef {object} NewDate
|
|
936
|
+
* @property {external:DateTime} newDate.startDate- Object with corrected values
|
|
937
|
+
* @property {external:DateTime} newDate.endDate - Object with corrected values
|
|
938
|
+
* @property {Violation[]} startDate - The constraints which violates the input
|
|
939
|
+
* @property {Violation[]?} endDate - The constraints which violates the input or `null` for singleDatePicker
|
|
940
|
+
* @property {NewDate} newDate - Object with corrected values
|
|
875
941
|
*/
|
|
876
942
|
/**
|
|
877
943
|
* Validate `startDate` and `endDate` against `timePickerStepSize`, `minDate`, `maxDate`,
|
|
878
944
|
* `minSpan`, `maxSpan`, `invalidDate` and `invalidTime`.
|
|
879
945
|
* @param {Array} range - `[startDate, endDate]`<br>Range to be checked, defaults to current `startDate` and `endDate`
|
|
880
|
-
* @param {boolean} dipatch=false - If `true` then event "
|
|
946
|
+
* @param {boolean} dipatch=false - If `true` then event "violate" is dispated.<br>
|
|
881
947
|
* If eventHandler returns `true`, then `null` is returned, otherwiese the object of violations.
|
|
882
|
-
* @emits "
|
|
948
|
+
* @emits "violate"
|
|
883
949
|
* @returns {InputViolation|null} - Object of violations and corrected values or `null` if no violation have been found
|
|
884
950
|
* @example
|
|
885
951
|
* options => {
|
|
@@ -892,18 +958,18 @@ class DateRangePicker {
|
|
|
892
958
|
* const result = validateInput(DateTime.now(), DateTime.now().plus({day: 3}));
|
|
893
959
|
*
|
|
894
960
|
* result => {
|
|
895
|
-
* startDate:
|
|
896
|
-
*
|
|
897
|
-
*
|
|
898
|
-
*
|
|
899
|
-
* ]
|
|
900
|
-
* },
|
|
961
|
+
* startDate: [
|
|
962
|
+
* { old: "2026-03-13T10:35:52", reason: "timePickerStepSize", new: "2026-03-13T11:00:00" },
|
|
963
|
+
* { old: "2026-03-13T11:00:00", reason: "maxDate", new: "2026-03-10T00:00:00" }
|
|
964
|
+
* ],
|
|
901
965
|
* endDate: {
|
|
902
|
-
*
|
|
903
|
-
*
|
|
904
|
-
*
|
|
905
|
-
*
|
|
906
|
-
*
|
|
966
|
+
* { old: "2026-03-16T10:35:52", reason: "stepSize", new: "2026-03-16T11:00:00" },
|
|
967
|
+
* { old: "2026-03-16T11:00:00", reason: "maxDate", new: "2026-03-10T00:00:00" },
|
|
968
|
+
* { old: "2026-03-10T00:00:00", reason: "minSpan", new: "2026-03-17T00:00:00" }
|
|
969
|
+
* ],
|
|
970
|
+
* newDate: {
|
|
971
|
+
* startDate: "2026-03-10T00:00:00",
|
|
972
|
+
* endDate: "2026-03-17T00:00:00"
|
|
907
973
|
* }
|
|
908
974
|
* }
|
|
909
975
|
*/
|
|
@@ -912,14 +978,14 @@ class DateRangePicker {
|
|
|
912
978
|
let endDate = range == null ? this.#endDate : range[1];
|
|
913
979
|
if (startDate == null)
|
|
914
980
|
return null;
|
|
915
|
-
let result = { startDate:
|
|
981
|
+
let result = { startDate: [] };
|
|
916
982
|
let violation = { old: startDate, reason: this.timePicker ? "timePickerStepSize" : "timePicker" };
|
|
917
983
|
if (this.timePicker) {
|
|
918
984
|
const secs = this.timePickerStepSize.as("seconds");
|
|
919
985
|
startDate = DateTime.fromSeconds(secs * Math.round(startDate.toSeconds() / secs));
|
|
920
986
|
violation.new = startDate;
|
|
921
987
|
if (!violation.new.equals(violation.old))
|
|
922
|
-
result.startDate.
|
|
988
|
+
result.startDate.push(violation);
|
|
923
989
|
} else {
|
|
924
990
|
startDate = startDate.startOf("day");
|
|
925
991
|
}
|
|
@@ -931,7 +997,7 @@ class DateRangePicker {
|
|
|
931
997
|
startDate = startDate.plus(this.timePicker ? this.timePickerStepSize : { days: 1 });
|
|
932
998
|
violation.new = startDate;
|
|
933
999
|
if (!violation.new.equals(violation.old))
|
|
934
|
-
result.startDate.
|
|
1000
|
+
result.startDate.push(violation);
|
|
935
1001
|
} else if (this.maxDate && startDate > this.maxDate) {
|
|
936
1002
|
violation = { old: startDate, reason: "maxDate" };
|
|
937
1003
|
startDate = startDate.minus({ seconds: Math.trunc(startDate.diff(this.maxDate).as("seconds") / shiftStep) * shiftStep });
|
|
@@ -939,7 +1005,7 @@ class DateRangePicker {
|
|
|
939
1005
|
startDate = startDate.minus(this.timePicker ? this.timePickerStepSize : { days: 1 });
|
|
940
1006
|
violation.new = startDate;
|
|
941
1007
|
if (!violation.new.equals(violation.old))
|
|
942
|
-
result.startDate.
|
|
1008
|
+
result.startDate.push(violation);
|
|
943
1009
|
}
|
|
944
1010
|
let units = ["hour"];
|
|
945
1011
|
if (this.timePicker) {
|
|
@@ -951,21 +1017,21 @@ class DateRangePicker {
|
|
|
951
1017
|
units.push("ampm");
|
|
952
1018
|
}
|
|
953
1019
|
if (this.isInvalidDate(startDate))
|
|
954
|
-
result.startDate.
|
|
1020
|
+
result.startDate.push({ old: startDate, reason: "isInvalidDate" });
|
|
955
1021
|
if (this.timePicker) {
|
|
956
1022
|
for (let unit of units) {
|
|
957
1023
|
if (this.isInvalidTime(startDate, unit, "start"))
|
|
958
|
-
result.startDate.
|
|
1024
|
+
result.startDate.push({ old: startDate, reason: "isInvalidTime", unit });
|
|
959
1025
|
}
|
|
960
1026
|
}
|
|
961
1027
|
if (this.singleDatePicker) {
|
|
962
|
-
if (result.startDate.
|
|
1028
|
+
if (result.startDate.length == 0)
|
|
963
1029
|
return null;
|
|
964
1030
|
if (dipatch) {
|
|
965
1031
|
let newValues = { startDate };
|
|
966
|
-
const
|
|
967
|
-
if (
|
|
968
|
-
result.newDate =
|
|
1032
|
+
const event = this.triggerEvent(this.#events.onViolate, { violation: result, newDate: newValues });
|
|
1033
|
+
if (event.defaultPrevented) {
|
|
1034
|
+
result.newDate = event.newDate;
|
|
969
1035
|
return result;
|
|
970
1036
|
}
|
|
971
1037
|
return result;
|
|
@@ -975,14 +1041,14 @@ class DateRangePicker {
|
|
|
975
1041
|
}
|
|
976
1042
|
if (endDate == null)
|
|
977
1043
|
return null;
|
|
978
|
-
result.endDate =
|
|
1044
|
+
result.endDate = [];
|
|
979
1045
|
violation = { old: endDate, reason: this.timePicker ? "stepSize" : "timePicker" };
|
|
980
1046
|
if (this.timePicker) {
|
|
981
1047
|
const secs = this.timePickerStepSize.as("seconds");
|
|
982
1048
|
endDate = DateTime.fromSeconds(secs * Math.round(endDate.toSeconds() / secs));
|
|
983
1049
|
violation.new = endDate;
|
|
984
1050
|
if (!violation.new.equals(violation.old))
|
|
985
|
-
result.endDate.
|
|
1051
|
+
result.endDate.push(violation);
|
|
986
1052
|
} else {
|
|
987
1053
|
endDate = endDate.endOf("day");
|
|
988
1054
|
}
|
|
@@ -993,7 +1059,7 @@ class DateRangePicker {
|
|
|
993
1059
|
endDate = endDate.minus(this.timePicker ? this.timePickerStepSize : { days: 1 });
|
|
994
1060
|
violation.new = endDate;
|
|
995
1061
|
if (!violation.new.equals(violation.old))
|
|
996
|
-
result.endDate.
|
|
1062
|
+
result.endDate.push(violation);
|
|
997
1063
|
} else if (this.minDate && endDate < this.minDate) {
|
|
998
1064
|
violation = { old: endDate, reason: "minDate" };
|
|
999
1065
|
endDate = endDate.plus({ seconds: Math.trunc(this.minDate.diff(endDate).as("seconds") / shiftStep) * shiftStep });
|
|
@@ -1001,7 +1067,7 @@ class DateRangePicker {
|
|
|
1001
1067
|
endDate = endDate.plus(this.timePicker ? this.timePickerStepSize : { days: 1 });
|
|
1002
1068
|
violation.new = endDate;
|
|
1003
1069
|
if (!violation.new.equals(violation.old))
|
|
1004
|
-
result.endDate.
|
|
1070
|
+
result.endDate.push(violation);
|
|
1005
1071
|
}
|
|
1006
1072
|
if (this.maxSpan) {
|
|
1007
1073
|
const maxDate = startDate.plus(this.maxSpan);
|
|
@@ -1012,7 +1078,7 @@ class DateRangePicker {
|
|
|
1012
1078
|
endDate = endDate.minus(this.timePicker ? this.timePickerStepSize : { days: 1 });
|
|
1013
1079
|
violation.new = endDate;
|
|
1014
1080
|
if (!violation.new.equals(violation.old))
|
|
1015
|
-
result.endDate.
|
|
1081
|
+
result.endDate.push(violation);
|
|
1016
1082
|
}
|
|
1017
1083
|
}
|
|
1018
1084
|
if (this.minSpan) {
|
|
@@ -1024,24 +1090,24 @@ class DateRangePicker {
|
|
|
1024
1090
|
endDate = endDate.plus(this.timePicker ? this.timePickerStepSize : { days: 1 });
|
|
1025
1091
|
violation.new = endDate;
|
|
1026
1092
|
if (!violation.new.equals(violation.old))
|
|
1027
|
-
result.endDate.
|
|
1093
|
+
result.endDate.push(violation);
|
|
1028
1094
|
}
|
|
1029
1095
|
}
|
|
1030
1096
|
if (this.isInvalidDate(endDate))
|
|
1031
|
-
result.endDate.
|
|
1097
|
+
result.endDate.push({ old: endDate, reason: "isInvalidDate" });
|
|
1032
1098
|
if (this.timePicker) {
|
|
1033
1099
|
for (let unit of units) {
|
|
1034
1100
|
if (this.isInvalidTime(endDate, unit, "end"))
|
|
1035
|
-
result.endDate.
|
|
1101
|
+
result.endDate.push({ old: endDate, reason: "isInvalidTime", unit });
|
|
1036
1102
|
}
|
|
1037
1103
|
}
|
|
1038
|
-
if (result.startDate.
|
|
1104
|
+
if (result.startDate.length == 0 && result.endDate.length == 0)
|
|
1039
1105
|
return null;
|
|
1040
1106
|
if (dipatch) {
|
|
1041
1107
|
let newValues = { startDate, endDate };
|
|
1042
|
-
const
|
|
1043
|
-
if (
|
|
1044
|
-
result.newDate =
|
|
1108
|
+
const event = this.triggerEvent(this.#events.onViolate, { violation: result, newDate: newValues });
|
|
1109
|
+
if (event.defaultPrevented) {
|
|
1110
|
+
result.newDate = event.newDate;
|
|
1045
1111
|
return result;
|
|
1046
1112
|
}
|
|
1047
1113
|
return result;
|
|
@@ -1054,18 +1120,15 @@ class DateRangePicker {
|
|
|
1054
1120
|
* Updates the picker when calendar is initiated or any date has been selected.
|
|
1055
1121
|
* Could be useful after running {@link #DateRangePicker+setStartDate|setStartDate} or {@link #DateRangePicker+setEndDate|setRange}
|
|
1056
1122
|
* @param {boolean} monthChange - If `true` then monthView changed
|
|
1057
|
-
* @emits "beforeRenderTimePicker
|
|
1123
|
+
* @emits "beforeRenderTimePicker"
|
|
1058
1124
|
*/
|
|
1059
1125
|
updateView(monthChange) {
|
|
1060
1126
|
if (this.timePicker) {
|
|
1061
1127
|
this.triggerEvent(this.#events.onBeforeRenderTimePicker);
|
|
1062
1128
|
this.renderTimePicker("start");
|
|
1063
1129
|
this.renderTimePicker("end");
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
} else {
|
|
1067
|
-
this.container.find(".calendar-time.end-time select").prop("disabled", false).removeClass("disabled");
|
|
1068
|
-
}
|
|
1130
|
+
this.container.querySelector(".calendar-time.end-time select").disabled = !this.#endDate;
|
|
1131
|
+
this.container.querySelector(".calendar-time.end-time select").classList.toggle("disabled", !this.#endDate);
|
|
1069
1132
|
}
|
|
1070
1133
|
this.updateLabel();
|
|
1071
1134
|
this.updateMonthsInView();
|
|
@@ -1107,8 +1170,8 @@ class DateRangePicker {
|
|
|
1107
1170
|
}
|
|
1108
1171
|
/**
|
|
1109
1172
|
* Updates the selected day value from calendar with selected time values
|
|
1110
|
-
* @emits "beforeRenderCalendar
|
|
1111
|
-
* @emits "monthViewChange
|
|
1173
|
+
* @emits "beforeRenderCalendar"
|
|
1174
|
+
* @emits "monthViewChange"
|
|
1112
1175
|
* @param {boolean} monthChange - If `true` then monthView changed
|
|
1113
1176
|
* @private
|
|
1114
1177
|
*/
|
|
@@ -1116,36 +1179,36 @@ class DateRangePicker {
|
|
|
1116
1179
|
if (this.timePicker) {
|
|
1117
1180
|
var hour, minute, second;
|
|
1118
1181
|
if (this.#endDate) {
|
|
1119
|
-
hour = parseInt(this.container.
|
|
1182
|
+
hour = parseInt(this.container.querySelector(".start-time .hourselect").value, 10);
|
|
1120
1183
|
if (isNaN(hour))
|
|
1121
|
-
hour = parseInt(this.container.
|
|
1184
|
+
hour = parseInt(this.container.querySelector(".start-time .hourselect option:last-child").value, 10);
|
|
1122
1185
|
minute = 0;
|
|
1123
1186
|
if (this.timePickerOpts.showMinutes) {
|
|
1124
|
-
minute = parseInt(this.container.
|
|
1187
|
+
minute = parseInt(this.container.querySelector(".start-time .minuteselect").value, 10);
|
|
1125
1188
|
if (isNaN(minute))
|
|
1126
|
-
minute = parseInt(this.container.
|
|
1189
|
+
minute = parseInt(this.container.querySelector(".start-time .minuteselect option:last-child").value, 10);
|
|
1127
1190
|
}
|
|
1128
1191
|
second = 0;
|
|
1129
1192
|
if (this.timePickerOpts.showSeconds) {
|
|
1130
|
-
second = parseInt(this.container.
|
|
1193
|
+
second = parseInt(this.container.querySelector(".start-time .secondselect").value, 10);
|
|
1131
1194
|
if (isNaN(second))
|
|
1132
|
-
second = parseInt(this.container.
|
|
1195
|
+
second = parseInt(this.container.querySelector(".start-time .secondselect option:last-child").value, 10);
|
|
1133
1196
|
}
|
|
1134
1197
|
} else {
|
|
1135
|
-
hour = parseInt(this.container.
|
|
1198
|
+
hour = parseInt(this.container.querySelector(".end-time .hourselect").value, 10);
|
|
1136
1199
|
if (isNaN(hour))
|
|
1137
|
-
hour = parseInt(this.container.
|
|
1200
|
+
hour = parseInt(this.container.querySelector(".end-time .hourselect option:last-child").value, 10);
|
|
1138
1201
|
minute = 0;
|
|
1139
1202
|
if (this.timePickerOpts.showMinutes) {
|
|
1140
|
-
minute = parseInt(this.container.
|
|
1203
|
+
minute = parseInt(this.container.querySelector(".end-time .minuteselect").value, 10);
|
|
1141
1204
|
if (isNaN(minute))
|
|
1142
|
-
minute = parseInt(this.container.
|
|
1205
|
+
minute = parseInt(this.container.querySelector(".end-time .minuteselect option:last-child").value, 10);
|
|
1143
1206
|
}
|
|
1144
1207
|
second = 0;
|
|
1145
1208
|
if (this.timePickerOpts.showSeconds) {
|
|
1146
|
-
second = parseInt(this.container.
|
|
1209
|
+
second = parseInt(this.container.querySelector(".end-time .secondselect").value, 10);
|
|
1147
1210
|
if (isNaN(second))
|
|
1148
|
-
second = parseInt(this.container.
|
|
1211
|
+
second = parseInt(this.container.querySelector(".end-time .secondselect option:last-child").value, 10);
|
|
1149
1212
|
}
|
|
1150
1213
|
}
|
|
1151
1214
|
this.leftCalendar.month = this.leftCalendar.month.set({ hour, minute, second });
|
|
@@ -1160,12 +1223,10 @@ class DateRangePicker {
|
|
|
1160
1223
|
this.renderCalendar("left");
|
|
1161
1224
|
this.renderCalendar("right");
|
|
1162
1225
|
if (monthChange)
|
|
1163
|
-
this.triggerEvent(
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
);
|
|
1168
|
-
this.container.find(".ranges li").removeClass("active");
|
|
1226
|
+
this.triggerEvent(this.#events.onMonthViewChange);
|
|
1227
|
+
this.container.querySelectorAll(".ranges li").forEach((el) => {
|
|
1228
|
+
el.classList.remove("active");
|
|
1229
|
+
});
|
|
1169
1230
|
if (this.#endDate == null) return;
|
|
1170
1231
|
this.calculateChosenLabel();
|
|
1171
1232
|
}
|
|
@@ -1252,7 +1313,7 @@ class DateRangePicker {
|
|
|
1252
1313
|
}
|
|
1253
1314
|
;
|
|
1254
1315
|
html += "</tr>";
|
|
1255
|
-
this.container.
|
|
1316
|
+
this.container.querySelector(`.drp-calendar.${side} .calendar-table thead`).innerHTML = html;
|
|
1256
1317
|
html = "";
|
|
1257
1318
|
if (this.#endDate == null && this.maxSpan) {
|
|
1258
1319
|
var maxLimit = this.#startDate.plus(this.maxSpan).endOf("day");
|
|
@@ -1266,9 +1327,9 @@ class DateRangePicker {
|
|
|
1266
1327
|
for (let row = 0; row < 6; row++) {
|
|
1267
1328
|
html += "<tr>";
|
|
1268
1329
|
if (this.showISOWeekNumbers)
|
|
1269
|
-
html +=
|
|
1330
|
+
html += `<td class="week">${calendar[row][0].weekNumber}</td>`;
|
|
1270
1331
|
else if (this.showWeekNumbers)
|
|
1271
|
-
html +=
|
|
1332
|
+
html += `<td class="week">${calendar[row][0].localWeekNumber}</td>`;
|
|
1272
1333
|
for (let col = 0; col < 7; col++) {
|
|
1273
1334
|
var classes = [];
|
|
1274
1335
|
if (this.todayClasses && this.todayClasses.length && calendar[row][col].hasSame(DateTime.now(), "day"))
|
|
@@ -1292,31 +1353,27 @@ class DateRangePicker {
|
|
|
1292
1353
|
if (this.#endDate != null && calendar[row][col] > this.#startDate && calendar[row][col] < this.#endDate)
|
|
1293
1354
|
classes.push("in-range");
|
|
1294
1355
|
var isCustom = this.isCustomDate(calendar[row][col]);
|
|
1295
|
-
if (isCustom !== false)
|
|
1296
|
-
|
|
1297
|
-
classes.push(isCustom);
|
|
1298
|
-
else
|
|
1299
|
-
Array.prototype.push.apply(classes, isCustom);
|
|
1300
|
-
}
|
|
1356
|
+
if (isCustom !== false)
|
|
1357
|
+
typeof isCustom === "string" ? classes.push(isCustom) : classes.push(...isCustom);
|
|
1301
1358
|
if (!classes.includes("disabled"))
|
|
1302
1359
|
classes.push("available");
|
|
1303
1360
|
html += `<td class="${classes.join(" ")}" data-title="r${row}c${col}">${calendar[row][col].day}</td>`;
|
|
1304
1361
|
}
|
|
1305
1362
|
html += "</tr>";
|
|
1306
1363
|
}
|
|
1307
|
-
this.container.
|
|
1364
|
+
this.container.querySelector(`.drp-calendar.${side} .calendar-table tbody`).innerHTML = html;
|
|
1308
1365
|
}
|
|
1309
1366
|
/**
|
|
1310
1367
|
* Emitted before the TimePicker is rendered.
|
|
1311
1368
|
* Useful to remove any manually added elements.
|
|
1312
1369
|
* @event
|
|
1313
|
-
* @name "beforeRenderTimePicker
|
|
1370
|
+
* @name "beforeRenderTimePicker"
|
|
1314
1371
|
* @param {DateRangePicker} this - The daterangepicker object
|
|
1315
1372
|
*/
|
|
1316
1373
|
/**
|
|
1317
1374
|
* Renders the time pickers
|
|
1318
1375
|
* @private
|
|
1319
|
-
* @emits "beforeRenderTimePicker
|
|
1376
|
+
* @emits "beforeRenderTimePicker"
|
|
1320
1377
|
*/
|
|
1321
1378
|
renderTimePicker(side) {
|
|
1322
1379
|
if (side === "end" && !this.#endDate) return;
|
|
@@ -1334,12 +1391,12 @@ class DateRangePicker {
|
|
|
1334
1391
|
} else if (side === "end") {
|
|
1335
1392
|
selected = this.#endDate;
|
|
1336
1393
|
minDate = this.#startDate;
|
|
1337
|
-
|
|
1338
|
-
if (timeSelector.
|
|
1394
|
+
let timeSelector = this.container.querySelector(".drp-calendar .calendar-time.end-time");
|
|
1395
|
+
if (timeSelector.innerHTML != "") {
|
|
1339
1396
|
selected = selected.set({
|
|
1340
|
-
hour: !isNaN(selected.hour) ? selected.hour : timeSelector.
|
|
1341
|
-
minute: !isNaN(selected.minute) ? selected.minute : timeSelector.
|
|
1342
|
-
second: !isNaN(selected.second) ? selected.second : timeSelector.
|
|
1397
|
+
hour: !isNaN(selected.hour) ? selected.hour : timeSelector.querySelector(".hourselect option:selected").value,
|
|
1398
|
+
minute: !isNaN(selected.minute) ? selected.minute : timeSelector.querySelector(".minuteselect option:selected").value,
|
|
1399
|
+
second: !isNaN(selected.second) ? selected.second : timeSelector.querySelector(".secondselect option:selected").value
|
|
1343
1400
|
});
|
|
1344
1401
|
}
|
|
1345
1402
|
if (selected < this.#startDate)
|
|
@@ -1488,18 +1545,15 @@ class DateRangePicker {
|
|
|
1488
1545
|
html += "</div>";
|
|
1489
1546
|
}
|
|
1490
1547
|
html += "</div></th>";
|
|
1491
|
-
this.container.
|
|
1548
|
+
this.container.querySelector(`.drp-calendar .calendar-time.${side}-time`).innerHTML = html;
|
|
1492
1549
|
}
|
|
1493
1550
|
/**
|
|
1494
1551
|
* Disable the `Apply` button if no date value is selected
|
|
1495
1552
|
* @private
|
|
1496
1553
|
*/
|
|
1497
1554
|
setApplyBtnState() {
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
} else {
|
|
1501
|
-
this.container.find("button.applyBtn").prop("disabled", true);
|
|
1502
|
-
}
|
|
1555
|
+
const state = this.singleDatePicker || this.#endDate && this.#startDate <= this.#endDate;
|
|
1556
|
+
this.container.querySelector("button.applyBtn").disabled = !state;
|
|
1503
1557
|
}
|
|
1504
1558
|
/* #endregion */
|
|
1505
1559
|
/* #region Move/Show/Hide */
|
|
@@ -1508,115 +1562,102 @@ class DateRangePicker {
|
|
|
1508
1562
|
* @private
|
|
1509
1563
|
*/
|
|
1510
1564
|
move() {
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1565
|
+
let parentOffset = { top: 0, left: 0 };
|
|
1566
|
+
let containerTop;
|
|
1567
|
+
let containerLeft;
|
|
1568
|
+
let drops = this.drops;
|
|
1569
|
+
let parentRightEdge = window.innerWidth;
|
|
1570
|
+
if (!this.parentEl.matches("body")) {
|
|
1514
1571
|
parentOffset = {
|
|
1515
|
-
top: this.parentEl
|
|
1516
|
-
left: this.parentEl
|
|
1572
|
+
top: offset(this.parentEl).top - this.parentEl.scrollTop(),
|
|
1573
|
+
left: offset(this.parentEl).left - this.parentEl.scrollLeft()
|
|
1517
1574
|
};
|
|
1518
|
-
parentRightEdge = this.parentEl[0].clientWidth + this.parentEl
|
|
1575
|
+
parentRightEdge = this.parentEl[0].clientWidth + offset(this.parentEl).left;
|
|
1519
1576
|
}
|
|
1520
|
-
switch (drops) {
|
|
1577
|
+
switch (this.drops) {
|
|
1521
1578
|
case "auto":
|
|
1522
|
-
containerTop = this.element
|
|
1523
|
-
if (containerTop + this.container
|
|
1524
|
-
containerTop = this.element
|
|
1579
|
+
containerTop = offset(this.element).top + outerHeight(this.element) - parentOffset.top;
|
|
1580
|
+
if (containerTop + outerHeight(this.container) >= this.parentEl.scrollHeight) {
|
|
1581
|
+
containerTop = offset(this.element).top - outerHeight(this.container) - parentOffset.top;
|
|
1525
1582
|
drops = "up";
|
|
1526
1583
|
}
|
|
1527
1584
|
break;
|
|
1528
1585
|
case "up":
|
|
1529
|
-
containerTop = this.element
|
|
1586
|
+
containerTop = offset(this.element).top - outerHeight(this.container) - parentOffset.top;
|
|
1587
|
+
break;
|
|
1588
|
+
case "down":
|
|
1589
|
+
containerTop = offset(this.element).top + outerHeight(this.element) - parentOffset.top;
|
|
1530
1590
|
break;
|
|
1531
1591
|
default:
|
|
1532
|
-
|
|
1592
|
+
console.error(`Option drops '${drops}' not defined`);
|
|
1533
1593
|
break;
|
|
1534
1594
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
top: containerTop,
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
this.
|
|
1552
|
-
|
|
1553
|
-
right:
|
|
1554
|
-
|
|
1555
|
-
})
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
right:
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
});
|
|
1577
|
-
}
|
|
1578
|
-
} else {
|
|
1579
|
-
var containerLeft = this.element.offset().left - parentOffset.left;
|
|
1580
|
-
if (containerLeft + containerWidth > $(window).width()) {
|
|
1581
|
-
this.container.css({
|
|
1582
|
-
top: containerTop,
|
|
1583
|
-
left: "auto",
|
|
1584
|
-
right: 0
|
|
1585
|
-
});
|
|
1586
|
-
} else {
|
|
1587
|
-
this.container.css({
|
|
1588
|
-
top: containerTop,
|
|
1589
|
-
left: containerLeft,
|
|
1590
|
-
right: "auto"
|
|
1591
|
-
});
|
|
1592
|
-
}
|
|
1595
|
+
for (const [key2, value] of Object.entries({ top: 0, left: 0, right: "auto" }))
|
|
1596
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1597
|
+
const containerWidth = outerWidth(this.container);
|
|
1598
|
+
this.container.classList.toggle("drop-up", drops === "up");
|
|
1599
|
+
switch (this.opens) {
|
|
1600
|
+
case "left":
|
|
1601
|
+
const containerRight = parentRightEdge - offset(this.element).left - outerWidth(this.element);
|
|
1602
|
+
if (containerWidth + containerRight > window.innerWidth) {
|
|
1603
|
+
for (const [key2, value] of Object.entries({ top: containerTop, right: "auto", left: 9 }))
|
|
1604
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1605
|
+
} else {
|
|
1606
|
+
for (const [key2, value] of Object.entries({ top: containerTop, right: containerRight, left: "auto" }))
|
|
1607
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1608
|
+
}
|
|
1609
|
+
break;
|
|
1610
|
+
case "center":
|
|
1611
|
+
containerLeft = offset(this.element).left - parentOffset.left + outerWidth(this.element) / 2 - containerWidth / 2;
|
|
1612
|
+
if (containerLeft < 0) {
|
|
1613
|
+
for (const [key2, value] of Object.entries({ top: containerTop, right: "auto", left: 9 }))
|
|
1614
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1615
|
+
} else if (containerLeft + containerWidth > window.innerWidth) {
|
|
1616
|
+
for (const [key2, value] of Object.entries({ top: containerTop, left: "auto", right: 0 }))
|
|
1617
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1618
|
+
} else {
|
|
1619
|
+
for (const [key2, value] of Object.entries({ top: containerTop, left: containerLeft, right: "auto" }))
|
|
1620
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1621
|
+
}
|
|
1622
|
+
break;
|
|
1623
|
+
case "right":
|
|
1624
|
+
containerLeft = offset(this.element).left - parentOffset.left;
|
|
1625
|
+
if (containerLeft + containerWidth > window.innerWidth) {
|
|
1626
|
+
for (const [key2, value] of Object.entries({ top: containerTop, left: "auto", right: 0 }))
|
|
1627
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1628
|
+
} else {
|
|
1629
|
+
for (const [key2, value] of Object.entries({ top: `${containerTop}px`, left: containerLeft, right: "auto" }))
|
|
1630
|
+
this.container.style[key2] = typeof value === "number" && value > 0 ? `${value}px` : value;
|
|
1631
|
+
}
|
|
1632
|
+
break;
|
|
1633
|
+
default:
|
|
1634
|
+
console.error(`Option opens '${this.opens}' not defined`);
|
|
1635
|
+
break;
|
|
1593
1636
|
}
|
|
1594
1637
|
}
|
|
1595
1638
|
/**
|
|
1596
1639
|
* Shows the picker
|
|
1597
|
-
* @emits "show
|
|
1640
|
+
* @emits "show"
|
|
1598
1641
|
*/
|
|
1599
1642
|
show() {
|
|
1600
1643
|
if (this.isShowing) return;
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
this.move(e);
|
|
1607
|
-
}.bind(this));
|
|
1644
|
+
document.addEventListener("mousedown", this.#outsideClickProxy);
|
|
1645
|
+
document.addEventListener("touchend", this.#outsideClickProxy);
|
|
1646
|
+
document.addEventListener("click", this.#dropdownClickWrapper);
|
|
1647
|
+
document.addEventListener("focusin", this.#outsideClickProxy);
|
|
1648
|
+
window.addEventListener("resize", this.#onResizeProxy);
|
|
1608
1649
|
this.oldStartDate = this.#startDate;
|
|
1609
1650
|
this.oldEndDate = this.#endDate;
|
|
1610
1651
|
this.updateView(false);
|
|
1611
|
-
this.container.
|
|
1652
|
+
this.container.style.display = "block";
|
|
1612
1653
|
this.move();
|
|
1613
1654
|
this.triggerEvent(this.#events.onShow);
|
|
1614
1655
|
this.isShowing = true;
|
|
1615
1656
|
}
|
|
1616
1657
|
/**
|
|
1617
1658
|
* Hides the picker
|
|
1618
|
-
* @emits "beforeHide
|
|
1619
|
-
* @emits "hide
|
|
1659
|
+
* @emits "beforeHide"
|
|
1660
|
+
* @emits "hide"
|
|
1620
1661
|
*/
|
|
1621
1662
|
hide() {
|
|
1622
1663
|
if (!this.isShowing) return;
|
|
@@ -1627,11 +1668,15 @@ class DateRangePicker {
|
|
|
1627
1668
|
if (!this.#startDate.equals(this.oldStartDate) || !this.#endDate.equals(this.oldEndDate))
|
|
1628
1669
|
this.callback(this.startDate, this.endDate, this.chosenLabel);
|
|
1629
1670
|
this.updateElement();
|
|
1630
|
-
|
|
1671
|
+
const event = this.triggerEvent(this.#events.onBeforeHide);
|
|
1672
|
+
if (event.defaultPrevented)
|
|
1631
1673
|
return;
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1674
|
+
document.removeEventListener("mousedown", this.#outsideClickProxy);
|
|
1675
|
+
document.removeEventListener("touchend", this.#outsideClickProxy);
|
|
1676
|
+
document.removeEventListener("focusin", this.#outsideClickProxy);
|
|
1677
|
+
document.removeEventListener("click", this.#dropdownClickWrapper);
|
|
1678
|
+
window.removeEventListener("resize", this.#onResizeProxy);
|
|
1679
|
+
this.container.style.display = "none";
|
|
1635
1680
|
this.triggerEvent(this.#events.onHide);
|
|
1636
1681
|
this.isShowing = false;
|
|
1637
1682
|
}
|
|
@@ -1647,34 +1692,43 @@ class DateRangePicker {
|
|
|
1647
1692
|
}
|
|
1648
1693
|
/**
|
|
1649
1694
|
* Shows calendar when user selects "Custom Ranges"
|
|
1650
|
-
* @emits "showCalendar
|
|
1695
|
+
* @emits "showCalendar"
|
|
1651
1696
|
*/
|
|
1652
1697
|
showCalendars() {
|
|
1653
|
-
this.container.
|
|
1698
|
+
this.container.classList.add("show-calendar");
|
|
1654
1699
|
this.move();
|
|
1655
1700
|
this.triggerEvent(this.#events.onShowCalendar);
|
|
1656
1701
|
}
|
|
1657
1702
|
/**
|
|
1658
1703
|
* Hides calendar when user selects a predefined range
|
|
1659
|
-
* @emits "hideCalendar
|
|
1704
|
+
* @emits "hideCalendar"
|
|
1660
1705
|
*/
|
|
1661
1706
|
hideCalendars() {
|
|
1662
|
-
this.container.
|
|
1707
|
+
this.container.classList.remove("show-calendar");
|
|
1663
1708
|
this.triggerEvent(this.#events.onHideCalendar);
|
|
1664
1709
|
}
|
|
1665
1710
|
/* #endregion */
|
|
1666
1711
|
/* #region Handle mouse related events */
|
|
1667
1712
|
/**
|
|
1668
1713
|
* Closes the picker when user clicks outside
|
|
1669
|
-
* @param {external:
|
|
1670
|
-
* @emits "outsideClick
|
|
1714
|
+
* @param {external:Event} e - The Event target
|
|
1715
|
+
* @emits "outsideClick"
|
|
1671
1716
|
* @private
|
|
1672
1717
|
*/
|
|
1673
1718
|
outsideClick(e) {
|
|
1674
|
-
|
|
1719
|
+
const target = e.target;
|
|
1720
|
+
function closest2(el, selector) {
|
|
1721
|
+
let parent = el.parentElement;
|
|
1722
|
+
while (parent) {
|
|
1723
|
+
if (parent == selector)
|
|
1724
|
+
return parent;
|
|
1725
|
+
parent = parent.parentElement;
|
|
1726
|
+
}
|
|
1727
|
+
return null;
|
|
1728
|
+
}
|
|
1675
1729
|
if (
|
|
1676
1730
|
// ie modal dialog fix
|
|
1677
|
-
e.type === "focusin" || target
|
|
1731
|
+
e.type === "focusin" || closest2(target, this.element) || closest2(target, this.container) || target.closest(".calendar-table")
|
|
1678
1732
|
) return;
|
|
1679
1733
|
if (this.onOutsideClick === "cancel") {
|
|
1680
1734
|
this.#startDate = this.oldStartDate;
|
|
@@ -1685,12 +1739,12 @@ class DateRangePicker {
|
|
|
1685
1739
|
}
|
|
1686
1740
|
/**
|
|
1687
1741
|
* Move calendar to previous month
|
|
1688
|
-
* @param {external:
|
|
1742
|
+
* @param {external:Event} e - The Event target
|
|
1689
1743
|
* @private
|
|
1690
1744
|
*/
|
|
1691
1745
|
clickPrev(e) {
|
|
1692
|
-
|
|
1693
|
-
if (cal.
|
|
1746
|
+
let cal = e.target.closest(".drp-calendar");
|
|
1747
|
+
if (cal.classList.contains("left")) {
|
|
1694
1748
|
this.leftCalendar.month = this.leftCalendar.month.minus({ month: 1 });
|
|
1695
1749
|
if (this.linkedCalendars && !this.singleMonthView)
|
|
1696
1750
|
this.rightCalendar.month = this.rightCalendar.month.minus({ month: 1 });
|
|
@@ -1701,12 +1755,12 @@ class DateRangePicker {
|
|
|
1701
1755
|
}
|
|
1702
1756
|
/**
|
|
1703
1757
|
* Move calendar to next month
|
|
1704
|
-
* @param {external:
|
|
1758
|
+
* @param {external:Event} e - The Event target
|
|
1705
1759
|
* @private
|
|
1706
1760
|
*/
|
|
1707
1761
|
clickNext(e) {
|
|
1708
|
-
|
|
1709
|
-
if (cal.
|
|
1762
|
+
let cal = e.target.closest(".drp-calendar");
|
|
1763
|
+
if (cal.classList.contains("left")) {
|
|
1710
1764
|
this.leftCalendar.month = this.leftCalendar.month.plus({ month: 1 });
|
|
1711
1765
|
} else {
|
|
1712
1766
|
this.rightCalendar.month = this.rightCalendar.month.plus({ month: 1 });
|
|
@@ -1717,108 +1771,88 @@ class DateRangePicker {
|
|
|
1717
1771
|
}
|
|
1718
1772
|
/**
|
|
1719
1773
|
* User hovers over date values
|
|
1720
|
-
* @param {external:
|
|
1774
|
+
* @param {external:Event} e - The Event target
|
|
1721
1775
|
* @private
|
|
1722
1776
|
*/
|
|
1723
1777
|
hoverDate(e) {
|
|
1724
|
-
if (
|
|
1725
|
-
let title =
|
|
1778
|
+
if (!e.target.classList.contains("available")) return;
|
|
1779
|
+
let title = e.target.dataset.title;
|
|
1726
1780
|
const row = title.substring(1, 2);
|
|
1727
1781
|
const col = title.substring(3, 4);
|
|
1728
|
-
const cal =
|
|
1729
|
-
var date = cal.
|
|
1782
|
+
const cal = e.target(closest, ".drp-calendar");
|
|
1783
|
+
var date = cal.classList.contains("left") ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
|
|
1730
1784
|
const leftCalendar = this.leftCalendar;
|
|
1731
1785
|
const rightCalendar = this.rightCalendar;
|
|
1732
1786
|
const startDate = this.#startDate;
|
|
1733
1787
|
const initalMonth = this.initalMonth;
|
|
1734
1788
|
if (!this.#endDate) {
|
|
1735
|
-
this.container.
|
|
1736
|
-
if (
|
|
1737
|
-
const title2 =
|
|
1789
|
+
this.container.querySelectorAll(".drp-calendar tbody td").forEach((el) => {
|
|
1790
|
+
if (el.classList.contains("week")) return;
|
|
1791
|
+
const title2 = el.dataset.title;
|
|
1738
1792
|
const row2 = title2.substring(1, 2);
|
|
1739
1793
|
const col2 = title2.substring(3, 4);
|
|
1740
|
-
const cal2 =
|
|
1741
|
-
const dt = cal2.
|
|
1794
|
+
const cal2 = el.closest(".drp-calendar");
|
|
1795
|
+
const dt = cal2.classList.contains("left") ? leftCalendar.calendar[row2][col2] : rightCalendar.calendar[row2][col2];
|
|
1742
1796
|
if (!startDate && initalMonth) {
|
|
1743
|
-
|
|
1797
|
+
el.classList.remove("in-range");
|
|
1744
1798
|
} else {
|
|
1745
|
-
|
|
1746
|
-
$(el).addClass("in-range");
|
|
1747
|
-
} else {
|
|
1748
|
-
$(el).removeClass("in-range");
|
|
1749
|
-
}
|
|
1799
|
+
el.classList.toggle("in-range", dt > startDate && dt < date || dt.hasSame(date, "day"));
|
|
1750
1800
|
}
|
|
1751
1801
|
});
|
|
1752
1802
|
}
|
|
1753
1803
|
}
|
|
1754
1804
|
/**
|
|
1755
1805
|
* User hovers over ranges
|
|
1756
|
-
* @param {external:
|
|
1806
|
+
* @param {external:Event} e - The Event target
|
|
1757
1807
|
* @private
|
|
1758
1808
|
*/
|
|
1759
1809
|
hoverRange(e) {
|
|
1760
|
-
const label = e.target.
|
|
1810
|
+
const label = e.target.dataset.rangeKey;
|
|
1761
1811
|
const previousDates = [this.#startDate, this.#endDate];
|
|
1762
1812
|
const dates = this.ranges[label] ?? [this.#startDate, this.#endDate];
|
|
1763
1813
|
const leftCalendar = this.leftCalendar;
|
|
1764
1814
|
const rightCalendar = this.rightCalendar;
|
|
1765
|
-
this.container.
|
|
1766
|
-
if (
|
|
1767
|
-
const title =
|
|
1815
|
+
this.container.querySelectorAll(".drp-calendar tbody td").forEach((el) => {
|
|
1816
|
+
if (el.classList.contains("week")) return;
|
|
1817
|
+
const title = el.dataset.ttitle;
|
|
1768
1818
|
const row = title.substring(1, 2);
|
|
1769
1819
|
const col = title.substring(3, 4);
|
|
1770
|
-
const cal =
|
|
1771
|
-
const dt = cal.
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
classAdded = $(el).addClass("end-hover").length > 0;
|
|
1779
|
-
if (previousDates[1] != null && dt.hasSame(previousDates[1], "day"))
|
|
1780
|
-
classAdded = $(el).addClass("end-date").length > 0;
|
|
1781
|
-
if (dt.startOf("day") >= dates[0].startOf("day") && dt.startOf("day") <= dates[1].startOf("day"))
|
|
1782
|
-
classAdded = $(el).addClass("range-hover").length > 0;
|
|
1783
|
-
if (dt.startOf("day") >= previousDates[0].startOf("day") && previousDates[1] != null && dt.startOf("day") <= previousDates[1].startOf("day"))
|
|
1784
|
-
classAdded = $(el).addClass("in-range").length > 0;
|
|
1785
|
-
if (!classAdded) {
|
|
1786
|
-
$(el).removeClass("start-hover");
|
|
1787
|
-
$(el).removeClass("end-hover");
|
|
1788
|
-
$(el).removeClass("start-date");
|
|
1789
|
-
$(el).removeClass("end-date");
|
|
1790
|
-
$(el).removeClass("in-range");
|
|
1791
|
-
$(el).removeClass("range-hover");
|
|
1792
|
-
}
|
|
1820
|
+
const cal = el.closest(".drp-calendar");
|
|
1821
|
+
const dt = cal.classList.contains("left") ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];
|
|
1822
|
+
el.classList.toggle("start-hover", dt.hasSame(dates[0], "day"));
|
|
1823
|
+
el.classList.toggle("start-date", dt.hasSame(previousDates[0], "day"));
|
|
1824
|
+
el.classList.toggle("end-hover", dt.hasSame(dates[1], "day"));
|
|
1825
|
+
el.classList.toggle("end-date", previousDates[1] != null && dt.hasSame(previousDates[1], "day"));
|
|
1826
|
+
el.classList.toggle("range-hover", dt.startOf("day") >= dates[0].startOf("day") && dt.startOf("day") <= dates[1].startOf("day"));
|
|
1827
|
+
el.classList.toggle("in-range", dt.startOf("day") >= previousDates[0].startOf("day") && previousDates[1] != null && dt.startOf("day") <= previousDates[1].startOf("day"));
|
|
1793
1828
|
});
|
|
1794
1829
|
}
|
|
1795
1830
|
/**
|
|
1796
1831
|
* User leave ranges, remove hightlight from dates
|
|
1797
|
-
* @param {external:jQuery} e - The Event target
|
|
1798
1832
|
* @private
|
|
1799
1833
|
*/
|
|
1800
|
-
leaveRange(
|
|
1801
|
-
this.container.
|
|
1802
|
-
if (
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1834
|
+
leaveRange() {
|
|
1835
|
+
this.container.querySelectorAll(".drp-calendar tbody td").forEach((el) => {
|
|
1836
|
+
if (el.classList.contains("week")) return;
|
|
1837
|
+
el.classList.remove("start-hover");
|
|
1838
|
+
el.classList.remove("end-hover");
|
|
1839
|
+
el.classList.remove("range-hover");
|
|
1806
1840
|
});
|
|
1807
1841
|
}
|
|
1808
1842
|
/* #endregion */
|
|
1809
1843
|
/* #region Select values by Mouse */
|
|
1810
1844
|
/**
|
|
1811
1845
|
* Set date values after user selected a date
|
|
1812
|
-
* @param {external:
|
|
1846
|
+
* @param {external:Event} e - The Event target
|
|
1813
1847
|
* @private
|
|
1814
1848
|
*/
|
|
1815
1849
|
clickRange(e) {
|
|
1816
|
-
|
|
1850
|
+
let label = e.target.getAttribute("data-range-key");
|
|
1817
1851
|
this.chosenLabel = label;
|
|
1818
1852
|
if (label == this.locale.customRangeLabel) {
|
|
1819
1853
|
this.showCalendars();
|
|
1820
1854
|
} else {
|
|
1821
|
-
|
|
1855
|
+
let newDate = this.ranges[label];
|
|
1822
1856
|
const monthChange = !this.#startDate.hasSame(newDate[0], "month") || !this.#endDate.hasSame(newDate[1], "month");
|
|
1823
1857
|
this.#startDate = newDate[0];
|
|
1824
1858
|
this.#endDate = newDate[1];
|
|
@@ -1828,41 +1862,42 @@ class DateRangePicker {
|
|
|
1828
1862
|
}
|
|
1829
1863
|
if (!this.alwaysShowCalendars)
|
|
1830
1864
|
this.hideCalendars();
|
|
1831
|
-
|
|
1865
|
+
const event = this.triggerEvent(this.#events.onBeforeHide);
|
|
1866
|
+
if (event.defaultPrevented)
|
|
1832
1867
|
this.updateView(monthChange);
|
|
1833
1868
|
this.clickApply();
|
|
1834
1869
|
}
|
|
1835
1870
|
}
|
|
1836
1871
|
/**
|
|
1837
1872
|
* User clicked a date
|
|
1838
|
-
* @param {external:
|
|
1839
|
-
* @emits "dateChange
|
|
1873
|
+
* @param {external:Event} e - The Event target
|
|
1874
|
+
* @emits "dateChange"
|
|
1840
1875
|
* @private
|
|
1841
1876
|
*/
|
|
1842
1877
|
clickDate(e) {
|
|
1843
|
-
if (
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1878
|
+
if (!e.target.classList.contains("available")) return;
|
|
1879
|
+
let title = e.target.dataset.title;
|
|
1880
|
+
let row = title.substring(1, 2);
|
|
1881
|
+
let col = title.substring(3, 4);
|
|
1882
|
+
let cal = e.target.closest(".drp-calendar");
|
|
1883
|
+
let date = cal.classList.contains("left") ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
|
|
1849
1884
|
let side;
|
|
1850
1885
|
if (this.#endDate || !this.#startDate || date < this.#startDate.startOf("day")) {
|
|
1851
1886
|
if (this.timePicker) {
|
|
1852
|
-
let hour = parseInt(this.container.
|
|
1887
|
+
let hour = parseInt(this.container.querySelector(".start-time .hourselect").value, 10);
|
|
1853
1888
|
if (isNaN(hour))
|
|
1854
|
-
hour = parseInt(this.container.
|
|
1889
|
+
hour = parseInt(this.container.querySelector(".start-time .hourselect option:last-child").value, 10);
|
|
1855
1890
|
let minute = 0;
|
|
1856
1891
|
if (this.timePickerOpts.showMinutes) {
|
|
1857
|
-
minute = parseInt(this.container.
|
|
1892
|
+
minute = parseInt(this.container.querySelector(".start-time .minuteselect").value, 10);
|
|
1858
1893
|
if (isNaN(minute))
|
|
1859
|
-
minute = parseInt(this.container.
|
|
1894
|
+
minute = parseInt(this.container.querySelector(".start-time .minuteselect option:last-child").value, 10);
|
|
1860
1895
|
}
|
|
1861
1896
|
let second = 0;
|
|
1862
1897
|
if (this.timePickerOpts.showSeconds) {
|
|
1863
|
-
second = parseInt(this.container.
|
|
1898
|
+
second = parseInt(this.container.querySelector(".start-time .secondselect").value, 10);
|
|
1864
1899
|
if (isNaN(second))
|
|
1865
|
-
second = parseInt(this.container.
|
|
1900
|
+
second = parseInt(this.container.querySelector(".start-time .secondselect option:last-child").value, 10);
|
|
1866
1901
|
}
|
|
1867
1902
|
date = date.set({ hour, minute, second });
|
|
1868
1903
|
} else {
|
|
@@ -1876,20 +1911,20 @@ class DateRangePicker {
|
|
|
1876
1911
|
side = "end";
|
|
1877
1912
|
} else {
|
|
1878
1913
|
if (this.timePicker) {
|
|
1879
|
-
let hour = parseInt(this.container.
|
|
1914
|
+
let hour = parseInt(this.container.querySelector(".end-time .hourselect").value, 10);
|
|
1880
1915
|
if (isNaN(hour))
|
|
1881
|
-
hour = parseInt(this.container.
|
|
1916
|
+
hour = parseInt(this.container.querySelector(".end-time .hourselect option:last-child").value, 10);
|
|
1882
1917
|
let minute = 0;
|
|
1883
1918
|
if (this.timePickerOpts.showMinutes) {
|
|
1884
|
-
minute = parseInt(this.container.
|
|
1919
|
+
minute = parseInt(this.container.querySelector(".end-time .minuteselect").value, 10);
|
|
1885
1920
|
if (isNaN(minute))
|
|
1886
|
-
minute = parseInt(this.container.
|
|
1921
|
+
minute = parseInt(this.container.querySelector(".end-time .minuteselect option:last-child").value, 10);
|
|
1887
1922
|
}
|
|
1888
1923
|
let second = 0;
|
|
1889
1924
|
if (this.timePickerOpts.showSeconds) {
|
|
1890
|
-
second = parseInt(this.container.
|
|
1925
|
+
second = parseInt(this.container.querySelector(".end-time .secondselect").value, 10);
|
|
1891
1926
|
if (isNaN(second))
|
|
1892
|
-
second = parseInt(this.container.
|
|
1927
|
+
second = parseInt(this.container.querySelector(".end-time .secondselect option:last-child").value, 10);
|
|
1893
1928
|
}
|
|
1894
1929
|
date = date.set({ hour, minute, second });
|
|
1895
1930
|
} else {
|
|
@@ -1912,13 +1947,15 @@ class DateRangePicker {
|
|
|
1912
1947
|
e.stopPropagation();
|
|
1913
1948
|
if (this.autoUpdateInput)
|
|
1914
1949
|
this.updateElement();
|
|
1915
|
-
this.triggerEvent(this.#events.onDateChange, side);
|
|
1950
|
+
this.triggerEvent(this.#events.onDateChange, { side });
|
|
1916
1951
|
}
|
|
1917
1952
|
/**
|
|
1918
1953
|
* Hightlight selected predefined range in calendar
|
|
1919
1954
|
* @private
|
|
1920
1955
|
*/
|
|
1921
1956
|
calculateChosenLabel() {
|
|
1957
|
+
if (Object.keys(this.ranges).length === 0)
|
|
1958
|
+
return;
|
|
1922
1959
|
var customRange = true;
|
|
1923
1960
|
var i = 0;
|
|
1924
1961
|
for (var range in this.ranges) {
|
|
@@ -1932,14 +1969,18 @@ class DateRangePicker {
|
|
|
1932
1969
|
}
|
|
1933
1970
|
if (this.#startDate.startOf(unit).equals(this.ranges[range][0].startOf(unit)) && this.#endDate.startOf(unit).equals(this.ranges[range][1].startOf(unit))) {
|
|
1934
1971
|
customRange = false;
|
|
1935
|
-
|
|
1972
|
+
const range2 = this.container.querySelector(`.ranges li:eq(${i})`);
|
|
1973
|
+
this.chosenLabel = range2.dataset.rangeKey;
|
|
1974
|
+
range2.classList.add("active");
|
|
1936
1975
|
break;
|
|
1937
1976
|
}
|
|
1938
1977
|
i++;
|
|
1939
1978
|
}
|
|
1940
1979
|
if (customRange) {
|
|
1941
1980
|
if (this.showCustomRangeLabel) {
|
|
1942
|
-
|
|
1981
|
+
const range2 = this.container.querySelector(".ranges li:last-child");
|
|
1982
|
+
this.chosenLabel = range2.dataset.rangeKey;
|
|
1983
|
+
range2.classList.add("active");
|
|
1943
1984
|
} else {
|
|
1944
1985
|
this.chosenLabel = null;
|
|
1945
1986
|
}
|
|
@@ -1948,25 +1989,23 @@ class DateRangePicker {
|
|
|
1948
1989
|
}
|
|
1949
1990
|
/**
|
|
1950
1991
|
* User clicked a time
|
|
1951
|
-
* @param {external:
|
|
1952
|
-
* @emits "timeChange
|
|
1992
|
+
* @param {external:Event} e - The Event target
|
|
1993
|
+
* @emits "timeChange"
|
|
1953
1994
|
* @private
|
|
1954
1995
|
*/
|
|
1955
1996
|
timeChanged(e) {
|
|
1956
|
-
const time =
|
|
1957
|
-
;
|
|
1958
|
-
|
|
1959
|
-
var hour = parseInt(time.find(".hourselect").val(), 10);
|
|
1997
|
+
const time = e.target.closest(".calendar-time");
|
|
1998
|
+
const side = time.classList.contains("start-time") ? "start" : "end";
|
|
1999
|
+
var hour = parseInt(time.querySelector(".hourselect").value, 10);
|
|
1960
2000
|
if (isNaN(hour))
|
|
1961
|
-
hour = parseInt(time.
|
|
2001
|
+
hour = parseInt(time.querySelector(".hourselect option:last-child").value, 10);
|
|
1962
2002
|
if (!this.timePicker24Hour) {
|
|
1963
|
-
const ampm = time.
|
|
2003
|
+
const ampm = time.querySelector(".ampmselect").value;
|
|
1964
2004
|
if (ampm == null)
|
|
1965
|
-
time.
|
|
2005
|
+
time.querySelector(".ampmselect option:last-child").value;
|
|
1966
2006
|
if (ampm != DateTime.fromFormat(`${hour}`, "H").toFormat("a", { locale: "en-US" })) {
|
|
1967
|
-
time.
|
|
1968
|
-
|
|
1969
|
-
$(this).attr("hidden", hidden);
|
|
2007
|
+
time.querySelectorAll(".hourselect > option").forEach((el) => {
|
|
2008
|
+
el.hidden = !el.hidden;
|
|
1970
2009
|
});
|
|
1971
2010
|
const h = DateTime.fromFormat(`${hour}`, "H").toFormat("h");
|
|
1972
2011
|
hour = DateTime.fromFormat(`${h}${ampm}`, "ha", { locale: "en-US" }).hour;
|
|
@@ -1974,15 +2013,15 @@ class DateRangePicker {
|
|
|
1974
2013
|
}
|
|
1975
2014
|
var minute = 0;
|
|
1976
2015
|
if (this.timePickerOpts.showMinutes) {
|
|
1977
|
-
minute = parseInt(time.
|
|
2016
|
+
minute = parseInt(time.querySelector(".minuteselect").value, 10);
|
|
1978
2017
|
if (isNaN(minute))
|
|
1979
|
-
minute = parseInt(time.
|
|
2018
|
+
minute = parseInt(time.querySelector(".minuteselect option:last-child").value, 10);
|
|
1980
2019
|
}
|
|
1981
2020
|
var second = 0;
|
|
1982
2021
|
if (this.timePickerOpts.showSeconds) {
|
|
1983
|
-
second = parseInt(time.
|
|
2022
|
+
second = parseInt(time.querySelector(".secondselect").value, 10);
|
|
1984
2023
|
if (isNaN(second))
|
|
1985
|
-
second = parseInt(time.
|
|
2024
|
+
second = parseInt(time.querySelector(".secondselect option:last-child").value, 10);
|
|
1986
2025
|
}
|
|
1987
2026
|
if (side === "start") {
|
|
1988
2027
|
if (this.#startDate)
|
|
@@ -2002,17 +2041,19 @@ class DateRangePicker {
|
|
|
2002
2041
|
this.renderTimePicker("end");
|
|
2003
2042
|
if (this.autoUpdateInput)
|
|
2004
2043
|
this.updateElement();
|
|
2005
|
-
this.triggerEvent(this.#events.onTimeChange, this.singleDatePicker ? null : side);
|
|
2044
|
+
this.triggerEvent(this.#events.onTimeChange, { side: this.singleDatePicker ? null : side });
|
|
2006
2045
|
}
|
|
2007
2046
|
/**
|
|
2008
2047
|
* Calender month moved
|
|
2009
|
-
* @param {external:
|
|
2048
|
+
* @param {external:Event} e - The Event target
|
|
2010
2049
|
* @private
|
|
2011
2050
|
*/
|
|
2012
2051
|
monthOrYearChanged(e) {
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2052
|
+
const isLeft = e.target.closest(".drp-calendar").classList.contains("left");
|
|
2053
|
+
const leftOrRight = isLeft ? "left" : "right";
|
|
2054
|
+
const cal = this.container.querySelector(`.drp-calendar.${leftOrRight}`);
|
|
2055
|
+
let month = parseInt(cal.querySelector(".monthselect").value, 10);
|
|
2056
|
+
let year = cal.querySelector(".yearselect").value;
|
|
2016
2057
|
let monthChange = false;
|
|
2017
2058
|
if (!isLeft) {
|
|
2018
2059
|
if (year < this.#startDate.year || year == this.#startDate.year && month < this.#startDate.month) {
|
|
@@ -2047,7 +2088,7 @@ class DateRangePicker {
|
|
|
2047
2088
|
}
|
|
2048
2089
|
/**
|
|
2049
2090
|
* User clicked `Apply` button
|
|
2050
|
-
* @emits "apply
|
|
2091
|
+
* @emits "apply"
|
|
2051
2092
|
* @private
|
|
2052
2093
|
*/
|
|
2053
2094
|
clickApply() {
|
|
@@ -2056,7 +2097,7 @@ class DateRangePicker {
|
|
|
2056
2097
|
}
|
|
2057
2098
|
/**
|
|
2058
2099
|
* User clicked `Cancel` button
|
|
2059
|
-
* @emits "cancel
|
|
2100
|
+
* @emits "cancel"
|
|
2060
2101
|
* @private
|
|
2061
2102
|
*/
|
|
2062
2103
|
clickCancel() {
|
|
@@ -2068,18 +2109,18 @@ class DateRangePicker {
|
|
|
2068
2109
|
/* #endregion */
|
|
2069
2110
|
/**
|
|
2070
2111
|
* Update the picker with value from `<input>` element.<br>
|
|
2071
|
-
* Input values must be given in format of `locale.format`. Invalid values are handles by `
|
|
2072
|
-
* @emits "inputChange
|
|
2112
|
+
* Input values must be given in format of `locale.format`. Invalid values are handles by `violate` Event
|
|
2113
|
+
* @emits "inputChange"
|
|
2073
2114
|
* @private
|
|
2074
2115
|
*/
|
|
2075
2116
|
elementChanged() {
|
|
2076
|
-
if (!this.
|
|
2077
|
-
if (!this.element.
|
|
2117
|
+
if (!this.isInputText) return;
|
|
2118
|
+
if (!this.element.value.length) return;
|
|
2078
2119
|
const format = typeof this.locale.format === "string" ? this.locale.format : DateTime.parseFormatForOpts(this.locale.format);
|
|
2079
|
-
const dateString = this.element.
|
|
2120
|
+
const dateString = this.element.value.split(this.locale.separator);
|
|
2080
2121
|
let monthChange = false;
|
|
2081
2122
|
if (this.singleDatePicker) {
|
|
2082
|
-
let newDate = DateTime.fromFormat(this.element.
|
|
2123
|
+
let newDate = DateTime.fromFormat(this.element.value, format, { locale: DateTime.now().locale });
|
|
2083
2124
|
const oldDate = this.#startDate;
|
|
2084
2125
|
if (!newDate.isValid || oldDate.equals(newDate))
|
|
2085
2126
|
return;
|
|
@@ -2128,13 +2169,12 @@ class DateRangePicker {
|
|
|
2128
2169
|
}
|
|
2129
2170
|
/**
|
|
2130
2171
|
* Handles key press, IE 11 compatibility
|
|
2131
|
-
* @param {external:
|
|
2172
|
+
* @param {external:Event} e - The Event target
|
|
2132
2173
|
* @private
|
|
2133
2174
|
*/
|
|
2134
2175
|
keydown(e) {
|
|
2135
|
-
if (
|
|
2176
|
+
if ([9, 11].includes(e.keyCode))
|
|
2136
2177
|
this.hide();
|
|
2137
|
-
}
|
|
2138
2178
|
if (e.keyCode === 27) {
|
|
2139
2179
|
e.preventDefault();
|
|
2140
2180
|
e.stopPropagation();
|
|
@@ -2148,7 +2188,7 @@ class DateRangePicker {
|
|
|
2148
2188
|
updateElement() {
|
|
2149
2189
|
if (this.#startDate == null && this.initalMonth)
|
|
2150
2190
|
return;
|
|
2151
|
-
if (this.
|
|
2191
|
+
if (this.isInputText) {
|
|
2152
2192
|
let newValue = this.formatDate(this.#startDate);
|
|
2153
2193
|
if (!this.singleDatePicker) {
|
|
2154
2194
|
newValue += this.locale.separator;
|
|
@@ -2156,8 +2196,10 @@ class DateRangePicker {
|
|
|
2156
2196
|
newValue += this.formatDate(this.#endDate);
|
|
2157
2197
|
}
|
|
2158
2198
|
this.updateAltInput();
|
|
2159
|
-
if (newValue !== this.element.
|
|
2160
|
-
this.element.
|
|
2199
|
+
if (newValue !== this.element.value) {
|
|
2200
|
+
this.element.value = newValue;
|
|
2201
|
+
this.element.dispatchEvent(new Event("change", { bubbles: true }));
|
|
2202
|
+
}
|
|
2161
2203
|
} else {
|
|
2162
2204
|
this.updateAltInput();
|
|
2163
2205
|
}
|
|
@@ -2168,8 +2210,6 @@ class DateRangePicker {
|
|
|
2168
2210
|
updateAltInput() {
|
|
2169
2211
|
if (this.altInput == null)
|
|
2170
2212
|
return;
|
|
2171
|
-
if (this.singleDatePicker)
|
|
2172
|
-
$(this.altInput[1]).val(null);
|
|
2173
2213
|
if (this.altFormat == null) {
|
|
2174
2214
|
let precision = "day";
|
|
2175
2215
|
if (this.timePicker) {
|
|
@@ -2182,17 +2222,17 @@ class DateRangePicker {
|
|
|
2182
2222
|
}
|
|
2183
2223
|
}
|
|
2184
2224
|
const startDate = this.#startDate.toISO({ format: "basic", precision, includeOffset: false });
|
|
2185
|
-
|
|
2225
|
+
(this.singleDatePicker ? this.altInput : this.altInput[0]).value = startDate;
|
|
2186
2226
|
if (!this.singleDatePicker && this.#endDate) {
|
|
2187
2227
|
const endDate = this.#endDate.toISO({ format: "basic", precision, includeOffset: false });
|
|
2188
|
-
|
|
2228
|
+
this.altInput[1].value = endDate;
|
|
2189
2229
|
}
|
|
2190
2230
|
} else {
|
|
2191
2231
|
const startDate = typeof this.altFormat === "function" ? this.altFormat(this.#startDate) : this.formatDate(this.#startDate, this.altFormat);
|
|
2192
|
-
|
|
2232
|
+
(this.singleDatePicker ? this.altInput : this.altInput[0]).value = startDate;
|
|
2193
2233
|
if (!this.singleDatePicker && this.#endDate) {
|
|
2194
2234
|
const endDate = typeof this.altFormat === "function" ? this.altFormat(this.#endDate) : this.formatDate(this.#endDate, this.altFormat);
|
|
2195
|
-
|
|
2235
|
+
this.altInput[1].value = endDate;
|
|
2196
2236
|
}
|
|
2197
2237
|
}
|
|
2198
2238
|
}
|
|
@@ -2200,52 +2240,140 @@ class DateRangePicker {
|
|
|
2200
2240
|
* Removes the picker from document
|
|
2201
2241
|
*/
|
|
2202
2242
|
remove() {
|
|
2243
|
+
this.element.removeEventListener("click", this.#showProxy);
|
|
2244
|
+
this.element.removeEventListener("focus", this.#showProxy);
|
|
2245
|
+
this.element.removeEventListener("keyup", this.#elementChangedProxy);
|
|
2246
|
+
this.element.removeEventListener("keydown", this.#keydownProxy);
|
|
2247
|
+
this.element.removeEventListener("click", this.#toggleProxy);
|
|
2248
|
+
this.element.removeEventListener("keydown", this.#toggleProxy);
|
|
2203
2249
|
this.container.remove();
|
|
2204
|
-
this.element.off(".daterangepicker");
|
|
2205
|
-
this.element.removeData();
|
|
2206
2250
|
}
|
|
2207
2251
|
/**
|
|
2208
|
-
* Helper function to
|
|
2252
|
+
* Helper function to dispatch events
|
|
2209
2253
|
* @param {Event} ev - From this.#events
|
|
2210
|
-
* @param {...any} args -
|
|
2254
|
+
* @param {...any?} args - Additional parameters if needed
|
|
2211
2255
|
* @private
|
|
2212
2256
|
*/
|
|
2213
2257
|
triggerEvent(ev, ...args) {
|
|
2214
2258
|
if (args.length === 0) {
|
|
2215
|
-
this
|
|
2259
|
+
const event = new DateRangePickerEvent(this, ev);
|
|
2260
|
+
this.element.dispatchEvent(event);
|
|
2261
|
+
return event;
|
|
2216
2262
|
} else {
|
|
2217
|
-
const
|
|
2218
|
-
this.element.
|
|
2263
|
+
const event = new DateRangePickerEvent(this, ev, ...args);
|
|
2264
|
+
this.element.dispatchEvent(event);
|
|
2265
|
+
return event;
|
|
2219
2266
|
}
|
|
2220
2267
|
}
|
|
2221
2268
|
/**
|
|
2222
|
-
* Helper function to
|
|
2223
|
-
* @param {
|
|
2224
|
-
* @param
|
|
2225
|
-
* @
|
|
2269
|
+
* Helper function to add eventListener similar to jQuery .on( events [, selector ] [, data ] )
|
|
2270
|
+
* @param {string} element - Query selector of element where listener is added
|
|
2271
|
+
* @param {string} eventName - Name of the event
|
|
2272
|
+
* @param {string} selector - Query selector string to filter the descendants of the element
|
|
2273
|
+
* @param {any} delegate - Handler data
|
|
2226
2274
|
*/
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2275
|
+
addListener(element, eventName, selector, delegate) {
|
|
2276
|
+
this.container.querySelectorAll(element).forEach((el) => {
|
|
2277
|
+
el.addEventListener(eventName, function(event) {
|
|
2278
|
+
const target = event.target.closest(selector);
|
|
2279
|
+
if (target && el.contains(target))
|
|
2280
|
+
delegate.call(target, event);
|
|
2281
|
+
});
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
function createElementFromHTML(html) {
|
|
2286
|
+
const template = document.createElement("template");
|
|
2287
|
+
template.innerHTML = html.trim();
|
|
2288
|
+
return template.content.firstElementChild;
|
|
2289
|
+
}
|
|
2290
|
+
class DateRangePickerEvent extends Event {
|
|
2291
|
+
#picker;
|
|
2292
|
+
constructor(drp, ev, args = {}) {
|
|
2293
|
+
let param = {};
|
|
2294
|
+
if (ev.param)
|
|
2295
|
+
param = typeof ev.param === "function" ? ev.param() : ev.param;
|
|
2296
|
+
param = { ...param, ...args };
|
|
2297
|
+
super(ev.type, param);
|
|
2298
|
+
this.#picker = drp;
|
|
2299
|
+
for (const [key2, value] of Object.entries(param)) {
|
|
2300
|
+
if (Object.getOwnPropertyNames(Event.prototype).includes(key2)) continue;
|
|
2301
|
+
this[key2] = value;
|
|
2233
2302
|
}
|
|
2234
2303
|
}
|
|
2304
|
+
get picker() {
|
|
2305
|
+
return this.#picker;
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
function offset(el) {
|
|
2309
|
+
const rect = el.getBoundingClientRect();
|
|
2310
|
+
return {
|
|
2311
|
+
top: rect.top + window.scrollY,
|
|
2312
|
+
left: rect.left + window.scrollX
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
function outerWidth(el, withMargin = false) {
|
|
2316
|
+
if (!withMargin)
|
|
2317
|
+
return el.offsetWidth;
|
|
2318
|
+
const style = getComputedStyle(el);
|
|
2319
|
+
return el.offsetWidth + parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
|
2320
|
+
}
|
|
2321
|
+
function outerHeight(el, withMargin = false) {
|
|
2322
|
+
if (!withMargin)
|
|
2323
|
+
return el.offsetHeight;
|
|
2324
|
+
const style = getComputedStyle(el);
|
|
2325
|
+
return el.offsetHeight + parseFloat(style.marginTop) + parseFloat(style.marginBottom);
|
|
2326
|
+
}
|
|
2327
|
+
function daterangepicker(elements, options, callback) {
|
|
2328
|
+
if (typeof elements === "string")
|
|
2329
|
+
return daterangepicker(document.querySelectorAll(elements), options, callback);
|
|
2330
|
+
if (elements instanceof HTMLElement)
|
|
2331
|
+
elements = [elements];
|
|
2332
|
+
if (elements instanceof NodeList || elements instanceof HTMLCollection)
|
|
2333
|
+
elements = Array.from(elements);
|
|
2334
|
+
if (elements == null)
|
|
2335
|
+
return new DateRangePicker(null, options || {}, callback);
|
|
2336
|
+
elements.forEach((el) => {
|
|
2337
|
+
if (el._daterangepicker && typeof el._daterangepicker.remove === "function")
|
|
2338
|
+
el._daterangepicker.remove();
|
|
2339
|
+
el._daterangepicker = new DateRangePicker(el, options || {}, callback);
|
|
2340
|
+
});
|
|
2341
|
+
return elements.length === 1 ? elements[0] : elements;
|
|
2235
2342
|
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2343
|
+
function getDateRangePicker(target) {
|
|
2344
|
+
if (typeof target === "string")
|
|
2345
|
+
target = document.querySelector(target);
|
|
2346
|
+
return target instanceof HTMLElement ? target._daterangepicker : void 0;
|
|
2347
|
+
}
|
|
2348
|
+
if (window.jQuery?.fn) {
|
|
2349
|
+
jQuery.fn.daterangepicker = function(options, callback) {
|
|
2350
|
+
return this.each(function() {
|
|
2351
|
+
daterangepicker(this, options, callback);
|
|
2244
2352
|
});
|
|
2245
|
-
return this;
|
|
2246
2353
|
};
|
|
2247
2354
|
}
|
|
2248
|
-
|
|
2355
|
+
function registerJqueryPlugin(jq) {
|
|
2356
|
+
if (!jq?.fn) return;
|
|
2357
|
+
jq.fn.daterangepicker = function(options, callback) {
|
|
2358
|
+
return this.each(function() {
|
|
2359
|
+
daterangepicker(this, options, callback);
|
|
2360
|
+
});
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
Object.defineProperty(window, "jQuery", {
|
|
2364
|
+
configurable: true,
|
|
2365
|
+
set(value) {
|
|
2366
|
+
this._jQuery = value;
|
|
2367
|
+
registerJqueryPlugin(value);
|
|
2368
|
+
},
|
|
2369
|
+
get() {
|
|
2370
|
+
return this._jQuery;
|
|
2371
|
+
}
|
|
2372
|
+
});
|
|
2373
|
+
var daterangepicker_default = daterangepicker;
|
|
2249
2374
|
export {
|
|
2250
|
-
|
|
2375
|
+
DateRangePicker,
|
|
2376
|
+
daterangepicker,
|
|
2377
|
+
daterangepicker_default as default,
|
|
2378
|
+
getDateRangePicker
|
|
2251
2379
|
};
|