@wernfried/daterangepicker 4.0.0 → 4.15.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.
@@ -0,0 +1,1952 @@
1
+ var DateRangePicker = (() => {
2
+ const DateTime = luxon.DateTime;
3
+ const Duration = luxon.Duration;
4
+ const Info = luxon.Info;
5
+ const Settings = luxon.Settings;
6
+ class DateRangePicker {
7
+ constructor(element, options, cb) {
8
+ this.parentEl = "body";
9
+ this.element = $(element);
10
+ this.startDate = DateTime.now().startOf("day");
11
+ this.endDate = DateTime.now().endOf("day");
12
+ this.minDate = null;
13
+ this.maxDate = null;
14
+ this.maxSpan = null;
15
+ this.minSpan = null;
16
+ this.defaultSpan = null;
17
+ this.initalMonth = DateTime.now().startOf("month");
18
+ this.autoApply = false;
19
+ this.singleDatePicker = false;
20
+ this.singleMonthView = false;
21
+ this.showDropdowns = false;
22
+ this.minYear = DateTime.now().minus({ year: 100 }).year;
23
+ this.maxYear = DateTime.now().plus({ year: 100 }).year;
24
+ this.showWeekNumbers = false;
25
+ this.showISOWeekNumbers = false;
26
+ this.showCustomRangeLabel = true;
27
+ this.timePicker = false;
28
+ const usesMeridiems = new Intl.DateTimeFormat(DateTime.now().locale, { hour: "numeric" }).resolvedOptions();
29
+ this.timePicker24Hour = !usesMeridiems.hour12;
30
+ this.timePickerStepSize = Duration.fromObject({ minutes: 1 });
31
+ this.linkedCalendars = true;
32
+ this.autoUpdateInput = true;
33
+ this.alwaysShowCalendars = false;
34
+ this.isInvalidDate = null;
35
+ this.isInvalidTime = null;
36
+ this.isCustomDate = null;
37
+ this.onOutsideClick = "apply";
38
+ this.opens = this.element.hasClass("pull-right") ? "left" : "right";
39
+ this.drops = this.element.hasClass("dropup") ? "up" : "down";
40
+ this.buttonClasses = "btn btn-sm";
41
+ this.applyButtonClasses = "btn-primary";
42
+ this.cancelButtonClasses = "btn-default";
43
+ this.weekendClasses = "weekend";
44
+ this.weekendDayClasses = "weekend-day";
45
+ this.todayClasses = "today";
46
+ this.altInput = null;
47
+ this.altFormat = null;
48
+ this.externalStyle = null;
49
+ this.ranges = {};
50
+ this.locale = {
51
+ direction: "ltr",
52
+ format: DateTime.DATE_SHORT,
53
+ // or DateTime.DATETIME_SHORT when timePicker: true
54
+ separator: " - ",
55
+ applyLabel: "Apply",
56
+ cancelLabel: "Cancel",
57
+ weekLabel: "W",
58
+ customRangeLabel: "Custom Range",
59
+ daysOfWeek: Info.weekdays("short"),
60
+ monthNames: Info.months("long"),
61
+ firstDay: Info.getStartOfWeek(),
62
+ durationFormat: null
63
+ };
64
+ this.callback = function() {
65
+ };
66
+ this.isShowing = false;
67
+ this.leftCalendar = {};
68
+ this.rightCalendar = {};
69
+ if (typeof options !== "object" || options === null)
70
+ options = {};
71
+ options = $.extend(this.element.data(), options);
72
+ if (typeof options.singleDatePicker === "boolean")
73
+ this.singleDatePicker = options.singleDatePicker;
74
+ if (!this.singleDatePicker && typeof options.singleMonthView === "boolean") {
75
+ this.singleMonthView = options.singleMonthView;
76
+ } else {
77
+ this.singleMonthView = false;
78
+ }
79
+ if (typeof options.externalStyle === "string" && ["bulma"].includes(options.externalStyle))
80
+ this.externalStyle = options.externalStyle;
81
+ if (typeof options.template !== "string" && !(options.template instanceof $)) {
82
+ let template = [
83
+ '<div class="daterangepicker">',
84
+ '<div class="ranges"></div>',
85
+ '<div class="drp-calendar left">',
86
+ '<table class="calendar-table">',
87
+ "<thead></thead>",
88
+ "<tbody></tbody>",
89
+ "<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(...[
95
+ "</tfoot>",
96
+ "</table>",
97
+ "</div>"
98
+ ]);
99
+ template.push(...[
100
+ '<div class="drp-calendar right">',
101
+ '<table class="calendar-table">',
102
+ "<thead></thead>",
103
+ "<tbody></tbody>",
104
+ "<tfoot>",
105
+ '<tr class="calendar-time end-time"></tr>',
106
+ "</tfoot>",
107
+ "</table>",
108
+ "</div>"
109
+ ]);
110
+ template.push(...[
111
+ '<div class="drp-buttons">',
112
+ '<div class="drp-duration-label"></div>',
113
+ '<div class="drp-selected"></div>'
114
+ ]);
115
+ if (this.externalStyle === "bulma") {
116
+ template.push(...[
117
+ '<div class="buttons">',
118
+ '<button class="cancelBtn button is-small" type="button"></button>',
119
+ '<button class="applyBtn button is-small" disabled type="button"></button>',
120
+ "</div>"
121
+ ]);
122
+ } else {
123
+ template.push(...[
124
+ "<div>",
125
+ '<button class="cancelBtn" type="button"></button>',
126
+ '<button class="applyBtn" disabled type="button"></button>',
127
+ "</div>"
128
+ ]);
129
+ }
130
+ template.push("</div></div>");
131
+ options.template = template.join("");
132
+ }
133
+ this.parentEl = options.parentEl && $(options.parentEl).length ? $(options.parentEl) : $(this.parentEl);
134
+ this.container = $(options.template).appendTo(this.parentEl);
135
+ if (typeof options.timePicker === "boolean")
136
+ this.timePicker = options.timePicker;
137
+ if (this.timePicker)
138
+ this.locale.format = DateTime.DATETIME_SHORT;
139
+ if (typeof options.locale === "object") {
140
+ for (let key2 of ["separator", "applyLabel", "cancelLabel", "weekLabel"]) {
141
+ if (typeof options.locale[key2] === "string")
142
+ this.locale[key2] = options.locale[key2];
143
+ }
144
+ if (typeof options.locale.direction === "string") {
145
+ if (["rtl", "ltr"].includes(options.locale.direction))
146
+ this.locale.direction = options.locale.direction;
147
+ else
148
+ console.error(`Option 'options.locale.direction' must be 'rtl' or 'ltr'`);
149
+ }
150
+ if (["string", "object"].includes(typeof options.locale.format))
151
+ this.locale.format = options.locale.format;
152
+ if (Array.isArray(options.locale.daysOfWeek)) {
153
+ if (options.locale.daysOfWeek.some((x) => typeof x !== "string"))
154
+ console.error(`Option 'options.locale.daysOfWeek' must be an array of strings`);
155
+ else
156
+ this.locale.daysOfWeek = options.locale.daysOfWeek.slice();
157
+ }
158
+ if (Array.isArray(options.locale.monthNames)) {
159
+ if (options.locale.monthNames.some((x) => typeof x !== "string"))
160
+ console.error(`Option 'locale.monthNames' must be an array of strings`);
161
+ else
162
+ this.locale.monthNames = options.locale.monthNames.slice();
163
+ }
164
+ if (typeof options.locale.firstDay === "number")
165
+ this.locale.firstDay = options.locale.firstDay;
166
+ if (typeof options.locale.customRangeLabel === "string") {
167
+ var elem = document.createElement("textarea");
168
+ elem.innerHTML = options.locale.customRangeLabel;
169
+ var rangeHtml = elem.value;
170
+ this.locale.customRangeLabel = rangeHtml;
171
+ }
172
+ if (["string", "object", "function"].includes(typeof options.locale.durationFormat) && options.locale.durationFormat != null)
173
+ this.locale.durationFormat = options.locale.durationFormat;
174
+ }
175
+ this.container.addClass(this.locale.direction);
176
+ for (let key2 of [
177
+ "timePicker24Hour",
178
+ "showWeekNumbers",
179
+ "showISOWeekNumbers",
180
+ "showDropdowns",
181
+ "linkedCalendars",
182
+ "showCustomRangeLabel",
183
+ "alwaysShowCalendars",
184
+ "autoApply",
185
+ "autoUpdateInput"
186
+ ]) {
187
+ if (typeof options[key2] === "boolean")
188
+ this[key2] = options[key2];
189
+ }
190
+ for (let key2 of ["applyButtonClasses", "cancelButtonClasses", "weekendClasses", "weekendDayClasses", "todayClasses"]) {
191
+ if (typeof options[key2] === "string") {
192
+ this[key2] = options[key2];
193
+ } else if (["weekendClasses", "weekendDayClasses", "todayClasses"].includes(key2) && options[key2] === null) {
194
+ this[key2] = options[key2];
195
+ }
196
+ }
197
+ for (let key2 of ["minYear", "maxYear"]) {
198
+ if (typeof options[key2] === "number")
199
+ this[key2] = options[key2];
200
+ }
201
+ for (let key2 of ["isInvalidDate", "isInvalidTime", "isCustomDate"]) {
202
+ if (typeof options[key2] === "function")
203
+ this[key2] = options[key2];
204
+ else
205
+ this[key2] = function() {
206
+ return false;
207
+ };
208
+ }
209
+ if (!this.singleDatePicker) {
210
+ for (let opt of ["minSpan", "maxSpan", "defaultSpan"]) {
211
+ if (["string", "number", "object"].includes(typeof options[opt])) {
212
+ if (Duration.isDuration(options[opt]) && options[opt].isValid) {
213
+ this[opt] = options[opt];
214
+ } else if (Duration.fromISO(options[opt]).isValid) {
215
+ this[opt] = Duration.fromISO(options[opt]);
216
+ } else if (typeof options[opt] === "number" && Duration.fromObject({ seconds: options[opt] }).isValid) {
217
+ this[opt] = Duration.fromObject({ seconds: options[opt] });
218
+ } else if (options[opt] === null) {
219
+ this[opt] = null;
220
+ } else {
221
+ console.error(`Option '${key}' is not valid`);
222
+ }
223
+ ;
224
+ }
225
+ }
226
+ if (this.minSpan && this.maxSpan && this.minSpan > this.maxSpan) {
227
+ this.minSpan = null;
228
+ this.maxSpan = null;
229
+ console.warn(`Ignore option 'minSpan' and 'maxSpan', because 'minSpan' must be smaller than 'maxSpan'`);
230
+ }
231
+ if (this.defaultSpan && this.minSpan && this.minSpan > this.defaultSpan) {
232
+ this.defaultSpan = null;
233
+ console.warn(`Ignore option 'defaultSpan', because 'defaultSpan' must be greater than 'minSpan'`);
234
+ } else if (this.defaultSpan && this.maxSpan && this.maxSpan < this.defaultSpan) {
235
+ this.defaultSpan = null;
236
+ console.warn(`Ignore option 'defaultSpan', because 'defaultSpan' must be smaller than 'maxSpan'`);
237
+ }
238
+ }
239
+ if (this.timePicker) {
240
+ if (typeof options.timePickerSeconds === "boolean")
241
+ this.timePickerStepSize = Duration.fromObject({ [options.timePickerSeconds ? "seconds" : "minutes"]: 1 });
242
+ if (typeof options.timePickerIncrement === "number")
243
+ this.timePickerStepSize = Duration.fromObject({ minutes: options.timePickerIncrement });
244
+ if (["string", "object", "number"].includes(typeof options.timePickerStepSize)) {
245
+ let duration;
246
+ if (Duration.isDuration(options.timePickerStepSize) && options.timePickerStepSize.isValid) {
247
+ duration = options.timePickerStepSize;
248
+ } else if (Duration.fromISO(options.timePickerStepSize).isValid) {
249
+ duration = Duration.fromISO(options.timePickerStepSize);
250
+ } else if (typeof options.timePickerStepSize === "number" && Duration.fromObject({ seconds: options.timePickerStepSize }).isValid) {
251
+ duration = Duration.fromObject({ seconds: options.timePickerStepSize });
252
+ } else {
253
+ console.error(`Option 'timePickerStepSize' is not valid`);
254
+ duration = this.timePickerStepSize;
255
+ }
256
+ ;
257
+ var valid = [];
258
+ for (let unit of ["minutes", "seconds"])
259
+ valid.push(...[1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].map((x) => {
260
+ return Duration.fromObject({ [unit]: x });
261
+ }));
262
+ valid.push(...[1, 2, 3, 4, 6].map((x) => {
263
+ return Duration.fromObject({ hours: x });
264
+ }));
265
+ if (this.timePicker24Hour)
266
+ valid.push(...[8, 12].map((x) => {
267
+ return Duration.fromObject({ hours: x });
268
+ }));
269
+ if (valid.some((x) => duration.rescale().equals(x))) {
270
+ this.timePickerStepSize = duration.rescale();
271
+ } else {
272
+ console.error(`Option 'timePickerStepSize' ${JSON.stringify(duration.toObject())} is not valid`);
273
+ }
274
+ }
275
+ if (this.maxSpan && this.timePickerStepSize > this.maxSpan)
276
+ console.error(`Option 'timePickerStepSize' ${JSON.stringify(this.timePickerStepSize.toObject())} must be smaller than 'maxSpan'`);
277
+ this.timePickerOpts = {
278
+ showMinutes: this.timePickerStepSize < Duration.fromObject({ hours: 1 }),
279
+ showSeconds: this.timePickerStepSize < Duration.fromObject({ minutes: 1 }),
280
+ hourStep: this.timePickerStepSize >= Duration.fromObject({ hours: 1 }) ? this.timePickerStepSize.hours : 1,
281
+ minuteStep: this.timePickerStepSize >= Duration.fromObject({ minutes: 1 }) ? this.timePickerStepSize.minutes : 1,
282
+ secondStep: this.timePickerStepSize.seconds
283
+ };
284
+ }
285
+ for (let opt of ["startDate", "endDate", "minDate", "maxDate", "initalMonth"]) {
286
+ if (opt === "endDate" && this.singleDatePicker)
287
+ continue;
288
+ if (typeof options[opt] === "object") {
289
+ if (DateTime.isDateTime(options[opt]) && options[opt].isValid) {
290
+ this[opt] = options[opt];
291
+ } else if (options[opt] instanceof Date) {
292
+ this[opt] = DateTime.fromJSDate(options[opt]);
293
+ } else if (options[opt] === null) {
294
+ this[opt] = null;
295
+ } else {
296
+ console.error(`Option '${opt}' must be a luxon.DateTime or Date or string`);
297
+ }
298
+ } else if (typeof options[opt] === "string") {
299
+ const format = typeof this.locale.format === "string" ? this.locale.format : DateTime.parseFormatForOpts(this.locale.format);
300
+ if (DateTime.fromISO(options[opt]).isValid) {
301
+ this[opt] = DateTime.fromISO(options[opt]);
302
+ } else if (DateTime.fromFormat(options[opt], format, { locale: DateTime.now().locale }).isValid) {
303
+ this[opt] = DateTime.fromFormat(options[opt], format, { locale: DateTime.now().locale });
304
+ } else {
305
+ const invalid = DateTime.fromFormat(options[opt], format, { locale: DateTime.now().locale }).invalidExplanation;
306
+ console.error(`Option '${opt}' is not a valid string: ${invalid}`);
307
+ }
308
+ }
309
+ }
310
+ if (!this.timePicker) {
311
+ if (this.minDate)
312
+ this.minDate = this.minDate.startOf("day");
313
+ if (this.maxDate)
314
+ this.maxDate = this.maxDate.endOf("day");
315
+ }
316
+ if (typeof options.startDate === "undefined" && typeof options.endDate === "undefined") {
317
+ if ($(this.element).is(":text")) {
318
+ let start, end;
319
+ const val = $(this.element).val();
320
+ if (val != "") {
321
+ const split = val.split(this.locale.separator);
322
+ const format = typeof this.locale.format === "string" ? this.locale.format : DateTime.parseFormatForOpts(this.locale.format);
323
+ if (split.length === 2) {
324
+ start = DateTime.fromFormat(split[0], format, { locale: DateTime.now().locale });
325
+ end = DateTime.fromFormat(split[1], format, { locale: DateTime.now().locale });
326
+ } else if (this.singleDatePicker) {
327
+ start = DateTime.fromFormat(val, format, { locale: DateTime.now().locale });
328
+ end = DateTime.fromFormat(val, format, { locale: DateTime.now().locale });
329
+ }
330
+ if (start.isValid && end.isValid) {
331
+ this.setStartDate(start, false);
332
+ this.setEndDate(end, false);
333
+ } else {
334
+ if (this.singleDatePicker)
335
+ console.error(`Value in <input> is not a valid string: ${start.invalidExplanation}`);
336
+ else
337
+ console.error(`Value in <input> is not a valid string: ${start.invalidExplanation} - ${end.invalidExplanation}`);
338
+ }
339
+ }
340
+ }
341
+ }
342
+ if (this.singleDatePicker) {
343
+ this.endDate = this.startDate;
344
+ } else if (this.endDate < this.startDate) {
345
+ this.endDate = this.startDate;
346
+ console.warn(`Set 'endDate' to ${this - this.logDate(endDate)} because it was earlier than 'startDate'`);
347
+ }
348
+ if (["function", "string"].includes(typeof options.altFormat))
349
+ this.altFormat = options.altFormat;
350
+ if (typeof options.altInput === "string" || Array.isArray(options.altInput)) {
351
+ if (this.singleDatePicker && typeof options.altInput === "string") {
352
+ this.altInput = $(options.altInput).is("input") ? options.altInput : null;
353
+ } else if (!this.singleDatePicker && Array.isArray(options.altInput) && options.altInput.length === 2) {
354
+ this.altInput = options.altInput.every((x) => typeof x === "string" && $(x).is("input")) ? options.altInput : null;
355
+ } else {
356
+ const note = `Value of "altInput" must be ` + (this.singleDatePicker ? "a string" : "an array of two string elements");
357
+ console.error(`Option 'altInput' ${JSON.stringify(options.altInput)} is not valid
358
+ `, note);
359
+ }
360
+ }
361
+ if (options.warnings !== void 0)
362
+ console.warn(`Option 'warnings' not used anymore. Listen to event 'violated.daterangepicker'`);
363
+ if (!this.startDate && this.initalMonth) {
364
+ this.endDate = null;
365
+ if (this.timePicker)
366
+ console.error(`Option 'initalMonth' works only with 'timePicker: false'`);
367
+ } else {
368
+ this.validateInput();
369
+ }
370
+ if (typeof options.opens === "string") {
371
+ if (["left", "right", "center"].includes(options.opens))
372
+ this.opens = options.opens;
373
+ else
374
+ console.error(`Option 'options.opens' must be 'left', 'right' or 'center'`);
375
+ }
376
+ if (typeof options.drops === "string") {
377
+ if (["drop", "down", "auto"].includes(options.drops))
378
+ this.drops = options.drops;
379
+ else
380
+ console.error(`Option 'options.drops' must be 'drop', 'down' or 'auto'`);
381
+ }
382
+ if (Array.isArray(options.buttonClasses)) {
383
+ this.buttonClasses = options.buttonClasses.join(" ");
384
+ } else if (typeof options.buttonClasses === "string") {
385
+ this.buttonClasses = options.buttonClasses;
386
+ }
387
+ if (typeof options.onOutsideClick === "string") {
388
+ if (["cancel", "apply"].includes(options.onOutsideClick))
389
+ this.onOutsideClick = options.onOutsideClick;
390
+ else
391
+ console.error(`Option 'options.onOutsideClick' must be 'cancel' or 'apply'`);
392
+ }
393
+ if (this.locale.firstDay != 1) {
394
+ let iterator = this.locale.firstDay;
395
+ while (iterator > 1) {
396
+ this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
397
+ iterator--;
398
+ }
399
+ }
400
+ if (!this.singleDatePicker && typeof options.ranges === "object") {
401
+ for (let range in options.ranges) {
402
+ let start, end;
403
+ if (["string", "object"].includes(typeof options.ranges[range][0])) {
404
+ if (DateTime.isDateTime(options.ranges[range][0]) && options.ranges[range][0].isValid) {
405
+ start = options.ranges[range][0];
406
+ } else if (options.ranges[range][0] instanceof Date) {
407
+ start = DateTime.fromJSDate(options.ranges[range][0]);
408
+ } else if (typeof options.ranges[range][0] === "string" && DateTime.fromISO(options.ranges[range][0]).isValid) {
409
+ start = DateTime.fromISO(options.ranges[range][0]);
410
+ } else {
411
+ console.error(`Option ranges['${range}'] is not am array of valid ISO-8601 string or luxon.DateTime or Date`);
412
+ }
413
+ }
414
+ if (["string", "object"].includes(typeof options.ranges[range][1])) {
415
+ if (DateTime.isDateTime(options.ranges[range][1]) && options.ranges[range][1].isValid) {
416
+ end = options.ranges[range][1];
417
+ } else if (options.ranges[range][1] instanceof Date) {
418
+ end = DateTime.fromJSDate(options.ranges[range][1]);
419
+ } else if (typeof options.ranges[range][1] === "string" && DateTime.fromISO(options.ranges[range][1]).isValid) {
420
+ end = DateTime.fromISO(options.ranges[range][1]);
421
+ } else {
422
+ console.error(`Option ranges['${range}'] is not a valid ISO-8601 string or luxon.DateTime or Date`);
423
+ }
424
+ }
425
+ if (start == null || end == null)
426
+ continue;
427
+ const validRange = this.validateInput([range, start, end]);
428
+ if (validRange[2].startDate.violations.map((x) => x.reason).some((x) => ["minDate", "maxDate", "minSpan", "maxSpan"].includes(x))) {
429
+ const vio = validRange[2].startDate.violations.map((x) => x.reason).filter((x) => ["minDate", "maxDate", "minSpan", "maxSpan"].includes(x));
430
+ console.error(`Option ranges['${range}'] is not valid, violating ${vio.join(",")}`);
431
+ } else if (validRange[2].endDate.violations.map((x) => x.reason).some((x) => ["minDate", "maxDate", "minSpan", "maxSpan"].includes(x))) {
432
+ const vio = validRange[2].endDate.violations.map((x) => x.reason).filter((x) => ["minDate", "maxDate", "minSpan", "maxSpan"].includes(x));
433
+ console.error(`Option ranges['${range}'] is not valid, violating ${vio.join(",")}`);
434
+ } else {
435
+ options.ranges[range] = [validRange[0], validRange[1]];
436
+ var elem = document.createElement("textarea");
437
+ elem.innerHTML = range;
438
+ var rangeHtml = elem.value;
439
+ this.ranges[rangeHtml] = [validRange[0], validRange[1]];
440
+ }
441
+ }
442
+ var list = "<ul>";
443
+ for (let range in this.ranges) {
444
+ list += '<li data-range-key="' + range + '">' + range + "</li>";
445
+ }
446
+ if (this.showCustomRangeLabel) {
447
+ list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + "</li>";
448
+ }
449
+ list += "</ul>";
450
+ this.container.find(".ranges").prepend(list);
451
+ this.container.addClass("show-ranges");
452
+ }
453
+ if (typeof cb === "function") {
454
+ this.callback = cb;
455
+ }
456
+ if (!this.timePicker) {
457
+ if (this.startDate)
458
+ this.startDate = this.startDate.startOf("day");
459
+ if (this.endDate)
460
+ this.endDate = this.endDate.endOf("day");
461
+ this.container.find(".calendar-time").hide();
462
+ }
463
+ if (this.timePicker && this.autoApply)
464
+ this.autoApply = false;
465
+ if (this.autoApply)
466
+ this.container.addClass("auto-apply");
467
+ if (this.singleDatePicker || this.singleMonthView) {
468
+ this.container.addClass("single");
469
+ this.container.find(".drp-calendar.left").addClass("single");
470
+ this.container.find(".drp-calendar.left").show();
471
+ this.container.find(".drp-calendar.right").hide();
472
+ if (!this.timePicker && this.autoApply)
473
+ this.container.addClass("auto-apply");
474
+ }
475
+ if (typeof options.ranges === "undefined" && !this.singleDatePicker || this.alwaysShowCalendars)
476
+ this.container.addClass("show-calendar");
477
+ this.container.addClass("opens" + this.opens);
478
+ this.container.find(".applyBtn, .cancelBtn").addClass(this.buttonClasses);
479
+ if (this.applyButtonClasses.length)
480
+ this.container.find(".applyBtn").addClass(this.applyButtonClasses);
481
+ if (this.cancelButtonClasses.length)
482
+ this.container.find(".cancelBtn").addClass(this.cancelButtonClasses);
483
+ this.container.find(".applyBtn").html(this.locale.applyLabel);
484
+ this.container.find(".cancelBtn").html(this.locale.cancelLabel);
485
+ this.container.find(".drp-calendar").on("click.daterangepicker", ".prev", this.clickPrev.bind(this)).on("click.daterangepicker", ".next", this.clickNext.bind(this)).on("mousedown.daterangepicker", "td.available", this.clickDate.bind(this)).on("mouseenter.daterangepicker", "td.available", this.hoverDate.bind(this)).on("change.daterangepicker", "select.yearselect", this.monthOrYearChanged.bind(this)).on("change.daterangepicker", "select.monthselect", this.monthOrYearChanged.bind(this)).on("change.daterangepicker", "select.hourselect,select.minuteselect,select.secondselect,select.ampmselect", this.timeChanged.bind(this));
486
+ this.container.find(".ranges").on("click.daterangepicker", "li", this.clickRange.bind(this)).on("mouseenter.daterangepicker", "li", this.hoverRange.bind(this)).on("mouseleave.daterangepicker", "li", this.leaveRange.bind(this));
487
+ this.container.find(".drp-buttons").on("click.daterangepicker", "button.applyBtn", this.clickApply.bind(this)).on("click.daterangepicker", "button.cancelBtn", this.clickCancel.bind(this));
488
+ if (this.element.is("input") || this.element.is("button")) {
489
+ this.element.on({
490
+ "click.daterangepicker": this.show.bind(this),
491
+ "focus.daterangepicker": this.show.bind(this),
492
+ "keyup.daterangepicker": this.elementChanged.bind(this),
493
+ "keydown.daterangepicker": this.keydown.bind(this)
494
+ //IE 11 compatibility
495
+ });
496
+ } else {
497
+ this.element.on("click.daterangepicker", this.toggle.bind(this));
498
+ this.element.on("keydown.daterangepicker", this.toggle.bind(this));
499
+ }
500
+ this.updateElement();
501
+ }
502
+ /**
503
+ * Sets the date range picker's currently selected start date to the provided date.<br/>
504
+ * `startDate` must be a `luxon.DateTime` or `Date` or `string` according to {@link ISO-8601} or
505
+ * a string matching `locale.format`.
506
+ * The value of the attached `<input>` element is also updated.
507
+ * Date value is rounded to match option `timePickerStepSize` unless skipped by `violated.daterangepicker` event handler.<br/>
508
+ * If the `startDate` does not fall into `minDate` and `maxDate` then `startDate` is shifted unless skipped by `violated.daterangepicker` event handler.
509
+ * @param {external:DateTime|external:Date|string} startDate - startDate to be set
510
+ * @param {boolean} isValid=false - If `true` then the `startDate` is not checked against `minDate` and `maxDate`<br/>
511
+ * Use this option only if you are sure about the value you put in.
512
+ * @throws `RangeError` for invalid date values.
513
+ * @example const DateTime = luxon.DateTime;
514
+ * const drp = $('#picker').data('daterangepicker');
515
+ * drp.setStartDate(DateTime.now().startOf('hour'));
516
+ */
517
+ setStartDate(startDate, isValid = false) {
518
+ if (isValid === void 0 || !isValid) {
519
+ if (typeof startDate === "object") {
520
+ if (DateTime.isDateTime(startDate) && startDate.isValid) {
521
+ this.startDate = startDate;
522
+ } else if (startDate instanceof Date) {
523
+ this.startDate = DateTime.fromJSDate(startDate);
524
+ } else {
525
+ throw RangeError(`The 'startDate' must be a luxon.DateTime or Date or string`);
526
+ }
527
+ } else if (typeof startDate === "string") {
528
+ const format = typeof this.locale.format === "string" ? this.locale.format : DateTime.parseFormatForOpts(this.locale.format);
529
+ if (DateTime.fromISO(startDate).isValid) {
530
+ this.startDate = DateTime.fromISO(startDate);
531
+ } else if (DateTime.fromFormat(startDate, format, { locale: DateTime.now().locale }).isValid) {
532
+ this.startDate = DateTime.fromFormat(startDate, format, { locale: DateTime.now().locale });
533
+ } else {
534
+ const invalid = DateTime.fromFormat(startDate, format, { locale: DateTime.now().locale }).invalidExplanation;
535
+ throw RangeError(`The 'startDate' is not a valid string: ${invalid}`);
536
+ }
537
+ }
538
+ } else {
539
+ this.startDate = startDate;
540
+ }
541
+ if (isValid === void 0 || !isValid)
542
+ this.validateInput();
543
+ if (!this.singleDatePicker && !this.endDate) {
544
+ if (this.locale.durationFormat)
545
+ this.container.find(".drp-duration-label").html("");
546
+ const empty = `<span>${this.formatDate(this.startDate)}</span>`;
547
+ this.container.find(".drp-selected").html(this.formatDate(this.startDate) + this.locale.separator + empty);
548
+ }
549
+ if (!this.isShowing)
550
+ this.updateElement();
551
+ this.updateMonthsInView();
552
+ }
553
+ /**
554
+ * Sets the date range picker's currently selected end date to the provided date.<br/>
555
+ * `endDate` must be a `luxon.DateTime` or `Date` or `string` according to {@link ISO-8601} or
556
+ * a string matching`locale.format`.
557
+ * The value of the attached `<input>` element is also updated.
558
+ * Date value is rounded to match option `timePickerStepSize` unless skipped by `violated.daterangepicker` event handler.<br/>
559
+ * If the `endDate` does not fall into `minDate` and `maxDate` or into `minSpan` and `maxSpan`
560
+ * then `endDate` is shifted unless skipped by `violated.daterangepicker` event handler
561
+ * @param {external:DateTime|external:Date|string} endDate - endDate to be set
562
+ * @param {boolean} isValid=false - If `true` then the `endDate` is not checked against `minDate`, `maxDate` and `minSpan`, `maxSpan`<br/>
563
+ * Use this option only if you are sure about the value you put in.
564
+ * @throws `RangeError` for invalid date values.
565
+ * @example const drp = $('#picker').data('daterangepicker');
566
+ * drp.setEndDate('2025-03-28T18:30:00');
567
+ */
568
+ setEndDate(endDate2, isValid = false) {
569
+ if (isValid === void 0 || !isValid) {
570
+ if (typeof endDate2 === "object") {
571
+ if (DateTime.isDateTime(endDate2) && endDate2.isValid) {
572
+ this.endDate = endDate2;
573
+ } else if (endDate2 instanceof Date) {
574
+ this.endDate = DateTime.fromJSDate(endDate2);
575
+ } else {
576
+ throw RangeError(`The 'endDate' must be a luxon.DateTime or Date or string`);
577
+ }
578
+ } else if (typeof endDate2 === "string") {
579
+ const format = typeof this.locale.format === "string" ? this.locale.format : DateTime.parseFormatForOpts(this.locale.format);
580
+ if (DateTime.fromISO(endDate2).isValid) {
581
+ this.endDate = DateTime.fromISO(endDate2);
582
+ } else if (DateTime.fromFormat(endDate2, format, { locale: DateTime.now().locale }).isValid) {
583
+ this.endDate = DateTime.fromFormat(endDate2, format, { locale: DateTime.now().locale });
584
+ } else {
585
+ const invalid = DateTime.fromFormat(endDate2, format, { locale: DateTime.now().locale }).invalidExplanation;
586
+ throw RangeError(`The 'endDate' is not a valid string: ${invalid}`);
587
+ }
588
+ }
589
+ } else {
590
+ this.endDate = endDate2;
591
+ }
592
+ if (isValid === void 0 || !isValid)
593
+ this.validateInput();
594
+ this.previousRightTime = this.endDate;
595
+ this.updateDurationLabel();
596
+ if (!this.singleDatePicker)
597
+ this.container.find(".drp-selected").html(this.formatDate(this.startDate) + this.locale.separator + this.formatDate(this.endDate));
598
+ if (!this.isShowing)
599
+ this.updateElement();
600
+ this.updateMonthsInView();
601
+ }
602
+ /**
603
+ * Shortcut for {@link #DateRangePicker+setStartDate|setStartDate} and {@link #DateRangePicker+setEndDate|setEndDate}
604
+ * @param {external:DateTime|external:Date|string} startDate - startDate to be set
605
+ * @param {external:DateTime|external:Date|string} endDate - endDate to be set
606
+ * @param {boolean} isValid=false - If `true` then the `startDate` and `endDate` are not checked against `minDate`, `maxDate` and `minSpan`, `maxSpan`<br/>
607
+ * Use this option only if you are sure about the value you put in.
608
+ * @throws `RangeError` for invalid date values.
609
+ * @example const DateTime = luxon.DateTime;
610
+ * const drp = $('#picker').data('daterangepicker');
611
+ * drp.setPeriod(DateTime.now().startOf('week'), DateTime.now().startOf('week').plus({days: 10}));
612
+ */
613
+ setPeriod(startDate, endDate2, isValid = false) {
614
+ if (this.singleDatePicker) {
615
+ this.setStartDate(startDate, isValid);
616
+ } else {
617
+ this.setStartDate(startDate, true);
618
+ this.setEndDate(endDate2, true);
619
+ if (!isValid)
620
+ this.validateInput();
621
+ }
622
+ }
623
+ logDate(date) {
624
+ return this.timePicker ? date.toISO({ suppressMilliseconds: true }) : date.toISODate();
625
+ }
626
+ formatDate(date, format = this.locale.format) {
627
+ if (typeof format === "object") {
628
+ return date.toLocaleString(format);
629
+ } else {
630
+ if (Settings.defaultLocale === null) {
631
+ const locale = DateTime.now().locale;
632
+ return date.toFormat(format, { locale });
633
+ } else {
634
+ return date.toFormat(format);
635
+ }
636
+ }
637
+ }
638
+ updateDurationLabel() {
639
+ if (this.singleDatePicker || this.locale.durationFormat == null)
640
+ return;
641
+ if (!this.endDate) {
642
+ this.container.find(".drp-duration-label").html("");
643
+ return;
644
+ }
645
+ if (typeof this.locale.durationFormat === "function") {
646
+ this.container.find(".drp-duration-label").html(this.locale.durationFormat(this.startDate, this.endDate));
647
+ } else {
648
+ let duration = this.endDate.plus({ milliseconds: 1 }).diff(this.startDate).rescale().set({ milliseconds: 0 });
649
+ if (!this.timePicker)
650
+ duration = duration.set({ seconds: 0, minutes: 0, hours: 0 });
651
+ duration = duration.removeZeros();
652
+ if (typeof this.locale.durationFormat === "object") {
653
+ this.container.find(".drp-duration-label").html(duration.toHuman(this.locale.durationFormat));
654
+ } else {
655
+ this.container.find(".drp-duration-label").html(duration.toFormat(this.locale.durationFormat));
656
+ }
657
+ }
658
+ }
659
+ /**
660
+ * @typedef InputViolation
661
+ * @type {Object}
662
+ * @property {external:DateTime} startDate - Violation of startDate
663
+ * @property {external:DateTime|undefined} endDate - Violation of endDate
664
+ * @property {Array} reason - The constraint which violates the input
665
+ * @property {external:DateTime} old - Old value startDate/endDate
666
+ * @property {external:DateTime} new - Corrected value of startDate/endDate
667
+ */
668
+ /**
669
+ * Validate `startDate` and `endDate` or `range` against `timePickerStepSize`, `minDate`, `maxDate`,
670
+ * `minSpan`, `maxSpan`, `invalidDate` and `invalidTime` and corrects them, if needed.
671
+ * Correction can be skipped by returning `true` at event listener for `violated.daterangepicker`
672
+ * @param {Array} [range] - Used to check prefefined range instead of `startDate` and `endDate` => `[name, startDate, endDate]`
673
+ * When set, then function does not modify anything, just returning corrected range.
674
+ * @emits "violated.daterangepicker"
675
+ * @returns {Array|null} - Corrected range as array of `[startDate, endDate]` when `range` is defined
676
+ * @example
677
+ * validateInput([DateTime.fromISO('2025-02-03'), DateTime.fromISO('2025-02-25')]) =>
678
+ * [ DateTime.fromISO('2025-02-05'), DateTime.fromISO('2025-02-20'), { startDate: { violations: [{old: ..., new: ..., reasson: 'minDate'}] } } ]
679
+ */
680
+ validateInput(range) {
681
+ let startDate = range === void 0 ? this.startDate : range[1];
682
+ let endDate2 = range === void 0 ? this.endDate : range[2];
683
+ if (!startDate)
684
+ return;
685
+ let result = { startDate: { violations: [] } };
686
+ let violation = { old: startDate, reason: this.timePicker ? "timePickerStepSize" : "timePicker" };
687
+ if (this.timePicker) {
688
+ const secs = this.timePickerStepSize.as("seconds");
689
+ startDate = DateTime.fromSeconds(secs * Math.round(startDate.toSeconds() / secs));
690
+ } else {
691
+ startDate = startDate.startOf("day");
692
+ }
693
+ violation.new = startDate;
694
+ if (!violation.new.equals(violation.old))
695
+ result.startDate.violations.push(violation);
696
+ const shiftStep = this.timePicker ? this.timePickerStepSize.as("seconds") : Duration.fromObject({ days: 1 }).as("seconds");
697
+ if (this.minDate && startDate < this.minDate) {
698
+ violation = { old: startDate, reason: "minDate" };
699
+ startDate = startDate.plus({ seconds: Math.trunc(this.minDate.diff(startDate).as("seconds") / shiftStep) * shiftStep });
700
+ if (startDate < this.minDate)
701
+ startDate = startDate.plus(this.timePicker ? this.timePickerStepSize : { days: 1 });
702
+ violation.new = startDate;
703
+ if (!violation.new.equals(violation.old))
704
+ result.startDate.violations.push(violation);
705
+ } else if (this.maxDate && startDate > this.maxDate) {
706
+ violation = { old: startDate, reason: "maxDate" };
707
+ startDate = startDate.minus({ seconds: Math.trunc(startDate.diff(this.maxDate).as("seconds") / shiftStep) * shiftStep });
708
+ if (startDate > this.maxDate)
709
+ startDate = startDate.minus(this.timePicker ? this.timePickerStepSize : { days: 1 });
710
+ violation.new = startDate;
711
+ if (!violation.new.equals(violation.old))
712
+ result.startDate.violations.push(violation);
713
+ }
714
+ let units = ["hour"];
715
+ if (this.timePicker) {
716
+ if (this.timePickerOpts.showMinutes)
717
+ units.push("minute");
718
+ if (this.timePickerOpts.showSeconds)
719
+ units.push("second");
720
+ if (!this.timePicker24Hour)
721
+ units.push("ampm");
722
+ }
723
+ if (this.isInvalidDate(startDate))
724
+ result.startDate.violations.push({ old: startDate, new: startDate, reason: "isInvalidDate" });
725
+ if (this.timePicker) {
726
+ for (let unit of units) {
727
+ if (this.isInvalidTime(startDate, unit, "start"))
728
+ result.startDate.violations.push({ old: startDate, new: startDate, reason: "isInvalidTime", unit });
729
+ }
730
+ }
731
+ if (this.singleDatePicker) {
732
+ endDate2 = startDate;
733
+ if (range === void 0) {
734
+ if (result.startDate.violations.length > 0) {
735
+ if (!this.element.triggerHandler("violated.daterangepicker", [this, result])) {
736
+ this.startDate = startDate;
737
+ this.endDate = endDate2;
738
+ }
739
+ }
740
+ return;
741
+ } else {
742
+ return [startDate, endDate2, result];
743
+ }
744
+ }
745
+ if (endDate2 == null)
746
+ return;
747
+ result.endDate = { violations: [] };
748
+ violation = { old: endDate2, reason: this.timePicker ? "stepSize" : "timePicker" };
749
+ if (this.timePicker) {
750
+ const secs = this.timePickerStepSize.as("seconds");
751
+ endDate2 = DateTime.fromSeconds(secs * Math.round(endDate2.toSeconds() / secs));
752
+ } else {
753
+ endDate2 = endDate2.endOf("day");
754
+ }
755
+ violation.new = endDate2;
756
+ if (!violation.new.equals(violation.old))
757
+ result.endDate.violations.push(violation);
758
+ if (this.maxDate && endDate2 > this.maxDate) {
759
+ violation = { old: endDate2, reason: "maxDate" };
760
+ endDate2 = endDate2.minus({ seconds: Math.trunc(endDate2.diff(this.maxDate).as("seconds") / shiftStep) * shiftStep });
761
+ if (endDate2 > this.maxDate)
762
+ endDate2 = endDate2.minus(this.timePicker ? this.timePickerStepSize : { days: 1 });
763
+ violation.new = endDate2;
764
+ if (!violation.new.equals(violation.old))
765
+ result.endDate.violations.push(violation);
766
+ } else if (this.minDate && endDate2 < this.minDate) {
767
+ violation = { old: endDate2, reason: "minDate" };
768
+ endDate2 = endDate2.plus({ seconds: Math.trunc(this.minDate.diff(endDate2).as("seconds") / shiftStep) * shiftStep });
769
+ if (endDate2 < this.minDate)
770
+ endDate2 = endDate2.plus(this.timePicker ? this.timePickerStepSize : { days: 1 });
771
+ violation.new = endDate2;
772
+ if (!violation.new.equals(violation.old))
773
+ result.endDate.violations.push(violation);
774
+ }
775
+ if (this.maxSpan) {
776
+ const maxDate = startDate.plus(this.maxSpan);
777
+ if (endDate2 > maxDate) {
778
+ violation = { old: endDate2, reason: "maxSpan" };
779
+ endDate2 = endDate2.minus({ seconds: Math.trunc(maxDate.diff(endDate2).as("seconds") / shiftStep) * shiftStep });
780
+ if (endDate2 > maxDate)
781
+ endDate2 = endDate2.minus(this.timePicker ? this.timePickerStepSize : { days: 1 });
782
+ violation.new = endDate2;
783
+ if (!violation.new.equals(violation.old))
784
+ result.endDate.violations.push(violation);
785
+ }
786
+ }
787
+ if (this.minSpan) {
788
+ const minDate = startDate.plus(this.defaultSpan ?? this.minSpan);
789
+ if (endDate2 < minDate) {
790
+ violation = { old: endDate2, reason: "minSpan" };
791
+ endDate2 = endDate2.plus({ seconds: Math.trunc(minDate.diff(endDate2).as("seconds") / shiftStep) * shiftStep });
792
+ if (endDate2 < minDate)
793
+ endDate2 = endDate2.plus(this.timePicker ? this.timePickerStepSize : { days: 1 });
794
+ violation.new = endDate2;
795
+ if (!violation.new.equals(violation.old))
796
+ result.endDate.violations.push(violation);
797
+ }
798
+ }
799
+ if (this.isInvalidDate(endDate2))
800
+ result.endDate.violations.push({ old: endDate2, new: endDate2, reason: "isInvalidDate" });
801
+ if (this.timePicker) {
802
+ for (let unit of units) {
803
+ if (this.isInvalidTime(endDate2, unit, "end"))
804
+ result.endDate.violations.push({ old: endDate2, new: endDate2, reason: "isInvalidTime", unit });
805
+ }
806
+ }
807
+ if (range === void 0) {
808
+ if (result.startDate.violations.length > 0 || result.endDate.violations.length > 0) {
809
+ if (!this.element.triggerHandler("violated.daterangepicker", [this, result])) {
810
+ this.startDate = startDate;
811
+ this.endDate = endDate2;
812
+ }
813
+ }
814
+ return;
815
+ } else {
816
+ return [startDate, endDate2, result];
817
+ }
818
+ }
819
+ /**
820
+ * Updates the picker when calendar is initiated or any date has been selected.
821
+ * Could be useful after running {@link #DateRangePicker+setStartDate|setStartDate} or {@link #DateRangePicker+setEndDate|setEndDate}
822
+ * @emits "beforeRenderTimePicker.daterangepicker"
823
+ */
824
+ updateView() {
825
+ if (this.timePicker) {
826
+ this.element.trigger("beforeRenderTimePicker.daterangepicker", this);
827
+ this.renderTimePicker("start");
828
+ this.renderTimePicker("end");
829
+ if (!this.endDate) {
830
+ this.container.find(".calendar-time.end-time select").prop("disabled", true).addClass("disabled");
831
+ } else {
832
+ this.container.find(".calendar-time.end-time select").prop("disabled", false).removeClass("disabled");
833
+ }
834
+ }
835
+ this.updateDurationLabel();
836
+ if (this.startDate && this.endDate)
837
+ this.container.find(".drp-selected").html(this.formatDate(this.startDate) + this.locale.separator + this.formatDate(this.endDate));
838
+ this.updateMonthsInView();
839
+ this.updateCalendars();
840
+ this.updateFormInputs();
841
+ }
842
+ /**
843
+ * Shows calendar months based on selected date values
844
+ * @private
845
+ */
846
+ updateMonthsInView() {
847
+ if (this.endDate) {
848
+ if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month && (this.startDate.hasSame(this.leftCalendar.month, "month") || this.startDate.hasSame(this.rightCalendar.month, "month")) && (this.endDate.hasSame(this.leftCalendar.month, "month") || this.endDate.hasSame(this.rightCalendar.month, "month")))
849
+ return;
850
+ this.leftCalendar.month = this.startDate.startOf("month");
851
+ if (!this.singleMonthView) {
852
+ if (!this.linkedCalendars && !this.endDate.hasSame(this.startDate, "month")) {
853
+ this.rightCalendar.month = this.endDate.startOf("month");
854
+ } else {
855
+ this.rightCalendar.month = this.startDate.startOf("month").plus({ month: 1 });
856
+ }
857
+ }
858
+ } else {
859
+ if (!this.startDate && this.initalMonth) {
860
+ this.leftCalendar.month = this.initalMonth;
861
+ if (!this.singleMonthView)
862
+ this.rightCalendar.month = this.initalMonth.plus({ month: 1 });
863
+ } else {
864
+ if (!this.leftCalendar.month.hasSame(this.startDate, "month") && !this.rightCalendar.month.hasSame(this.startDate, "month")) {
865
+ this.leftCalendar.month = this.startDate.startOf("month");
866
+ this.rightCalendar.month = this.startDate.startOf("month").plus({ month: 1 });
867
+ }
868
+ }
869
+ }
870
+ if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && !this.singleMonthView && this.rightCalendar.month > this.maxDate) {
871
+ this.rightCalendar.month = this.maxDate.startOf("month");
872
+ this.leftCalendar.month = this.maxDate.startOf("month").minus({ month: 1 });
873
+ }
874
+ }
875
+ /**
876
+ * Updates the selected day value from calendar with selected time values
877
+ * @emits "beforeRenderCalendar.daterangepicker"
878
+ * @private
879
+ */
880
+ updateCalendars() {
881
+ if (this.timePicker) {
882
+ var hour, minute, second;
883
+ if (this.endDate) {
884
+ hour = parseInt(this.container.find(".start-time .hourselect").val(), 10);
885
+ if (isNaN(hour))
886
+ hour = parseInt(this.container.find(".start-time .hourselect option:last").val(), 10);
887
+ minute = 0;
888
+ if (this.timePickerOpts.showMinutes) {
889
+ minute = parseInt(this.container.find(".start-time .minuteselect").val(), 10);
890
+ if (isNaN(minute))
891
+ minute = parseInt(this.container.find(".start-time .minuteselect option:last").val(), 10);
892
+ }
893
+ second = 0;
894
+ if (this.timePickerOpts.showSeconds) {
895
+ second = parseInt(this.container.find(".start-time .secondselect").val(), 10);
896
+ if (isNaN(second))
897
+ second = parseInt(this.container.find(".start-time .secondselect option:last").val(), 10);
898
+ }
899
+ } else {
900
+ hour = parseInt(this.container.find(".end-time .hourselect").val(), 10);
901
+ if (isNaN(hour))
902
+ hour = parseInt(this.container.find(".end-time .hourselect option:last").val(), 10);
903
+ minute = 0;
904
+ if (this.timePickerOpts.showMinutes) {
905
+ minute = parseInt(this.container.find(".end-time .minuteselect").val(), 10);
906
+ if (isNaN(minute))
907
+ minute = parseInt(this.container.find(".end-time .minuteselect option:last").val(), 10);
908
+ }
909
+ second = 0;
910
+ if (this.timePickerOpts.showSeconds) {
911
+ second = parseInt(this.container.find(".end-time .secondselect").val(), 10);
912
+ if (isNaN(second))
913
+ second = parseInt(this.container.find(".end-time .secondselect option:last").val(), 10);
914
+ }
915
+ }
916
+ this.leftCalendar.month = this.leftCalendar.month.set({ hour, minute, second });
917
+ if (!this.singleMonthView)
918
+ this.rightCalendar.month = this.rightCalendar.month.set({ hour, minute, second });
919
+ } else {
920
+ this.leftCalendar.month = this.leftCalendar.month.set({ hour: 0, minute: 0, second: 0 });
921
+ if (!this.singleMonthView)
922
+ this.rightCalendar.month = this.rightCalendar.month.set({ hour: 0, minute: 0, second: 0 });
923
+ }
924
+ this.element.trigger("beforeRenderCalendar.daterangepicker", this);
925
+ this.renderCalendar("left");
926
+ this.renderCalendar("right");
927
+ this.container.find(".ranges li").removeClass("active");
928
+ if (this.endDate == null) return;
929
+ this.calculateChosenLabel();
930
+ }
931
+ /**
932
+ * Renders the calendar month
933
+ * @private
934
+ */
935
+ renderCalendar(side) {
936
+ if (side === "right" && this.singleMonthView)
937
+ return;
938
+ var calendar = side === "left" ? this.leftCalendar : this.rightCalendar;
939
+ if (calendar.month == null && !this.startDate && this.initalMonth)
940
+ calendar.month = this.initalMonth.startOf("month");
941
+ const firstDay = calendar.month.startOf("month");
942
+ const lastDay = calendar.month.endOf("month").startOf("day");
943
+ var theDate = calendar.month.startOf("month").minus({ day: 1 });
944
+ const time = { hour: calendar.month.hour, minute: calendar.month.minute, second: calendar.month.second };
945
+ var calendar = [];
946
+ calendar.firstDay = firstDay;
947
+ calendar.lastDay = lastDay;
948
+ for (var i = 0; i < 6; i++)
949
+ calendar[i] = [];
950
+ while (theDate.weekday != this.locale.firstDay)
951
+ theDate = theDate.minus({ day: 1 });
952
+ for (let col = 0, row = -1; col < 42; col++, theDate = theDate.plus({ day: 1 })) {
953
+ if (col % 7 === 0)
954
+ row++;
955
+ calendar[row][col % 7] = theDate.set(time);
956
+ }
957
+ if (side === "left") {
958
+ this.leftCalendar.calendar = calendar;
959
+ } else {
960
+ this.rightCalendar.calendar = calendar;
961
+ }
962
+ var minDate = side === "left" ? this.minDate : this.startDate;
963
+ var maxDate = this.maxDate;
964
+ var html = "<tr>";
965
+ if (this.showWeekNumbers || this.showISOWeekNumbers)
966
+ html += "<th></th>";
967
+ if ((!minDate || minDate < calendar.firstDay) && (!this.linkedCalendars || side === "left")) {
968
+ html += '<th class="prev available"><span></span></th>';
969
+ } else {
970
+ html += "<th></th>";
971
+ }
972
+ var dateHtml = `${this.locale.monthNames[calendar.firstDay.month - 1]} ${calendar.firstDay.year}`;
973
+ if (this.showDropdowns) {
974
+ const maxYear = (maxDate && maxDate.year) ?? this.maxYear;
975
+ const minYear = (minDate && minDate.year) ?? this.minYear;
976
+ let div = this.externalStyle === "bulma" ? '<div class="select is-small mr-1">' : "";
977
+ var monthHtml = `${div}<select class="monthselect">`;
978
+ for (var m = 1; m <= 12; m++) {
979
+ monthHtml += `<option value="${m}"${m === calendar.firstDay.month ? " selected" : ""}`;
980
+ if (minDate && calendar.firstDay.set({ month: m }) < minDate.startOf("month") || maxDate && calendar.firstDay.set({ month: m }) > maxDate.endOf("month"))
981
+ monthHtml += ` disabled`;
982
+ monthHtml += `>${this.locale.monthNames[m - 1]}</option>`;
983
+ }
984
+ monthHtml += "</select>";
985
+ if (this.externalStyle === "bulma")
986
+ monthHtml += "</div>";
987
+ div = this.externalStyle === "bulma" ? '<div class="select is-small ml-1">' : "";
988
+ var yearHtml = `${div}<select class="yearselect">`;
989
+ for (var y = minYear; y <= maxYear; y++)
990
+ yearHtml += `<option value="${y}"${y === calendar.firstDay.year ? " selected" : ""}>${y}</option>`;
991
+ yearHtml += "</select>";
992
+ if (this.externalStyle === "bulma")
993
+ yearHtml += "</div>";
994
+ dateHtml = monthHtml + yearHtml;
995
+ }
996
+ html += '<th colspan="5" class="month">' + dateHtml + "</th>";
997
+ if ((!maxDate || maxDate > calendar.lastDay.endOf("day")) && (!this.linkedCalendars || side === "right" || this.singleDatePicker || this.singleMonthView)) {
998
+ html += '<th class="next available"><span></span></th>';
999
+ } else {
1000
+ html += "<th></th>";
1001
+ }
1002
+ html += "</tr>";
1003
+ html += "<tr>";
1004
+ if (this.showWeekNumbers || this.showISOWeekNumbers)
1005
+ html += `<th class="week">${this.locale.weekLabel}</th>`;
1006
+ for (let [index, dayOfWeek] of this.locale.daysOfWeek.entries()) {
1007
+ html += "<th";
1008
+ if (this.weekendDayClasses && this.weekendDayClasses.length && Info.getWeekendWeekdays().includes(index + 1))
1009
+ html += ` class="${this.weekendDayClasses}"`;
1010
+ html += `>${dayOfWeek}</th>`;
1011
+ }
1012
+ ;
1013
+ html += "</tr>";
1014
+ this.container.find(".drp-calendar." + side + " .calendar-table thead").html(html);
1015
+ html = "";
1016
+ if (this.endDate == null && this.maxSpan) {
1017
+ var maxLimit = this.startDate.plus(this.maxSpan).endOf("day");
1018
+ if (!maxDate || maxLimit < maxDate) {
1019
+ maxDate = maxLimit;
1020
+ }
1021
+ }
1022
+ var minLimit;
1023
+ if (this.endDate == null && this.minSpan)
1024
+ minLimit = this.startDate.plus(this.minSpan).startOf("day");
1025
+ for (let row = 0; row < 6; row++) {
1026
+ html += "<tr>";
1027
+ if (this.showISOWeekNumbers)
1028
+ html += '<td class="week">' + calendar[row][0].weekNumber + "</td>";
1029
+ else if (this.showWeekNumbers)
1030
+ html += '<td class="week">' + calendar[row][0].localWeekNumber + "</td>";
1031
+ for (let col = 0; col < 7; col++) {
1032
+ var classes = [];
1033
+ if (this.todayClasses && this.todayClasses.length && calendar[row][col].hasSame(DateTime.now(), "day"))
1034
+ classes.push(this.todayClasses);
1035
+ if (this.weekendClasses && this.weekendClasses.length && Info.getWeekendWeekdays().includes(calendar[row][col].weekday))
1036
+ classes.push(this.weekendClasses);
1037
+ if (calendar[row][col].month != calendar[1][1].month)
1038
+ classes.push("off", "ends");
1039
+ if (this.minDate && calendar[row][col].startOf("day") < this.minDate.startOf("day"))
1040
+ classes.push("off", "disabled");
1041
+ if (maxDate && calendar[row][col].startOf("day") > maxDate.startOf("day"))
1042
+ classes.push("off", "disabled");
1043
+ if (minLimit && calendar[row][col].startOf("day") > this.startDate.startOf("day") && calendar[row][col].startOf("day") < minLimit.startOf("day"))
1044
+ classes.push("off", "disabled");
1045
+ if (this.isInvalidDate(calendar[row][col]))
1046
+ classes.push("off", "disabled");
1047
+ if (this.startDate != null && calendar[row][col].hasSame(this.startDate, "day"))
1048
+ classes.push("active", "start-date");
1049
+ if (this.endDate != null && calendar[row][col].hasSame(this.endDate, "day"))
1050
+ classes.push("active", "end-date");
1051
+ if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)
1052
+ classes.push("in-range");
1053
+ var isCustom = this.isCustomDate(calendar[row][col]);
1054
+ if (isCustom !== false) {
1055
+ if (typeof isCustom === "string")
1056
+ classes.push(isCustom);
1057
+ else
1058
+ Array.prototype.push.apply(classes, isCustom);
1059
+ }
1060
+ if (!classes.includes("disabled"))
1061
+ classes.push("available");
1062
+ html += `<td class="${classes.join(" ")}" data-title="r${row}c${col}">${calendar[row][col].day}</td>`;
1063
+ }
1064
+ html += "</tr>";
1065
+ }
1066
+ this.container.find(".drp-calendar." + side + " .calendar-table tbody").html(html);
1067
+ }
1068
+ /**
1069
+ * Emitted before the TimePicker is rendered.
1070
+ * Useful to remove any manually added elements.
1071
+ * @event
1072
+ * @name "beforeRenderTimePicker.daterangepicker"
1073
+ * @param {DateRangePicker} this - The daterangepicker object
1074
+ */
1075
+ /**
1076
+ * Renders the time pickers
1077
+ * @private
1078
+ * @emits "beforeRenderTimePicker.daterangepicker"
1079
+ */
1080
+ renderTimePicker(side) {
1081
+ if (side === "end" && !this.endDate) return;
1082
+ var selected, minLimit, minDate, maxDate = this.maxDate;
1083
+ let html = "";
1084
+ if (this.showWeekNumbers || this.showISOWeekNumbers)
1085
+ html += "<th></th>";
1086
+ if (this.maxSpan && (!this.maxDate || this.startDate.plus(this.maxSpan) < this.maxDate))
1087
+ maxDate = this.startDate.plus(this.maxSpan);
1088
+ if (this.minSpan && side === "end")
1089
+ minLimit = this.startDate.plus(this.defaultSpan ?? this.minSpan);
1090
+ if (side === "start") {
1091
+ selected = this.startDate;
1092
+ minDate = this.minDate;
1093
+ } else if (side === "end") {
1094
+ selected = this.endDate;
1095
+ minDate = this.startDate;
1096
+ var timeSelector = this.container.find(".drp-calendar .calendar-time.end-time");
1097
+ if (timeSelector.html() != "") {
1098
+ selected = selected.set({
1099
+ hour: !isNaN(selected.hour) ? selected.hour : timeSelector.find(".hourselect option:selected").val(),
1100
+ minute: !isNaN(selected.minute) ? selected.minute : timeSelector.find(".minuteselect option:selected").val(),
1101
+ second: !isNaN(selected.second) ? selected.second : timeSelector.find(".secondselect option:selected").val()
1102
+ });
1103
+ }
1104
+ if (selected < this.startDate)
1105
+ selected = this.startDate;
1106
+ if (maxDate && selected > maxDate)
1107
+ selected = maxDate;
1108
+ }
1109
+ html += `<th colspan="7">`;
1110
+ if (this.externalStyle === "bulma")
1111
+ html += '<div class="select is-small mx-1">';
1112
+ html += '<select class="hourselect">';
1113
+ const ampm = selected.toFormat("a", { locale: "en-US" });
1114
+ let start = 0;
1115
+ if (!this.timePicker24Hour)
1116
+ start = ampm === "AM" ? 1 : 13;
1117
+ for (var i = start; i <= start + 23; i += this.timePickerOpts.hourStep) {
1118
+ let time = selected.set({ hour: i % 24 });
1119
+ let disabled = false;
1120
+ if (minDate && time.set({ minute: 59 }) < minDate)
1121
+ disabled = true;
1122
+ if (maxDate && time.set({ minute: 0 }) > maxDate)
1123
+ disabled = true;
1124
+ if (minLimit && time.endOf("hour") < minLimit)
1125
+ disabled = true;
1126
+ if (!disabled && this.isInvalidTime(time, this.singleDatePicker ? null : side, "hour"))
1127
+ disabled = true;
1128
+ if (this.timePicker24Hour) {
1129
+ if (!disabled && i == selected.hour) {
1130
+ html += `<option value="${i}" selected>${i}</option>`;
1131
+ } else if (disabled) {
1132
+ html += `<option value="${i}" disabled class="disabled">${i}</option>`;
1133
+ } else {
1134
+ html += `<option value="${i}">${i}</option>`;
1135
+ }
1136
+ } else {
1137
+ const i_12 = DateTime.fromFormat(`${i % 24}`, "H").toFormat("h");
1138
+ const i_ampm = DateTime.fromFormat(`${i % 24}`, "H").toFormat("a", { locale: "en-US" });
1139
+ if (ampm == i_ampm) {
1140
+ if (!disabled && i == selected.hour) {
1141
+ html += `<option ampm="${i_ampm}" value="${i % 24}" selected>${i_12}</option>`;
1142
+ } else if (disabled) {
1143
+ html += `<option ampm="${i_ampm}" value="${i % 24}" disabled class="disabled">${i_12}</option>`;
1144
+ } else {
1145
+ html += `<option ampm="${i_ampm}" value="${i % 24}">${i_12}</option>`;
1146
+ }
1147
+ } else {
1148
+ html += `<option ampm="${i_ampm}" hidden="hidden" value="${i % 24}">${i_12}</option>`;
1149
+ }
1150
+ }
1151
+ }
1152
+ html += "</select>";
1153
+ if (this.externalStyle === "bulma")
1154
+ html += "</div>";
1155
+ if (this.timePickerOpts.showMinutes) {
1156
+ html += " : ";
1157
+ if (this.externalStyle === "bulma")
1158
+ html += '<div class="select is-small mx-1">';
1159
+ html += '<select class="minuteselect">';
1160
+ for (var i = 0; i < 60; i += this.timePickerOpts.minuteStep) {
1161
+ var padded = i < 10 ? "0" + i : i;
1162
+ let time = selected.set({ minute: i });
1163
+ let disabled = false;
1164
+ if (minDate && time.set({ second: 59 }) < minDate)
1165
+ disabled = true;
1166
+ if (maxDate && time.set({ second: 0 }) > maxDate)
1167
+ disabled = true;
1168
+ if (minLimit && time.endOf("minute") < minLimit)
1169
+ disabled = true;
1170
+ if (!disabled && this.isInvalidTime(time, this.singleDatePicker ? null : side, "minute"))
1171
+ disabled = true;
1172
+ if (selected.minute == i && !disabled) {
1173
+ html += `<option value="${i}" selected>${padded}</option>`;
1174
+ } else if (disabled) {
1175
+ html += `<option value="${i}" disabled class="disabled">${padded}</option>`;
1176
+ } else {
1177
+ html += `<option value="${i}">${padded}</option>`;
1178
+ }
1179
+ }
1180
+ html += "</select>";
1181
+ if (this.externalStyle === "bulma")
1182
+ html += "</div>";
1183
+ }
1184
+ if (this.timePickerOpts.showSeconds) {
1185
+ html += " : ";
1186
+ if (this.externalStyle === "bulma")
1187
+ html += '<div class="select is-small mx-1">';
1188
+ html += '<select class="secondselect">';
1189
+ for (var i = 0; i < 60; i += this.timePickerOpts.secondStep) {
1190
+ var padded = i < 10 ? "0" + i : i;
1191
+ let time = selected.set({ second: i });
1192
+ let disabled = false;
1193
+ if (minDate && time < minDate)
1194
+ disabled = true;
1195
+ if (maxDate && time > maxDate)
1196
+ disabled = true;
1197
+ if (minLimit && time < minLimit)
1198
+ disabled = true;
1199
+ if (!disabled && this.isInvalidTime(time, this.singleDatePicker ? null : side, "second"))
1200
+ disabled = true;
1201
+ if (selected.second == i && !disabled) {
1202
+ html += `<option value="${i}" selected>${padded}</option>`;
1203
+ } else if (disabled) {
1204
+ html += `<option value="${i}" disabled class="disabled">${padded}</option>`;
1205
+ } else {
1206
+ html += `<option value="${i}">${padded}</option>`;
1207
+ }
1208
+ }
1209
+ html += "</select>";
1210
+ if (this.externalStyle === "bulma")
1211
+ html += "</div>";
1212
+ }
1213
+ if (!this.timePicker24Hour) {
1214
+ if (this.externalStyle === "bulma")
1215
+ html += '<div class="select is-small mx-1">';
1216
+ html += '<select class="ampmselect">';
1217
+ var am_html = "";
1218
+ var pm_html = "";
1219
+ let disabled = false;
1220
+ if (minDate && selected.startOf("day") < minDate)
1221
+ disabled = true;
1222
+ if (maxDate && selected.endOf("day") > maxDate)
1223
+ disabled = true;
1224
+ if (minLimit && selected.startOf("day") < minLimit)
1225
+ disabled = true;
1226
+ if (disabled) {
1227
+ am_html = ' disabled class="disabled "';
1228
+ pm_html = ' disabled class="disabled"';
1229
+ } else {
1230
+ if (this.isInvalidTime(selected, this.singleDatePicker ? null : side, "ampm")) {
1231
+ if (selected.toFormat("a", { locale: "en-US" }) === "AM") {
1232
+ pm_html = ' disabled class="disabled"';
1233
+ } else {
1234
+ am_html = ' disabled class="disabled"';
1235
+ }
1236
+ }
1237
+ }
1238
+ html += `<option value="AM"${am_html}`;
1239
+ if (selected.toFormat("a", { locale: "en-US" }) === "AM")
1240
+ html += " selected";
1241
+ html += `>${Info.meridiems()[0]}</option><option value="PM"${pm_html}`;
1242
+ if (selected.toFormat("a", { locale: "en-US" }) === "PM")
1243
+ html += " selected";
1244
+ html += `>${Info.meridiems()[1]}</option>`;
1245
+ html += "</select>";
1246
+ if (this.externalStyle === "bulma")
1247
+ html += "</div>";
1248
+ }
1249
+ html += "</div></th>";
1250
+ this.container.find(`.drp-calendar .calendar-time.${side}-time`).html(html);
1251
+ }
1252
+ /**
1253
+ * Disable the `Apply` button if no date value is selected
1254
+ * @private
1255
+ */
1256
+ updateFormInputs() {
1257
+ if (this.singleDatePicker || this.endDate && this.startDate <= this.endDate) {
1258
+ this.container.find("button.applyBtn").prop("disabled", false);
1259
+ } else {
1260
+ this.container.find("button.applyBtn").prop("disabled", true);
1261
+ }
1262
+ }
1263
+ /**
1264
+ * Place the picker at the right place in the document
1265
+ * @private
1266
+ */
1267
+ move() {
1268
+ var parentOffset = { top: 0, left: 0 }, containerTop, drops = this.drops;
1269
+ var parentRightEdge = $(window).width();
1270
+ if (!this.parentEl.is("body")) {
1271
+ parentOffset = {
1272
+ top: this.parentEl.offset().top - this.parentEl.scrollTop(),
1273
+ left: this.parentEl.offset().left - this.parentEl.scrollLeft()
1274
+ };
1275
+ parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;
1276
+ }
1277
+ switch (drops) {
1278
+ case "auto":
1279
+ containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
1280
+ if (containerTop + this.container.outerHeight() >= this.parentEl[0].scrollHeight) {
1281
+ containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
1282
+ drops = "up";
1283
+ }
1284
+ break;
1285
+ case "up":
1286
+ containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
1287
+ break;
1288
+ default:
1289
+ containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
1290
+ break;
1291
+ }
1292
+ this.container.css({
1293
+ top: 0,
1294
+ left: 0,
1295
+ right: "auto"
1296
+ });
1297
+ var containerWidth = this.container.outerWidth();
1298
+ this.container.toggleClass("drop-up", drops === "up");
1299
+ if (this.opens === "left") {
1300
+ var containerRight = parentRightEdge - this.element.offset().left - this.element.outerWidth();
1301
+ if (containerWidth + containerRight > $(window).width()) {
1302
+ this.container.css({
1303
+ top: containerTop,
1304
+ right: "auto",
1305
+ left: 9
1306
+ });
1307
+ } else {
1308
+ this.container.css({
1309
+ top: containerTop,
1310
+ right: containerRight,
1311
+ left: "auto"
1312
+ });
1313
+ }
1314
+ } else if (this.opens === "center") {
1315
+ var containerLeft = this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 - containerWidth / 2;
1316
+ if (containerLeft < 0) {
1317
+ this.container.css({
1318
+ top: containerTop,
1319
+ right: "auto",
1320
+ left: 9
1321
+ });
1322
+ } else if (containerLeft + containerWidth > $(window).width()) {
1323
+ this.container.css({
1324
+ top: containerTop,
1325
+ left: "auto",
1326
+ right: 0
1327
+ });
1328
+ } else {
1329
+ this.container.css({
1330
+ top: containerTop,
1331
+ left: containerLeft,
1332
+ right: "auto"
1333
+ });
1334
+ }
1335
+ } else {
1336
+ var containerLeft = this.element.offset().left - parentOffset.left;
1337
+ if (containerLeft + containerWidth > $(window).width()) {
1338
+ this.container.css({
1339
+ top: containerTop,
1340
+ left: "auto",
1341
+ right: 0
1342
+ });
1343
+ } else {
1344
+ this.container.css({
1345
+ top: containerTop,
1346
+ left: containerLeft,
1347
+ right: "auto"
1348
+ });
1349
+ }
1350
+ }
1351
+ }
1352
+ /**
1353
+ * Shows the picker
1354
+ * @emits "show.daterangepicker"
1355
+ */
1356
+ show() {
1357
+ if (this.isShowing) return;
1358
+ this._outsideClickProxy = function(e) {
1359
+ this.outsideClick(e);
1360
+ }.bind(this);
1361
+ $(document).on("mousedown.daterangepicker", this._outsideClickProxy).on("touchend.daterangepicker", this._outsideClickProxy).on("click.daterangepicker", "[data-toggle=dropdown]", this._outsideClickProxy).on("focusin.daterangepicker", this._outsideClickProxy);
1362
+ $(window).on("resize.daterangepicker", function(e) {
1363
+ this.move(e);
1364
+ }.bind(this));
1365
+ this.oldStartDate = this.startDate;
1366
+ this.oldEndDate = this.endDate;
1367
+ this.previousRightTime = this.endDate;
1368
+ this.updateView();
1369
+ this.container.show();
1370
+ this.move();
1371
+ this.element.trigger("show.daterangepicker", this);
1372
+ this.isShowing = true;
1373
+ }
1374
+ /**
1375
+ * Hides the picker
1376
+ * @emits "beforeHide.daterangepicker"
1377
+ * @emits "hide.daterangepicker"
1378
+ */
1379
+ hide() {
1380
+ if (!this.isShowing) return;
1381
+ if (!this.endDate) {
1382
+ this.startDate = this.oldStartDate;
1383
+ this.endDate = this.oldEndDate;
1384
+ }
1385
+ if (this.startDate != this.oldStartDate || this.endDate != this.oldEndDate)
1386
+ this.callback(this.startDate, this.endDate, this.chosenLabel);
1387
+ this.updateElement();
1388
+ if (this.element.triggerHandler("beforeHide.daterangepicker", this))
1389
+ return;
1390
+ $(document).off(".daterangepicker");
1391
+ $(window).off(".daterangepicker");
1392
+ this.container.hide();
1393
+ this.element.trigger("hide.daterangepicker", this);
1394
+ this.isShowing = false;
1395
+ }
1396
+ /**
1397
+ * Toggles visibility of the picker
1398
+ */
1399
+ toggle() {
1400
+ if (this.isShowing) {
1401
+ this.hide();
1402
+ } else {
1403
+ this.show();
1404
+ }
1405
+ }
1406
+ /**
1407
+ * Closes the picker when user clicks outside
1408
+ * @param {external:jQuery} e - The Event target
1409
+ * @emits "outsideClick.daterangepicker"
1410
+ * @private
1411
+ */
1412
+ outsideClick(e) {
1413
+ var target = $(e.target);
1414
+ if (
1415
+ // ie modal dialog fix
1416
+ e.type === "focusin" || target.closest(this.element).length || target.closest(this.container).length || target.closest(".calendar-table").length
1417
+ ) return;
1418
+ if (this.onOutsideClick === "cancel") {
1419
+ this.startDate = this.oldStartDate;
1420
+ this.endDate = this.oldEndDate;
1421
+ }
1422
+ this.hide();
1423
+ this.element.trigger("outsideClick.daterangepicker", this);
1424
+ }
1425
+ /**
1426
+ * Shows calendar when user selects "Custom Ranges"
1427
+ * @emits "showCalendar.daterangepicker"
1428
+ */
1429
+ showCalendars() {
1430
+ this.container.addClass("show-calendar");
1431
+ this.move();
1432
+ this.element.trigger("showCalendar.daterangepicker", this);
1433
+ }
1434
+ /**
1435
+ * Hides calendar when user selects a predefined range
1436
+ * @emits "hideCalendar.daterangepicker"
1437
+ */
1438
+ hideCalendars() {
1439
+ this.container.removeClass("show-calendar");
1440
+ this.element.trigger("hideCalendar.daterangepicker", this);
1441
+ }
1442
+ /**
1443
+ * Set date values after user selected a date
1444
+ * @param {external:jQuery} e - The Event target
1445
+ * @private
1446
+ */
1447
+ clickRange(e) {
1448
+ var label = e.target.getAttribute("data-range-key");
1449
+ this.chosenLabel = label;
1450
+ if (label == this.locale.customRangeLabel) {
1451
+ this.showCalendars();
1452
+ } else {
1453
+ var dates = this.ranges[label];
1454
+ this.startDate = dates[0];
1455
+ this.endDate = dates[1];
1456
+ if (!this.timePicker) {
1457
+ this.startDate.startOf("day");
1458
+ this.endDate.endOf("day");
1459
+ }
1460
+ if (!this.alwaysShowCalendars)
1461
+ this.hideCalendars();
1462
+ if (this.element.triggerHandler("beforeHide.daterangepicker", this))
1463
+ this.updateView();
1464
+ this.clickApply();
1465
+ }
1466
+ }
1467
+ /**
1468
+ * Move calendar to previous month
1469
+ * @param {external:jQuery} e - The Event target
1470
+ * @private
1471
+ */
1472
+ clickPrev(e) {
1473
+ var cal = $(e.target).parents(".drp-calendar");
1474
+ if (cal.hasClass("left")) {
1475
+ this.leftCalendar.month = this.leftCalendar.month.minus({ month: 1 });
1476
+ if (this.linkedCalendars && !this.singleMonthView)
1477
+ this.rightCalendar.month = this.rightCalendar.month.minus({ month: 1 });
1478
+ } else {
1479
+ this.rightCalendar.month = this.rightCalendar.month.minus({ month: 1 });
1480
+ }
1481
+ this.updateCalendars();
1482
+ }
1483
+ /**
1484
+ * Move calendar to next month
1485
+ * @param {external:jQuery} e - The Event target
1486
+ * @private
1487
+ */
1488
+ clickNext(e) {
1489
+ var cal = $(e.target).parents(".drp-calendar");
1490
+ if (cal.hasClass("left")) {
1491
+ this.leftCalendar.month = this.leftCalendar.month.plus({ month: 1 });
1492
+ } else {
1493
+ this.rightCalendar.month = this.rightCalendar.month.plus({ month: 1 });
1494
+ if (this.linkedCalendars)
1495
+ this.leftCalendar.month = this.leftCalendar.month.plus({ month: 1 });
1496
+ }
1497
+ this.updateCalendars();
1498
+ }
1499
+ /**
1500
+ * User hovers over date values
1501
+ * @param {external:jQuery} e - The Event target
1502
+ * @private
1503
+ */
1504
+ hoverDate(e) {
1505
+ if (!$(e.target).hasClass("available")) return;
1506
+ let title = $(e.target).attr("data-title");
1507
+ const row = title.substring(1, 2);
1508
+ const col = title.substring(3, 4);
1509
+ const cal = $(e.target).parents(".drp-calendar");
1510
+ var date = cal.hasClass("left") ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1511
+ const leftCalendar = this.leftCalendar;
1512
+ const rightCalendar = this.rightCalendar;
1513
+ const startDate = this.startDate;
1514
+ const initalMonth = this.initalMonth;
1515
+ if (!this.endDate) {
1516
+ this.container.find(".drp-calendar tbody td").each(function(index, el) {
1517
+ if ($(el).hasClass("week")) return;
1518
+ const title2 = $(el).attr("data-title");
1519
+ const row2 = title2.substring(1, 2);
1520
+ const col2 = title2.substring(3, 4);
1521
+ const cal2 = $(el).parents(".drp-calendar");
1522
+ const dt = cal2.hasClass("left") ? leftCalendar.calendar[row2][col2] : rightCalendar.calendar[row2][col2];
1523
+ if (!startDate && initalMonth) {
1524
+ $(el).removeClass("in-range");
1525
+ } else {
1526
+ if (dt > startDate && dt < date || dt.hasSame(date, "day")) {
1527
+ $(el).addClass("in-range");
1528
+ } else {
1529
+ $(el).removeClass("in-range");
1530
+ }
1531
+ }
1532
+ });
1533
+ }
1534
+ }
1535
+ /**
1536
+ * User hovers over ranges
1537
+ * @param {external:jQuery} e - The Event target
1538
+ * @private
1539
+ */
1540
+ hoverRange(e) {
1541
+ const label = e.target.getAttribute("data-range-key");
1542
+ const previousDates = [this.startDate, this.endDate];
1543
+ const dates = this.ranges[label] ?? [this.startDate, this.endDate];
1544
+ const leftCalendar = this.leftCalendar;
1545
+ const rightCalendar = this.rightCalendar;
1546
+ this.container.find(".drp-calendar tbody td").each(function(index, el) {
1547
+ if ($(el).hasClass("week")) return;
1548
+ const title = $(el).attr("data-title");
1549
+ const row = title.substring(1, 2);
1550
+ const col = title.substring(3, 4);
1551
+ const cal = $(el).parents(".drp-calendar");
1552
+ const dt = cal.hasClass("left") ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];
1553
+ let classAdded = false;
1554
+ if (dt.hasSame(dates[0], "day"))
1555
+ classAdded = $(el).addClass("start-hover").length > 0;
1556
+ if (dt.hasSame(previousDates[0], "day"))
1557
+ classAdded = $(el).addClass("start-date").length > 0;
1558
+ if (dt.hasSame(dates[1], "day"))
1559
+ classAdded = $(el).addClass("end-hover").length > 0;
1560
+ if (previousDates[1] != null && dt.hasSame(previousDates[1], "day"))
1561
+ classAdded = $(el).addClass("end-date").length > 0;
1562
+ if (dt.startOf("day") >= dates[0].startOf("day") && dt.startOf("day") <= dates[1].startOf("day"))
1563
+ classAdded = $(el).addClass("range-hover").length > 0;
1564
+ if (dt.startOf("day") >= previousDates[0].startOf("day") && previousDates[1] != null && dt.startOf("day") <= previousDates[1].startOf("day"))
1565
+ classAdded = $(el).addClass("in-range").length > 0;
1566
+ if (!classAdded) {
1567
+ $(el).removeClass("start-hover");
1568
+ $(el).removeClass("end-hover");
1569
+ $(el).removeClass("start-date");
1570
+ $(el).removeClass("end-date");
1571
+ $(el).removeClass("in-range");
1572
+ $(el).removeClass("range-hover");
1573
+ }
1574
+ });
1575
+ }
1576
+ /**
1577
+ * User leave ranges, remove hightlight from dates
1578
+ * @param {external:jQuery} e - The Event target
1579
+ * @private
1580
+ */
1581
+ leaveRange(e) {
1582
+ this.container.find(".drp-calendar tbody td").each(function(index, el) {
1583
+ if ($(el).hasClass("week")) return;
1584
+ $(el).removeClass("start-hover");
1585
+ $(el).removeClass("end-hover");
1586
+ $(el).removeClass("range-hover");
1587
+ });
1588
+ }
1589
+ /**
1590
+ * User clicked a date
1591
+ * @param {external:jQuery} e - The Event target
1592
+ * @emits "dateChange.daterangepicker"
1593
+ * @private
1594
+ */
1595
+ clickDate(e) {
1596
+ if (!$(e.target).hasClass("available")) return;
1597
+ var title = $(e.target).attr("data-title");
1598
+ var row = title.substring(1, 2);
1599
+ var col = title.substring(3, 4);
1600
+ var cal = $(e.target).parents(".drp-calendar");
1601
+ var date = cal.hasClass("left") ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1602
+ let side;
1603
+ if (this.endDate || !this.startDate || date < this.startDate.startOf("day")) {
1604
+ if (this.timePicker) {
1605
+ let hour = parseInt(this.container.find(".start-time .hourselect").val(), 10);
1606
+ if (isNaN(hour))
1607
+ hour = parseInt(this.container.find(".start-time .hourselect option:last").val(), 10);
1608
+ let minute = 0;
1609
+ if (this.timePickerOpts.showMinutes) {
1610
+ minute = parseInt(this.container.find(".start-time .minuteselect").val(), 10);
1611
+ if (isNaN(minute))
1612
+ minute = parseInt(this.container.find(".start-time .minuteselect option:last").val(), 10);
1613
+ }
1614
+ let second = 0;
1615
+ if (this.timePickerOpts.showSeconds) {
1616
+ second = parseInt(this.container.find(".start-time .secondselect").val(), 10);
1617
+ if (isNaN(second))
1618
+ second = parseInt(this.container.find(".start-time .secondselect option:last").val(), 10);
1619
+ }
1620
+ date = date.set({ hour, minute, second });
1621
+ } else {
1622
+ date = date.startOf("day");
1623
+ }
1624
+ this.endDate = null;
1625
+ this.setStartDate(date, true);
1626
+ side = "start";
1627
+ } else if (!this.endDate && date < this.startDate) {
1628
+ this.setEndDate(this.startDate, true);
1629
+ side = "end";
1630
+ } else {
1631
+ if (this.timePicker) {
1632
+ let hour = parseInt(this.container.find(".end-time .hourselect").val(), 10);
1633
+ if (isNaN(hour))
1634
+ hour = parseInt(this.container.find(".end-time .hourselect option:last").val(), 10);
1635
+ let minute = 0;
1636
+ if (this.timePickerOpts.showMinutes) {
1637
+ minute = parseInt(this.container.find(".end-time .minuteselect").val(), 10);
1638
+ if (isNaN(minute))
1639
+ minute = parseInt(this.container.find(".end-time .minuteselect option:last").val(), 10);
1640
+ }
1641
+ let second = 0;
1642
+ if (this.timePickerOpts.showSeconds) {
1643
+ second = parseInt(this.container.find(".end-time .secondselect").val(), 10);
1644
+ if (isNaN(second))
1645
+ second = parseInt(this.container.find(".end-time .secondselect option:last").val(), 10);
1646
+ }
1647
+ date = date.set({ hour, minute, second });
1648
+ } else {
1649
+ date = date.endOf("day");
1650
+ }
1651
+ this.setEndDate(date, true);
1652
+ if (this.autoApply) {
1653
+ this.calculateChosenLabel();
1654
+ this.clickApply();
1655
+ }
1656
+ side = "end";
1657
+ }
1658
+ if (this.singleDatePicker) {
1659
+ this.setEndDate(this.startDate, true);
1660
+ if (!this.timePicker && this.autoApply)
1661
+ this.clickApply();
1662
+ side = null;
1663
+ }
1664
+ this.updateView();
1665
+ e.stopPropagation();
1666
+ if (this.autoUpdateInput)
1667
+ this.updateElement();
1668
+ this.element.trigger("dateChange.daterangepicker", [this, side]);
1669
+ }
1670
+ /**
1671
+ * Hightlight selected predefined range in calendar
1672
+ * @private
1673
+ */
1674
+ calculateChosenLabel() {
1675
+ var customRange = true;
1676
+ var i = 0;
1677
+ for (var range in this.ranges) {
1678
+ var unit = this.timePicker ? "hour" : "day";
1679
+ if (this.timePicker) {
1680
+ if (this.timePickerOpts.showMinutes) {
1681
+ unit = "minute";
1682
+ } else if (this.timePickerOpts.showSeconds) {
1683
+ unit = "second";
1684
+ }
1685
+ }
1686
+ if (this.startDate.startOf(unit).equals(this.ranges[range][0].startOf(unit)) && this.endDate.startOf(unit).equals(this.ranges[range][1].startOf(unit))) {
1687
+ customRange = false;
1688
+ this.chosenLabel = this.container.find(".ranges li:eq(" + i + ")").addClass("active").attr("data-range-key");
1689
+ break;
1690
+ }
1691
+ i++;
1692
+ }
1693
+ if (customRange) {
1694
+ if (this.showCustomRangeLabel) {
1695
+ this.chosenLabel = this.container.find(".ranges li:last").addClass("active").attr("data-range-key");
1696
+ } else {
1697
+ this.chosenLabel = null;
1698
+ }
1699
+ this.showCalendars();
1700
+ }
1701
+ }
1702
+ /**
1703
+ * User clicked `Apply` button
1704
+ * @emits "apply.daterangepicker"
1705
+ * @private
1706
+ */
1707
+ clickApply() {
1708
+ this.hide();
1709
+ this.element.trigger("apply.daterangepicker", this);
1710
+ }
1711
+ /**
1712
+ * User clicked `Cancel` button
1713
+ * @emits "cancel.daterangepicker"
1714
+ * @private
1715
+ */
1716
+ clickCancel() {
1717
+ this.startDate = this.oldStartDate;
1718
+ this.endDate = this.oldEndDate;
1719
+ this.hide();
1720
+ this.element.trigger("cancel.daterangepicker", this);
1721
+ }
1722
+ /**
1723
+ * Calender month moved
1724
+ * @param {external:jQuery} e - The Event target
1725
+ * @private
1726
+ */
1727
+ monthOrYearChanged(e) {
1728
+ var isLeft = $(e.target).closest(".drp-calendar").hasClass("left"), leftOrRight = isLeft ? "left" : "right", cal = this.container.find(".drp-calendar." + leftOrRight);
1729
+ var month = parseInt(cal.find(".monthselect").val(), 10);
1730
+ var year = cal.find(".yearselect").val();
1731
+ if (!isLeft) {
1732
+ if (year < this.startDate.year || year == this.startDate.year && month < this.startDate.month) {
1733
+ month = this.startDate.month;
1734
+ year = this.startDate.year;
1735
+ }
1736
+ }
1737
+ if (this.minDate) {
1738
+ if (year < this.minDate.year || year == this.minDate.year && month < this.minDate.month) {
1739
+ month = this.minDate.month;
1740
+ year = this.minDate.year;
1741
+ }
1742
+ }
1743
+ if (this.maxDate) {
1744
+ if (year > this.maxDate.year || year == this.maxDate.year && month > this.maxDate.month) {
1745
+ month = this.maxDate.month;
1746
+ year = this.maxDate.year;
1747
+ }
1748
+ }
1749
+ if (isLeft) {
1750
+ this.leftCalendar.month = this.leftCalendar.month.set({ year, month });
1751
+ if (this.linkedCalendars)
1752
+ this.rightCalendar.month = this.leftCalendar.month.plus({ month: 1 });
1753
+ } else {
1754
+ this.rightCalendar.month = this.rightCalendar.month.set({ year, month });
1755
+ if (this.linkedCalendars)
1756
+ this.leftCalendar.month = this.rightCalendar.month.minus({ month: 1 });
1757
+ }
1758
+ this.updateCalendars();
1759
+ }
1760
+ /**
1761
+ * User clicked a time
1762
+ * @param {external:jQuery} e - The Event target
1763
+ * @emits "timeChange.daterangepicker"
1764
+ * @private
1765
+ */
1766
+ timeChanged(e) {
1767
+ const time = $(e.target).closest(".calendar-time");
1768
+ ;
1769
+ const side = time.hasClass("start-time") ? "start" : "end";
1770
+ var hour = parseInt(time.find(".hourselect").val(), 10);
1771
+ if (isNaN(hour))
1772
+ hour = parseInt(time.find(".hourselect option:last").val(), 10);
1773
+ if (!this.timePicker24Hour) {
1774
+ const ampm = time.find(".ampmselect").val();
1775
+ if (ampm == null)
1776
+ time.find(".ampmselect option:last").val();
1777
+ if (ampm != DateTime.fromFormat(`${hour}`, "H").toFormat("a", { locale: "en-US" })) {
1778
+ time.find(".hourselect > option").each(function() {
1779
+ const hidden = $(this).attr("hidden") || false;
1780
+ $(this).attr("hidden", hidden);
1781
+ });
1782
+ const h = DateTime.fromFormat(`${hour}`, "H").toFormat("h");
1783
+ hour = DateTime.fromFormat(`${h}${ampm}`, "ha", { locale: "en-US" }).hour;
1784
+ }
1785
+ }
1786
+ var minute = 0;
1787
+ if (this.timePickerOpts.showMinutes) {
1788
+ minute = parseInt(time.find(".minuteselect").val(), 10);
1789
+ if (isNaN(minute))
1790
+ minute = parseInt(time.find(".minuteselect option:last").val(), 10);
1791
+ }
1792
+ var second = 0;
1793
+ if (this.timePickerOpts.showSeconds) {
1794
+ second = parseInt(time.find(".secondselect").val(), 10);
1795
+ if (isNaN(second))
1796
+ second = parseInt(time.find(".secondselect option:last").val(), 10);
1797
+ }
1798
+ if (side === "start") {
1799
+ if (this.startDate) {
1800
+ let start = this.startDate.set({ hour, minute, second });
1801
+ this.setStartDate(start, true);
1802
+ }
1803
+ if (this.singleDatePicker) {
1804
+ this.endDate = this.startDate;
1805
+ } else if (this.endDate && this.endDate.hasSame(this.startDate, "day") && this.endDate < this.startDate) {
1806
+ this.setEndDate(this.startDate, true);
1807
+ }
1808
+ } else if (this.endDate) {
1809
+ let end = this.endDate.set({ hour, minute, second });
1810
+ this.setEndDate(end, true);
1811
+ }
1812
+ this.updateCalendars();
1813
+ this.updateFormInputs();
1814
+ this.element.trigger("beforeRenderTimePicker.daterangepicker", this);
1815
+ this.renderTimePicker("start");
1816
+ this.renderTimePicker("end");
1817
+ if (this.autoUpdateInput)
1818
+ this.updateElement();
1819
+ this.element.trigger("timeChange.daterangepicker", [this, this.singleDatePicker ? null : side]);
1820
+ }
1821
+ /**
1822
+ * Update the picker with value from attached `<input>` element.
1823
+ * Error is written to console if input string cannot be parsed as a valid date/range
1824
+ * @param {external:jQuery} e - The Event target
1825
+ * @emits "inputChanged.daterangepicker"
1826
+ * @private
1827
+ */
1828
+ elementChanged(e) {
1829
+ if (!this.element.is("input")) return;
1830
+ if (!this.element.val().length) return;
1831
+ const dateString = this.element.val().split(this.locale.separator);
1832
+ var start = null, end = null;
1833
+ const format = typeof this.locale.format === "string" ? this.locale.format : DateTime.parseFormatForOpts(this.locale.format);
1834
+ if (dateString.length === 2) {
1835
+ start = DateTime.fromFormat(dateString[0], format, { locale: DateTime.now().locale });
1836
+ end = DateTime.fromFormat(dateString[1], format, { locale: DateTime.now().locale });
1837
+ }
1838
+ if (this.singleDatePicker || start === null || end === null) {
1839
+ start = DateTime.fromFormat(this.element.val(), format, { locale: DateTime.now().locale });
1840
+ end = start;
1841
+ }
1842
+ if (!start.isValid || !end.isValid) {
1843
+ return;
1844
+ }
1845
+ const trigger = this.startDate != start || !this.singleDatePicker && this.endDate != end;
1846
+ this.setStartDate(start, false);
1847
+ this.setEndDate(end, false);
1848
+ this.updateView();
1849
+ this.updateAltInput();
1850
+ if (trigger)
1851
+ this.element.trigger("inputChanged.daterangepicker", this);
1852
+ }
1853
+ /**
1854
+ * Handles key press, IE 11 compatibility
1855
+ * @param {external:jQuery} e - The Event target
1856
+ * @private
1857
+ */
1858
+ keydown(e) {
1859
+ if (e.keyCode === 9 || e.keyCode === 13) {
1860
+ this.hide();
1861
+ }
1862
+ if (e.keyCode === 27) {
1863
+ e.preventDefault();
1864
+ e.stopPropagation();
1865
+ this.hide();
1866
+ }
1867
+ }
1868
+ /**
1869
+ * Update attached `<input>` element with selected value
1870
+ * @emits external:change
1871
+ */
1872
+ updateElement() {
1873
+ if (this.startDate == null && this.initalMonth)
1874
+ return;
1875
+ if (this.element.is("input")) {
1876
+ let newValue = this.formatDate(this.startDate);
1877
+ if (!this.singleDatePicker) {
1878
+ newValue += this.locale.separator;
1879
+ if (this.endDate)
1880
+ newValue += this.formatDate(this.endDate);
1881
+ }
1882
+ this.updateAltInput();
1883
+ if (newValue !== this.element.val())
1884
+ this.element.val(newValue).trigger("change");
1885
+ } else {
1886
+ this.updateAltInput();
1887
+ }
1888
+ }
1889
+ /**
1890
+ * Update altInput `<input>` element with selected value
1891
+ */
1892
+ updateAltInput() {
1893
+ if (this.altInput == null)
1894
+ return;
1895
+ if (!this.singleDatePicker && !this.endDate)
1896
+ $(this.altInput[1]).val(null);
1897
+ if (this.altFormat == null) {
1898
+ let precision = "day";
1899
+ if (this.timePicker) {
1900
+ if (this.timePickerOpts.showSeconds) {
1901
+ precision = "second";
1902
+ } else if (this.timePickerOpts.showMinutes) {
1903
+ precision = "minute";
1904
+ } else {
1905
+ precision = "hour";
1906
+ }
1907
+ }
1908
+ const startDate = this.startDate.toISO({ format: "basic", precision, includeOffset: false });
1909
+ if (this.singleDatePicker) {
1910
+ $(this.altInput).val(startDate);
1911
+ } else {
1912
+ $(this.altInput[0]).val(startDate);
1913
+ if (this.endDate) {
1914
+ const endDate2 = this.endDate.toISO({ format: "basic", precision, includeOffset: false });
1915
+ $(this.altInput[1]).val(endDate2);
1916
+ }
1917
+ }
1918
+ } else {
1919
+ const startDate = typeof this.altFormat === "function" ? this.altFormat(this.startDate) : this.formatDate(this.startDate, this.altFormat);
1920
+ if (this.singleDatePicker) {
1921
+ $(this.altInput).val(startDate);
1922
+ } else {
1923
+ $(this.altInput[0]).val(startDate);
1924
+ if (this.endDate) {
1925
+ const endDate2 = typeof this.altFormat === "function" ? this.altFormat(this.endDate) : this.formatDate(this.endDate, this.altFormat);
1926
+ $(this.altInput[1]).val(endDate2);
1927
+ }
1928
+ }
1929
+ }
1930
+ }
1931
+ /**
1932
+ * Removes the picker from document
1933
+ */
1934
+ remove() {
1935
+ this.container.remove();
1936
+ this.element.off(".daterangepicker");
1937
+ this.element.removeData();
1938
+ }
1939
+ }
1940
+ if (!$.fn.daterangepicker) {
1941
+ $.fn.daterangepicker = function(options, callback) {
1942
+ const implementOptions = $.extend(true, {}, $.fn.daterangepicker.defaultOptions, options);
1943
+ this.each(function() {
1944
+ const el = $(this);
1945
+ if (el.data("daterangepicker"))
1946
+ el.data("daterangepicker").remove();
1947
+ el.data("daterangepicker", new DateRangePicker(el, implementOptions, callback));
1948
+ });
1949
+ return this;
1950
+ };
1951
+ }
1952
+ })();