kmaterialize 2.3.3-1.0.21 → 2.3.3-1.0.23
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/components/air-datepicker/air-datepicker.js +152 -0
- package/components/alert/alert.js +54 -0
- package/components/button/buttons.js +220 -0
- package/components/card/cards.js +149 -0
- package/components/carousel/carousel.js +574 -0
- package/components/carousel/slider.js +340 -0
- package/components/chip/chips.js +341 -0
- package/components/collapsible/collapsible.js +156 -0
- package/components/color-input/color-input.js +166 -0
- package/components/datepicker/datepicker.js +1035 -0
- package/components/dialog/materialbox.js +377 -0
- package/components/dialog/modal.js +72 -0
- package/components/dropdown/dropdown.js +505 -0
- package/components/file-input/file-input.js +169 -0
- package/components/kanban/_kanban.scss +69 -0
- package/components/kanban/kanban.js +168 -0
- package/components/kanban/kanban.ts +57 -8
- package/components/loading/_loading.scss +68 -0
- package/components/loading/loading.ts +104 -0
- package/components/loading/loadingSpec.js +102 -0
- package/components/navigation-drawer/sidenav.js +454 -0
- package/components/number-input/number-input.js +68 -0
- package/components/password-input/password-input.js +49 -0
- package/components/popup/_popup.scss +106 -0
- package/components/popup/popup.ts +113 -0
- package/components/popup/popupSpec.js +140 -0
- package/components/search/autocomplete.js +470 -0
- package/components/slider/range.js +169 -0
- package/components/snackbar/toasts.js +244 -0
- package/components/tabs/tabs.js +289 -0
- package/components/textfield/forms.js +172 -0
- package/components/textfield/select.js +385 -0
- package/components/timepicker/timepicker.js +698 -0
- package/components/tom-select/tom-select-field.js +130 -0
- package/components/toolbar/toolbar.js +134 -0
- package/components/tooltip/tooltip.js +270 -0
- package/dist/css/materialize.colors.min.css +1 -1
- package/dist/css/materialize.css +322 -1
- package/dist/css/materialize.min.css +2 -2
- package/dist/css/materialize.min.css.map +1 -1
- package/dist/js/materialize.cjs.js +258 -42
- package/dist/js/materialize.d.ts +50 -3
- package/dist/js/materialize.js +258 -42
- package/dist/js/materialize.min.js +2 -2
- package/dist/js/materialize.mjs +257 -43
- package/package.json +6 -1
- package/sass/materialize.scss +2 -0
|
@@ -0,0 +1,1035 @@
|
|
|
1
|
+
import { Utils } from '../../src/utils';
|
|
2
|
+
import { Component } from '../../src/component';
|
|
3
|
+
import { FormSelect } from '../textfield/select';
|
|
4
|
+
import { DockedDisplayPlugin } from '../../src/dockedDisplayPlugin';
|
|
5
|
+
import { ModalDisplayPlugin } from '../../src/modalDisplayPlugin';
|
|
6
|
+
const _defaults = {
|
|
7
|
+
// the default output format for the input field value
|
|
8
|
+
format: 'mmm dd, yyyy',
|
|
9
|
+
// Used to create date object from current input string
|
|
10
|
+
parse: null,
|
|
11
|
+
// The initial condition if the datepicker is based on date range
|
|
12
|
+
isDateRange: false,
|
|
13
|
+
// The selector of the user specified date range end element
|
|
14
|
+
dateRangeEndEl: null,
|
|
15
|
+
// The initial condition if the datepicker is based on multiple date selection
|
|
16
|
+
isMultipleSelection: false,
|
|
17
|
+
// The initial date to view when first opened
|
|
18
|
+
defaultDate: null,
|
|
19
|
+
// The initial end date to view when first opened
|
|
20
|
+
defaultEndDate: null,
|
|
21
|
+
// Make the `defaultDate` the initial selected value
|
|
22
|
+
setDefaultDate: false,
|
|
23
|
+
// Make the `defaultEndDate` the initial selected value
|
|
24
|
+
setDefaultEndDate: false,
|
|
25
|
+
disableWeekends: false,
|
|
26
|
+
disableDayFn: null,
|
|
27
|
+
// First day of week (0: Sunday, 1: Monday etc)
|
|
28
|
+
firstDay: 0,
|
|
29
|
+
// The earliest date that can be selected
|
|
30
|
+
minDate: null,
|
|
31
|
+
// Thelatest date that can be selected
|
|
32
|
+
maxDate: null,
|
|
33
|
+
// Number of years either side, or array of upper/lower range
|
|
34
|
+
yearRange: 10,
|
|
35
|
+
// used internally (don't config outside)
|
|
36
|
+
minYear: 0,
|
|
37
|
+
maxYear: 9999,
|
|
38
|
+
minMonth: undefined,
|
|
39
|
+
maxMonth: undefined,
|
|
40
|
+
startRange: null,
|
|
41
|
+
endRange: null,
|
|
42
|
+
isRTL: false,
|
|
43
|
+
yearRangeReverse: false,
|
|
44
|
+
// Render the month after year in the calendar title
|
|
45
|
+
showMonthAfterYear: false,
|
|
46
|
+
// Render days of the calendar grid that fall in the next or previous month
|
|
47
|
+
showDaysInNextAndPreviousMonths: false,
|
|
48
|
+
// Specify if docked picker is in open state by default
|
|
49
|
+
openByDefault: false,
|
|
50
|
+
// Specify a DOM element to render the calendar in
|
|
51
|
+
container: null,
|
|
52
|
+
// Show clear button
|
|
53
|
+
showClearBtn: false,
|
|
54
|
+
// Autosubmit
|
|
55
|
+
autoSubmit: true,
|
|
56
|
+
// internationalization
|
|
57
|
+
i18n: {
|
|
58
|
+
cancel: 'Cancel',
|
|
59
|
+
clear: 'Clear',
|
|
60
|
+
done: 'Ok',
|
|
61
|
+
previousMonth: '‹',
|
|
62
|
+
nextMonth: '›',
|
|
63
|
+
months: [
|
|
64
|
+
'January',
|
|
65
|
+
'February',
|
|
66
|
+
'March',
|
|
67
|
+
'April',
|
|
68
|
+
'May',
|
|
69
|
+
'June',
|
|
70
|
+
'July',
|
|
71
|
+
'August',
|
|
72
|
+
'September',
|
|
73
|
+
'October',
|
|
74
|
+
'November',
|
|
75
|
+
'December'
|
|
76
|
+
],
|
|
77
|
+
monthsShort: [
|
|
78
|
+
'Jan',
|
|
79
|
+
'Feb',
|
|
80
|
+
'Mar',
|
|
81
|
+
'Apr',
|
|
82
|
+
'May',
|
|
83
|
+
'Jun',
|
|
84
|
+
'Jul',
|
|
85
|
+
'Aug',
|
|
86
|
+
'Sep',
|
|
87
|
+
'Oct',
|
|
88
|
+
'Nov',
|
|
89
|
+
'Dec'
|
|
90
|
+
],
|
|
91
|
+
weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
|
92
|
+
weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
93
|
+
weekdaysAbbrev: ['S', 'M', 'T', 'W', 'T', 'F', 'S']
|
|
94
|
+
},
|
|
95
|
+
// events array
|
|
96
|
+
events: [],
|
|
97
|
+
// callback function
|
|
98
|
+
onSelect: null,
|
|
99
|
+
onDraw: null,
|
|
100
|
+
onInputInteraction: null,
|
|
101
|
+
displayPlugin: null,
|
|
102
|
+
displayPluginOptions: null,
|
|
103
|
+
onConfirm: null,
|
|
104
|
+
onCancel: null
|
|
105
|
+
};
|
|
106
|
+
export class Datepicker extends Component {
|
|
107
|
+
id;
|
|
108
|
+
multiple = false;
|
|
109
|
+
calendarEl;
|
|
110
|
+
/** CLEAR button instance. */
|
|
111
|
+
// clearBtn: HTMLElement;
|
|
112
|
+
/** DONE button instance */
|
|
113
|
+
/*doneBtn: HTMLElement;
|
|
114
|
+
cancelBtn: HTMLElement;*/
|
|
115
|
+
containerEl;
|
|
116
|
+
yearTextEl;
|
|
117
|
+
dateTextEl;
|
|
118
|
+
endDateEl;
|
|
119
|
+
dateEls;
|
|
120
|
+
/** The selected Date. */
|
|
121
|
+
date;
|
|
122
|
+
endDate;
|
|
123
|
+
dates;
|
|
124
|
+
formats;
|
|
125
|
+
calendars;
|
|
126
|
+
_y;
|
|
127
|
+
_m;
|
|
128
|
+
displayPlugin;
|
|
129
|
+
footer;
|
|
130
|
+
static _template;
|
|
131
|
+
constructor(el, options) {
|
|
132
|
+
super(el, options, Datepicker);
|
|
133
|
+
this.el['M_Datepicker'] = this;
|
|
134
|
+
this.options = {
|
|
135
|
+
...Datepicker.defaults,
|
|
136
|
+
...options
|
|
137
|
+
};
|
|
138
|
+
// make sure i18n defaults are not lost when only few i18n option properties are passed
|
|
139
|
+
if (!!options && options.hasOwnProperty('i18n') && typeof options.i18n === 'object') {
|
|
140
|
+
this.options.i18n = { ...Datepicker.defaults.i18n, ...options.i18n };
|
|
141
|
+
}
|
|
142
|
+
// Remove time component from minDate and maxDate options
|
|
143
|
+
if (this.options.minDate)
|
|
144
|
+
this.options.minDate.setHours(0, 0, 0, 0);
|
|
145
|
+
if (this.options.maxDate)
|
|
146
|
+
this.options.maxDate.setHours(0, 0, 0, 0);
|
|
147
|
+
this.id = Utils.guid();
|
|
148
|
+
this._setupVariables();
|
|
149
|
+
this._insertHTMLIntoDOM();
|
|
150
|
+
this._setupEventHandlers();
|
|
151
|
+
if (this.options.displayPlugin)
|
|
152
|
+
this._setupDisplayPlugin();
|
|
153
|
+
this._pickerSetup();
|
|
154
|
+
}
|
|
155
|
+
static get defaults() {
|
|
156
|
+
return _defaults;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Initializes instances of Datepicker.
|
|
160
|
+
* @param els HTML elements.
|
|
161
|
+
* @param options Component options.
|
|
162
|
+
*/
|
|
163
|
+
static init(els, options = {}) {
|
|
164
|
+
return super.init(els, options, Datepicker);
|
|
165
|
+
}
|
|
166
|
+
static _isDate(obj) {
|
|
167
|
+
return /Date/.test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
|
|
168
|
+
}
|
|
169
|
+
static _isWeekend(date) {
|
|
170
|
+
const day = date.getDay();
|
|
171
|
+
return day === 0 || day === 6;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* @deprecated as this function has no effect without any return statement or global parameter setter.
|
|
175
|
+
*/
|
|
176
|
+
static _setToStartOfDay(date) {
|
|
177
|
+
if (Datepicker._isDate(date))
|
|
178
|
+
date.setHours(0, 0, 0, 0);
|
|
179
|
+
}
|
|
180
|
+
static _getDaysInMonth(year, month) {
|
|
181
|
+
return [31, Datepicker._isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
|
|
182
|
+
}
|
|
183
|
+
static _isLeapYear(year) {
|
|
184
|
+
// solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
|
|
185
|
+
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
186
|
+
}
|
|
187
|
+
static _compareDates(a, b) {
|
|
188
|
+
// weak date comparison (use setToStartOfDay(date) to ensure correct result)
|
|
189
|
+
return a.getTime() === b.getTime();
|
|
190
|
+
}
|
|
191
|
+
static _compareWithinRange(day, date, dateEnd) {
|
|
192
|
+
return day.getTime() > date.getTime() && day.getTime() < dateEnd.getTime();
|
|
193
|
+
}
|
|
194
|
+
static _comparePastDate(a, b) {
|
|
195
|
+
return a.getTime() < b.getTime();
|
|
196
|
+
}
|
|
197
|
+
static getInstance(el) {
|
|
198
|
+
return el['M_Datepicker'];
|
|
199
|
+
}
|
|
200
|
+
destroy() {
|
|
201
|
+
this._removeEventHandlers();
|
|
202
|
+
this.containerEl.remove();
|
|
203
|
+
this.destroySelects();
|
|
204
|
+
this.el['M_Datepicker'] = undefined;
|
|
205
|
+
}
|
|
206
|
+
destroySelects() {
|
|
207
|
+
const oldYearSelect = this.calendarEl.querySelector('.orig-select-year');
|
|
208
|
+
if (oldYearSelect) {
|
|
209
|
+
FormSelect.getInstance(oldYearSelect).destroy();
|
|
210
|
+
}
|
|
211
|
+
const oldMonthSelect = this.calendarEl.querySelector('.orig-select-month');
|
|
212
|
+
if (oldMonthSelect) {
|
|
213
|
+
FormSelect.getInstance(oldMonthSelect).destroy();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
_insertHTMLIntoDOM() {
|
|
217
|
+
// HTML5 input date field support
|
|
218
|
+
if (this.el.type == 'date') {
|
|
219
|
+
this.el.classList.add('datepicker-date-input');
|
|
220
|
+
}
|
|
221
|
+
if (!this.el.parentElement.querySelector('.datepicker-format') === null) {
|
|
222
|
+
this._renderDateInputFormat(this.el);
|
|
223
|
+
}
|
|
224
|
+
if (this.options.isDateRange) {
|
|
225
|
+
this.containerEl.classList.add('daterange');
|
|
226
|
+
if (!this.options.dateRangeEndEl) {
|
|
227
|
+
this.endDateEl = this.createDateInput();
|
|
228
|
+
this.endDateEl.classList.add('datepicker-end-date');
|
|
229
|
+
}
|
|
230
|
+
else if (document.querySelector(this.options.dateRangeEndEl) === undefined) {
|
|
231
|
+
console.warn('Specified date range end input element in dateRangeEndEl not found');
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
this.endDateEl = document.querySelector(this.options.dateRangeEndEl);
|
|
235
|
+
if (!this.endDateEl.parentElement.querySelector('.datepicker-format') === null) {
|
|
236
|
+
this._renderDateInputFormat(this.endDateEl);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
Utils.createButton(this.footer, this.options.i18n.clear, ['datepicker-clear'], this.options.showClearBtn, this._handleClearClick);
|
|
241
|
+
if (!this.options.autoSubmit) {
|
|
242
|
+
Utils.createConfirmationContainer(this.footer, this.options.i18n.done, this.options.i18n.cancel, this._confirm, this._cancel);
|
|
243
|
+
}
|
|
244
|
+
if (this.options.container) {
|
|
245
|
+
const optEl = this.options.container;
|
|
246
|
+
this.options.container =
|
|
247
|
+
optEl instanceof HTMLElement ? optEl : document.querySelector(optEl);
|
|
248
|
+
this.options.container.append(this.containerEl);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
const appendTo = !this.endDateEl ? this.el : this.endDateEl;
|
|
252
|
+
appendTo.parentElement.after(this.containerEl);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Renders the date input format
|
|
257
|
+
*/
|
|
258
|
+
_renderDateInputFormat(el) {
|
|
259
|
+
el.parentElement.querySelector('.datepicker-format').innerHTML = this.options.format.toString();
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Gets a string representation of the given date.
|
|
263
|
+
*/
|
|
264
|
+
toString(date = this.date, format = null) {
|
|
265
|
+
format = format || this.options.format;
|
|
266
|
+
if (typeof format === 'function')
|
|
267
|
+
return format(date);
|
|
268
|
+
if (!Datepicker._isDate(date))
|
|
269
|
+
return '';
|
|
270
|
+
// String Format
|
|
271
|
+
return this.formatDate(date, format);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Returns the formatted date.
|
|
275
|
+
*/
|
|
276
|
+
formatDate(date, format) {
|
|
277
|
+
const formatArray = format.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g);
|
|
278
|
+
return formatArray
|
|
279
|
+
.map((label) => (this.formats[label] ? this.formats[label](date) : label))
|
|
280
|
+
.join('');
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Sets date from input field.
|
|
284
|
+
*/
|
|
285
|
+
setDateFromInput(el) {
|
|
286
|
+
const date = new Date(Date.parse(el.value));
|
|
287
|
+
this.setDate(date, false, el == this.endDateEl, true);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Set a date on the datepicker.
|
|
291
|
+
* @param date Date to set on the datepicker.
|
|
292
|
+
* @param preventOnSelect Undocumented as of 5 March 2018.
|
|
293
|
+
* @param isEndDate
|
|
294
|
+
* @param fromUserInput
|
|
295
|
+
*/
|
|
296
|
+
setDate(date = null, preventOnSelect = false, isEndDate = false, fromUserInput = false) {
|
|
297
|
+
const selectedDate = this.validateDate(date);
|
|
298
|
+
if (!selectedDate) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (!this.options.isMultipleSelection)
|
|
302
|
+
this.setSingleDate(selectedDate, isEndDate);
|
|
303
|
+
else if (!fromUserInput)
|
|
304
|
+
this.setMultiDate(selectedDate);
|
|
305
|
+
Datepicker._setToStartOfDay(selectedDate);
|
|
306
|
+
this.gotoDate(selectedDate);
|
|
307
|
+
if (!preventOnSelect && typeof this.options.onSelect === 'function') {
|
|
308
|
+
this.options.onSelect.call(this, selectedDate);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
validateDate(date) {
|
|
312
|
+
if (!date) {
|
|
313
|
+
this._renderDateDisplay(date);
|
|
314
|
+
return this.draw();
|
|
315
|
+
}
|
|
316
|
+
if (typeof date === 'string') {
|
|
317
|
+
date = new Date(Date.parse(date));
|
|
318
|
+
}
|
|
319
|
+
if (!Datepicker._isDate(date)) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const min = this.options.minDate, max = this.options.maxDate;
|
|
323
|
+
if (Datepicker._isDate(min) && date < min) {
|
|
324
|
+
date = min;
|
|
325
|
+
}
|
|
326
|
+
else if (Datepicker._isDate(max) && date > max) {
|
|
327
|
+
date = max;
|
|
328
|
+
}
|
|
329
|
+
return new Date(date.getTime());
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Set a single date on the datepicker.
|
|
333
|
+
* @param date Date to set on the datepicker.
|
|
334
|
+
* @param isEndDate
|
|
335
|
+
*/
|
|
336
|
+
setSingleDate(date, isEndDate) {
|
|
337
|
+
if (!isEndDate) {
|
|
338
|
+
this.date = date;
|
|
339
|
+
}
|
|
340
|
+
else if (isEndDate) {
|
|
341
|
+
this.endDate = date;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Set a multi date on the datepicker.
|
|
346
|
+
* @param date Date to set on the datepicker.
|
|
347
|
+
*/
|
|
348
|
+
setMultiDate(date) {
|
|
349
|
+
const selectedDate = this.dates?.find((item) => {
|
|
350
|
+
return item.getTime() === date.getTime() ? item : false;
|
|
351
|
+
});
|
|
352
|
+
if (!selectedDate) {
|
|
353
|
+
this.dates.push(date);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
this.dates.splice(this.dates.indexOf(selectedDate), 1);
|
|
357
|
+
}
|
|
358
|
+
this.dates.sort((a, b) => (a.getTime() < b.getTime() ? -1 : 0));
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Sets the data-date attribute on the date input field
|
|
362
|
+
*/
|
|
363
|
+
setDataDate(el, date) {
|
|
364
|
+
el.setAttribute('data-date', this.toString(date));
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Sets dates on the input values.
|
|
368
|
+
*/
|
|
369
|
+
setInputValues() {
|
|
370
|
+
if (!this.options?.isMultipleSelection) {
|
|
371
|
+
this.setInputValue(this.el, this.date);
|
|
372
|
+
if (this.options?.isDateRange) {
|
|
373
|
+
this.setInputValue(this.endDateEl, this.endDate);
|
|
374
|
+
}
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
this.setMultipleSelectionInputValues();
|
|
378
|
+
}
|
|
379
|
+
setMultipleSelectionInputValues() {
|
|
380
|
+
const dateElsArr = Array.from(this.dateEls).filter((el, index) => {
|
|
381
|
+
if (index > this.dates.length - 1)
|
|
382
|
+
return el;
|
|
383
|
+
});
|
|
384
|
+
dateElsArr.forEach((el) => {
|
|
385
|
+
el.remove();
|
|
386
|
+
});
|
|
387
|
+
this.dates.forEach((date, index) => {
|
|
388
|
+
if (Array.from(this.dateEls)[index]) {
|
|
389
|
+
this.setInputValue(this.dateEls[index], date);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const dateEl = this.createDateInput();
|
|
393
|
+
this.setInputValue(dateEl, date);
|
|
394
|
+
this.dateEls.push(dateEl);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Sets given date as the input value on the given element.
|
|
399
|
+
*/
|
|
400
|
+
setInputValue(el, date) {
|
|
401
|
+
if (el.type == 'date') {
|
|
402
|
+
this.setDataDate(el, date);
|
|
403
|
+
el.value = this.formatDate(date, 'yyyy-mm-dd');
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
el.value = this.toString(date);
|
|
407
|
+
}
|
|
408
|
+
this.el.dispatchEvent(new CustomEvent('change', {
|
|
409
|
+
bubbles: true,
|
|
410
|
+
cancelable: true,
|
|
411
|
+
composed: true,
|
|
412
|
+
detail: { firedBy: this }
|
|
413
|
+
}));
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Display plugin setup.
|
|
417
|
+
*/
|
|
418
|
+
_setupDisplayPlugin() {
|
|
419
|
+
const displayPluginOptions = {
|
|
420
|
+
...this.options.displayPluginOptions,
|
|
421
|
+
...{
|
|
422
|
+
onOpen: () => {
|
|
423
|
+
document.querySelectorAll('.select-dropdown').forEach((e) => {
|
|
424
|
+
e.tabIndex = 0;
|
|
425
|
+
});
|
|
426
|
+
},
|
|
427
|
+
onClose: () => {
|
|
428
|
+
document.querySelectorAll('.select-dropdown').forEach((e) => {
|
|
429
|
+
e.tabIndex = -1;
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
if (this.options.displayPlugin === 'docked')
|
|
435
|
+
this.displayPlugin = DockedDisplayPlugin.init(this.el, this.containerEl, displayPluginOptions);
|
|
436
|
+
if (this.options.displayPlugin === 'modal') {
|
|
437
|
+
this.displayPlugin = ModalDisplayPlugin.init(this.el, this.containerEl, {
|
|
438
|
+
...displayPluginOptions,
|
|
439
|
+
...{ classList: ['datepicker-modal'] }
|
|
440
|
+
});
|
|
441
|
+
this.footer.remove();
|
|
442
|
+
this.footer = this.displayPlugin.footer;
|
|
443
|
+
}
|
|
444
|
+
if (this.options.openByDefault)
|
|
445
|
+
this.displayPlugin.show();
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Renders the date in the modal head section.
|
|
449
|
+
*/
|
|
450
|
+
_renderDateDisplay(date, endDate = null) {
|
|
451
|
+
const displayDate = Datepicker._isDate(date) ? date : new Date();
|
|
452
|
+
// this.yearTextEl.innerHTML = displayDate.getFullYear().toString();
|
|
453
|
+
// @todo should we include an option for date formatting by component options?
|
|
454
|
+
if (!this.options.isDateRange) {
|
|
455
|
+
this.dateTextEl.innerHTML = this.formatDate(displayDate, 'ddd, mmm d');
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
const displayEndDate = Datepicker._isDate(endDate) ? endDate : new Date();
|
|
459
|
+
this.dateTextEl.innerHTML = `${this.formatDate(displayDate, 'mmm d')} - ${this.formatDate(displayEndDate, 'mmm d')}`;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Change date view to a specific date on the datepicker.
|
|
464
|
+
* @param date Date to show on the datepicker.
|
|
465
|
+
*/
|
|
466
|
+
gotoDate(date) {
|
|
467
|
+
let newCalendar = true;
|
|
468
|
+
if (!Datepicker._isDate(date)) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (this.calendars) {
|
|
472
|
+
const firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1), lastVisibleDate = new Date(this.calendars[this.calendars.length - 1].year, this.calendars[this.calendars.length - 1].month, 1), visibleDate = date.getTime();
|
|
473
|
+
// get the end of the month
|
|
474
|
+
lastVisibleDate.setMonth(lastVisibleDate.getMonth() + 1);
|
|
475
|
+
lastVisibleDate.setDate(lastVisibleDate.getDate() - 1);
|
|
476
|
+
newCalendar =
|
|
477
|
+
visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate;
|
|
478
|
+
}
|
|
479
|
+
if (newCalendar) {
|
|
480
|
+
this.calendars = [
|
|
481
|
+
{
|
|
482
|
+
month: date.getMonth(),
|
|
483
|
+
year: date.getFullYear()
|
|
484
|
+
}
|
|
485
|
+
];
|
|
486
|
+
}
|
|
487
|
+
this.adjustCalendars();
|
|
488
|
+
}
|
|
489
|
+
adjustCalendars() {
|
|
490
|
+
this.calendars[0] = this.adjustCalendar(this.calendars[0]);
|
|
491
|
+
this.draw();
|
|
492
|
+
}
|
|
493
|
+
adjustCalendar(calendar) {
|
|
494
|
+
if (calendar.month < 0) {
|
|
495
|
+
calendar.year -= Math.ceil(Math.abs(calendar.month) / 12);
|
|
496
|
+
calendar.month += 12;
|
|
497
|
+
}
|
|
498
|
+
if (calendar.month > 11) {
|
|
499
|
+
calendar.year += Math.floor(Math.abs(calendar.month) / 12);
|
|
500
|
+
calendar.month -= 12;
|
|
501
|
+
}
|
|
502
|
+
return calendar;
|
|
503
|
+
}
|
|
504
|
+
nextMonth() {
|
|
505
|
+
this.calendars[0].month++;
|
|
506
|
+
this.adjustCalendars();
|
|
507
|
+
}
|
|
508
|
+
prevMonth() {
|
|
509
|
+
this.calendars[0].month--;
|
|
510
|
+
this.adjustCalendars();
|
|
511
|
+
}
|
|
512
|
+
render(year, month, randId) {
|
|
513
|
+
const now = new Date(), days = Datepicker._getDaysInMonth(year, month), data = [];
|
|
514
|
+
let before = new Date(year, month, 1).getDay(), row = [];
|
|
515
|
+
Datepicker._setToStartOfDay(now);
|
|
516
|
+
if (this.options.firstDay > 0) {
|
|
517
|
+
before -= this.options.firstDay;
|
|
518
|
+
if (before < 0) {
|
|
519
|
+
before += 7;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
const previousMonth = month === 0 ? 11 : month - 1, nextMonth = month === 11 ? 0 : month + 1, yearOfPreviousMonth = month === 0 ? year - 1 : year, yearOfNextMonth = month === 11 ? year + 1 : year, daysInPreviousMonth = Datepicker._getDaysInMonth(yearOfPreviousMonth, previousMonth);
|
|
523
|
+
let cells = days + before, after = cells;
|
|
524
|
+
while (after > 7) {
|
|
525
|
+
after -= 7;
|
|
526
|
+
}
|
|
527
|
+
cells += 7 - after;
|
|
528
|
+
let isWeekSelected = false;
|
|
529
|
+
for (let i = 0, r = 0; i < cells; i++) {
|
|
530
|
+
const day = new Date(year, month, 1 + (i - before)), isToday = Datepicker._compareDates(day, now), hasEvent = this.options.events.indexOf(day.toDateString()) !== -1, isEmpty = i < before || i >= days + before, isStartRange = this.options.startRange && Datepicker._compareDates(this.options.startRange, day), isEndRange = this.options.endRange && Datepicker._compareDates(this.options.endRange, day), isInRange = this.options.startRange &&
|
|
531
|
+
this.options.endRange &&
|
|
532
|
+
this.options.startRange < day &&
|
|
533
|
+
day < this.options.endRange, isDisabled = (this.options.minDate && day < this.options.minDate) ||
|
|
534
|
+
(this.options.maxDate && day > this.options.maxDate) ||
|
|
535
|
+
(this.options.disableWeekends && Datepicker._isWeekend(day)) ||
|
|
536
|
+
(this.options.disableDayFn && this.options.disableDayFn(day)), isDateRangeStart = this.options.isDateRange &&
|
|
537
|
+
this.date &&
|
|
538
|
+
this.endDate &&
|
|
539
|
+
Datepicker._compareDates(this.date, day), isDateRangeEnd = this.options.isDateRange && this.endDate && Datepicker._compareDates(this.endDate, day), isDateRange = this.options.isDateRange &&
|
|
540
|
+
Datepicker._isDate(this.endDate) &&
|
|
541
|
+
Datepicker._compareWithinRange(day, this.date, this.endDate);
|
|
542
|
+
let dayNumber = 1 + (i - before), monthNumber = month, yearNumber = year;
|
|
543
|
+
let isSelected = false;
|
|
544
|
+
if (Datepicker._isDate(this.date)) {
|
|
545
|
+
isSelected = Datepicker._compareDates(day, this.date);
|
|
546
|
+
}
|
|
547
|
+
if (!isSelected && Datepicker._isDate(this.endDate)) {
|
|
548
|
+
isSelected = Datepicker._compareDates(day, this.endDate);
|
|
549
|
+
}
|
|
550
|
+
if (this.options.isMultipleSelection &&
|
|
551
|
+
this.dates?.some((item) => item.getTime() === day.getTime())) {
|
|
552
|
+
isSelected = true;
|
|
553
|
+
}
|
|
554
|
+
if (isEmpty) {
|
|
555
|
+
if (i < before) {
|
|
556
|
+
dayNumber = daysInPreviousMonth + dayNumber;
|
|
557
|
+
monthNumber = previousMonth;
|
|
558
|
+
yearNumber = yearOfPreviousMonth;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
dayNumber = dayNumber - days;
|
|
562
|
+
monthNumber = nextMonth;
|
|
563
|
+
yearNumber = yearOfNextMonth;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
const dayConfig = {
|
|
567
|
+
day: dayNumber,
|
|
568
|
+
month: monthNumber,
|
|
569
|
+
year: yearNumber,
|
|
570
|
+
hasEvent: hasEvent,
|
|
571
|
+
isSelected: isSelected,
|
|
572
|
+
isToday: isToday,
|
|
573
|
+
isDisabled: isDisabled,
|
|
574
|
+
isEmpty: isEmpty,
|
|
575
|
+
isStartRange: isStartRange,
|
|
576
|
+
isEndRange: isEndRange,
|
|
577
|
+
isInRange: isInRange,
|
|
578
|
+
showDaysInNextAndPreviousMonths: this.options.showDaysInNextAndPreviousMonths,
|
|
579
|
+
isDateRangeStart: isDateRangeStart,
|
|
580
|
+
isDateRangeEnd: isDateRangeEnd,
|
|
581
|
+
isDateRange: isDateRange
|
|
582
|
+
};
|
|
583
|
+
row.push(this.renderDay(dayConfig));
|
|
584
|
+
if (++r === 7) {
|
|
585
|
+
data.push(this.renderRow(row, this.options.isRTL, isWeekSelected));
|
|
586
|
+
row = [];
|
|
587
|
+
r = 0;
|
|
588
|
+
isWeekSelected = false;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return this.renderTable(this.options, data, randId);
|
|
592
|
+
}
|
|
593
|
+
renderDay(opts) {
|
|
594
|
+
const classMap = {
|
|
595
|
+
isDisabled: 'is-disabled',
|
|
596
|
+
isToday: 'is-today',
|
|
597
|
+
isSelected: 'is-selected',
|
|
598
|
+
hasEvent: 'has-event',
|
|
599
|
+
isInRange: 'is-inrange',
|
|
600
|
+
isStartRange: 'is-startrange',
|
|
601
|
+
isEndRange: 'is-endrange',
|
|
602
|
+
isDateRangeStart: 'is-daterange-start',
|
|
603
|
+
isDateRangeEnd: 'is-daterange-end',
|
|
604
|
+
isDateRange: 'is-daterange'
|
|
605
|
+
}, ariaSelected = !(['isSelected', 'isDateRange'].filter((prop) => !!(opts.hasOwnProperty(prop) && opts[prop] === true)).length === 0), arr = ['datepicker-day'];
|
|
606
|
+
if (opts.isEmpty) {
|
|
607
|
+
if (opts.showDaysInNextAndPreviousMonths) {
|
|
608
|
+
arr.push('is-outside-current-month');
|
|
609
|
+
arr.push('is-selection-disabled');
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
return '<td class="is-empty"></td>';
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
for (const [property, className] of Object.entries(classMap)) {
|
|
616
|
+
if (opts.hasOwnProperty(property) && opts[property]) {
|
|
617
|
+
arr.push(className);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return (`<td data-day="${opts.day}" class="${arr.join(' ')}" aria-selected="${ariaSelected}">` +
|
|
621
|
+
`<button class="datepicker-day-button" type="button" data-year="${opts.year}" data-month="${opts.month}" data-day="${opts.day}">${opts.day}</button>` +
|
|
622
|
+
'</td>');
|
|
623
|
+
}
|
|
624
|
+
renderRow(days, isRTL, isRowSelected) {
|
|
625
|
+
return ('<tr class="datepicker-row' +
|
|
626
|
+
(isRowSelected ? ' is-selected' : '') +
|
|
627
|
+
'">' +
|
|
628
|
+
(isRTL ? days.reverse() : days).join('') +
|
|
629
|
+
'</tr>');
|
|
630
|
+
}
|
|
631
|
+
renderTable(opts, data, randId) {
|
|
632
|
+
return ('<div class="datepicker-table-wrapper"><table cellpadding="0" cellspacing="0" class="datepicker-table" role="grid" aria-labelledby="' +
|
|
633
|
+
randId +
|
|
634
|
+
'">' +
|
|
635
|
+
this.renderHead(opts) +
|
|
636
|
+
this.renderBody(data) +
|
|
637
|
+
'</table></div>');
|
|
638
|
+
}
|
|
639
|
+
renderHead(opts) {
|
|
640
|
+
const arr = [];
|
|
641
|
+
let i;
|
|
642
|
+
for (i = 0; i < 7; i++) {
|
|
643
|
+
arr.push(`<th scope="col"><abbr title="${this.renderDayName(opts, i)}">${this.renderDayName(opts, i, true)}</abbr></th>`);
|
|
644
|
+
}
|
|
645
|
+
return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
|
|
646
|
+
}
|
|
647
|
+
renderBody(rows) {
|
|
648
|
+
return '<tbody>' + rows.join('') + '</tbody>';
|
|
649
|
+
}
|
|
650
|
+
renderTitle(instance, c, year, month, refYear, randId) {
|
|
651
|
+
const opts = this.options, isMinYear = year === opts.minYear, isMaxYear = year === opts.maxYear;
|
|
652
|
+
let i, j, arr = [], html = '<div id="' +
|
|
653
|
+
randId +
|
|
654
|
+
'" class="datepicker-controls" role="heading" aria-live="assertive">', prev = true, next = true;
|
|
655
|
+
for (i = 0; i < 12; i++) {
|
|
656
|
+
arr.push('<option value="' +
|
|
657
|
+
(year === refYear ? i - c : 12 + i - c) +
|
|
658
|
+
'"' +
|
|
659
|
+
(i === month ? ' selected="selected"' : '') +
|
|
660
|
+
((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth)
|
|
661
|
+
? 'disabled="disabled"'
|
|
662
|
+
: '') +
|
|
663
|
+
'>' +
|
|
664
|
+
opts.i18n.months[i] +
|
|
665
|
+
'</option>');
|
|
666
|
+
}
|
|
667
|
+
const monthHtml = '<select class="datepicker-select orig-select-month" tabindex="-1">' +
|
|
668
|
+
arr.join('') +
|
|
669
|
+
'</select>';
|
|
670
|
+
if (Array.isArray(opts.yearRange)) {
|
|
671
|
+
i = opts.yearRange[0];
|
|
672
|
+
j = opts.yearRange[1] + 1;
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
i = year - opts.yearRange;
|
|
676
|
+
j = 1 + year + opts.yearRange;
|
|
677
|
+
}
|
|
678
|
+
for (arr = []; i < j && i <= opts.maxYear; i++) {
|
|
679
|
+
if (i >= opts.minYear) {
|
|
680
|
+
arr.push(`<option value="${i}" ${i === year ? 'selected="selected"' : ''}>${i}</option>`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (opts.yearRangeReverse)
|
|
684
|
+
arr.reverse();
|
|
685
|
+
const yearHtml = `<select class="datepicker-select orig-select-year" tabindex="-1">${arr.join('')}</select>`;
|
|
686
|
+
const leftArrow = '<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/><path d="M0-.5h24v24H0z" fill="none"/></svg>';
|
|
687
|
+
html += `<button class="month-prev${prev ? '' : ' is-disabled'
|
|
688
|
+
// @todo remove button class and add scss mixin, current implementation temporary for focus states, @see https://github.com/materializecss/materialize/issues/566
|
|
689
|
+
} btn" type="button">${leftArrow}</button>`;
|
|
690
|
+
html += '<div class="selects-container">';
|
|
691
|
+
if (opts.showMonthAfterYear) {
|
|
692
|
+
html += yearHtml + monthHtml;
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
html += monthHtml + yearHtml;
|
|
696
|
+
}
|
|
697
|
+
html += '</div>';
|
|
698
|
+
if (isMinYear && (month === 0 || opts.minMonth >= month)) {
|
|
699
|
+
prev = false;
|
|
700
|
+
}
|
|
701
|
+
if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
|
|
702
|
+
next = false;
|
|
703
|
+
}
|
|
704
|
+
const rightArrow = '<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/><path d="M0-.25h24v24H0z" fill="none"/></svg>';
|
|
705
|
+
html += `<button class="month-next${next ? '' : ' is-disabled'
|
|
706
|
+
// @todo remove button class and add scss mixin, current implementation temporary for focus states, @see https://github.com/materializecss/materialize/issues/566
|
|
707
|
+
} btn" type="button">${rightArrow}</button>`;
|
|
708
|
+
return (html += '</div>');
|
|
709
|
+
}
|
|
710
|
+
// refresh HTML
|
|
711
|
+
draw() {
|
|
712
|
+
const opts = this.options, minYear = opts.minYear, maxYear = opts.maxYear, minMonth = opts.minMonth, maxMonth = opts.maxMonth;
|
|
713
|
+
let html = '';
|
|
714
|
+
if (this._y <= minYear) {
|
|
715
|
+
this._y = minYear;
|
|
716
|
+
if (!isNaN(minMonth) && this._m < minMonth) {
|
|
717
|
+
this._m = minMonth;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
if (this._y >= maxYear) {
|
|
721
|
+
this._y = maxYear;
|
|
722
|
+
if (!isNaN(maxMonth) && this._m > maxMonth) {
|
|
723
|
+
this._m = maxMonth;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
const randId = 'datepicker-title-' +
|
|
727
|
+
Math.random()
|
|
728
|
+
.toString(36)
|
|
729
|
+
.replace(/[^a-z]+/g, '')
|
|
730
|
+
.substr(0, 2);
|
|
731
|
+
for (let c = 0; c < 1; c++) {
|
|
732
|
+
if (!this.options.isDateRange) {
|
|
733
|
+
this._renderDateDisplay(this.date);
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
736
|
+
this._renderDateDisplay(this.date, this.endDate);
|
|
737
|
+
}
|
|
738
|
+
html +=
|
|
739
|
+
this.renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId);
|
|
740
|
+
}
|
|
741
|
+
this.destroySelects();
|
|
742
|
+
this.calendarEl.innerHTML = html;
|
|
743
|
+
// Init Materialize Select
|
|
744
|
+
const yearSelect = this.calendarEl.querySelector('.orig-select-year');
|
|
745
|
+
const monthSelect = this.calendarEl.querySelector('.orig-select-month');
|
|
746
|
+
// @todo fix accessibility @see https://github.com/materializecss/materialize/issues/522
|
|
747
|
+
FormSelect.init(yearSelect, {
|
|
748
|
+
classes: 'select-year',
|
|
749
|
+
dropdownOptions: { container: document.body, constrainWidth: false }
|
|
750
|
+
});
|
|
751
|
+
FormSelect.init(monthSelect, {
|
|
752
|
+
classes: 'select-month',
|
|
753
|
+
dropdownOptions: { container: document.body, constrainWidth: false }
|
|
754
|
+
});
|
|
755
|
+
// Add change handlers for select
|
|
756
|
+
yearSelect.addEventListener('change', this._handleYearChange);
|
|
757
|
+
monthSelect.addEventListener('change', this._handleMonthChange);
|
|
758
|
+
if (typeof this.options.onDraw === 'function') {
|
|
759
|
+
this.options.onDraw.call(this);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
_setupEventHandlers() {
|
|
763
|
+
this.el.addEventListener('click', this._handleInputClick);
|
|
764
|
+
this.el.addEventListener('keydown', this._handleInputKeydown);
|
|
765
|
+
this.el.addEventListener('change', this._handleInputChange);
|
|
766
|
+
this.calendarEl.addEventListener('click', this._handleCalendarClick);
|
|
767
|
+
}
|
|
768
|
+
_setupVariables() {
|
|
769
|
+
const template = document.createElement('template');
|
|
770
|
+
template.innerHTML = Datepicker._template.trim();
|
|
771
|
+
this.containerEl = template.content.firstChild;
|
|
772
|
+
this.calendarEl = this.containerEl.querySelector('.datepicker-calendar');
|
|
773
|
+
this.yearTextEl = this.containerEl.querySelector('.year-text');
|
|
774
|
+
this.dateTextEl = this.containerEl.querySelector('.date-text');
|
|
775
|
+
this.footer = this.containerEl.querySelector('.datepicker-footer');
|
|
776
|
+
this.formats = {
|
|
777
|
+
d: (date) => {
|
|
778
|
+
return date.getDate();
|
|
779
|
+
},
|
|
780
|
+
dd: (date) => {
|
|
781
|
+
const d = date.getDate();
|
|
782
|
+
return (d < 10 ? '0' : '') + d;
|
|
783
|
+
},
|
|
784
|
+
ddd: (date) => {
|
|
785
|
+
return this.options.i18n.weekdaysShort[date.getDay()];
|
|
786
|
+
},
|
|
787
|
+
dddd: (date) => {
|
|
788
|
+
return this.options.i18n.weekdays[date.getDay()];
|
|
789
|
+
},
|
|
790
|
+
m: (date) => {
|
|
791
|
+
return date.getMonth() + 1;
|
|
792
|
+
},
|
|
793
|
+
mm: (date) => {
|
|
794
|
+
const m = date.getMonth() + 1;
|
|
795
|
+
return (m < 10 ? '0' : '') + m;
|
|
796
|
+
},
|
|
797
|
+
mmm: (date) => {
|
|
798
|
+
return this.options.i18n.monthsShort[date.getMonth()];
|
|
799
|
+
},
|
|
800
|
+
mmmm: (date) => {
|
|
801
|
+
return this.options.i18n.months[date.getMonth()];
|
|
802
|
+
},
|
|
803
|
+
yy: (date) => {
|
|
804
|
+
return ('' + date.getFullYear()).slice(2);
|
|
805
|
+
},
|
|
806
|
+
yyyy: (date) => {
|
|
807
|
+
return date.getFullYear();
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
_pickerSetup() {
|
|
812
|
+
if (!this.options.defaultDate) {
|
|
813
|
+
this.options.defaultDate = new Date(Date.parse(this.el.value));
|
|
814
|
+
}
|
|
815
|
+
const defDate = this.options.defaultDate;
|
|
816
|
+
if (Datepicker._isDate(defDate)) {
|
|
817
|
+
if (this.options.setDefaultDate) {
|
|
818
|
+
this.setDate(defDate, true);
|
|
819
|
+
this.setInputValue(this.el, defDate);
|
|
820
|
+
}
|
|
821
|
+
else {
|
|
822
|
+
this.gotoDate(defDate);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
826
|
+
this.gotoDate(new Date());
|
|
827
|
+
}
|
|
828
|
+
if (this.options.isDateRange) {
|
|
829
|
+
this.multiple = true;
|
|
830
|
+
const defEndDate = this.options.defaultEndDate;
|
|
831
|
+
if (Datepicker._isDate(defEndDate)) {
|
|
832
|
+
if (this.options.setDefaultEndDate) {
|
|
833
|
+
this.setDate(defEndDate, true, true);
|
|
834
|
+
this.setInputValue(this.endDateEl, defEndDate);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (this.options.isMultipleSelection) {
|
|
839
|
+
this.multiple = true;
|
|
840
|
+
this.dates = [];
|
|
841
|
+
this.dateEls = [];
|
|
842
|
+
this.dateEls.push(this.el);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
_removeEventHandlers() {
|
|
846
|
+
this.el.removeEventListener('click', this._handleInputClick);
|
|
847
|
+
this.el.removeEventListener('keydown', this._handleInputKeydown);
|
|
848
|
+
this.el.removeEventListener('change', this._handleInputChange);
|
|
849
|
+
this.calendarEl.removeEventListener('click', this._handleCalendarClick);
|
|
850
|
+
if (this.options.isDateRange) {
|
|
851
|
+
this.endDateEl.removeEventListener('click', this._handleInputClick);
|
|
852
|
+
this.endDateEl.removeEventListener('keypress', this._handleInputKeydown);
|
|
853
|
+
this.endDateEl.removeEventListener('change', this._handleInputChange);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
_handleInputClick = (e) => {
|
|
857
|
+
// Prevents default browser datepicker modal rendering
|
|
858
|
+
if (e.type == 'date') {
|
|
859
|
+
e.preventDefault();
|
|
860
|
+
}
|
|
861
|
+
this.setDateFromInput(e.target);
|
|
862
|
+
this.draw();
|
|
863
|
+
this.gotoDate(e.target === this.el ? this.date : this.endDate);
|
|
864
|
+
if (this.displayPlugin)
|
|
865
|
+
this.displayPlugin.show();
|
|
866
|
+
if (this.options.onInputInteraction)
|
|
867
|
+
this.options.onInputInteraction.call(this);
|
|
868
|
+
};
|
|
869
|
+
_handleInputKeydown = (e) => {
|
|
870
|
+
if (Utils.keys.ENTER.includes(e.key)) {
|
|
871
|
+
e.preventDefault();
|
|
872
|
+
this.setDateFromInput(e.target);
|
|
873
|
+
this.draw();
|
|
874
|
+
if (this.displayPlugin)
|
|
875
|
+
this.displayPlugin.show();
|
|
876
|
+
if (this.options.onInputInteraction)
|
|
877
|
+
this.options.onInputInteraction.call(this);
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
_handleCalendarClick = (e) => {
|
|
881
|
+
const target = e.target;
|
|
882
|
+
if (!target.classList.contains('is-disabled')) {
|
|
883
|
+
if (target.classList.contains('datepicker-day-button') &&
|
|
884
|
+
!target.classList.contains('is-empty') &&
|
|
885
|
+
!target.parentElement.classList.contains('is-disabled')) {
|
|
886
|
+
const selectedDate = new Date(e.target.getAttribute('data-year'), e.target.getAttribute('data-month'), e.target.getAttribute('data-day'));
|
|
887
|
+
if (!this.multiple || (this.multiple && this.options.isMultipleSelection)) {
|
|
888
|
+
this.setDate(selectedDate);
|
|
889
|
+
}
|
|
890
|
+
if (this.options.isDateRange) {
|
|
891
|
+
const confirmAfterSelection = Datepicker._isDate(this.date) && this.options.autoSubmit;
|
|
892
|
+
this._handleDateRangeCalendarClick(selectedDate);
|
|
893
|
+
if (confirmAfterSelection) {
|
|
894
|
+
this._confirm();
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (!this.options.isDateRange && this.options.autoSubmit)
|
|
898
|
+
this._confirm();
|
|
899
|
+
}
|
|
900
|
+
else if (target.closest('.month-prev')) {
|
|
901
|
+
this.prevMonth();
|
|
902
|
+
}
|
|
903
|
+
else if (target.closest('.month-next')) {
|
|
904
|
+
this.nextMonth();
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
_handleDateRangeCalendarClick = (date) => {
|
|
909
|
+
if (this.endDate == null || !Datepicker._compareDates(date, this.endDate)) {
|
|
910
|
+
if (Datepicker._isDate(this.date) && Datepicker._comparePastDate(date, this.date)) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
this.setDate(date, true, Datepicker._isDate(this.date));
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
this._clearDates();
|
|
917
|
+
this.draw();
|
|
918
|
+
};
|
|
919
|
+
_handleClearClick = () => {
|
|
920
|
+
this._clearDates();
|
|
921
|
+
this.setInputValues();
|
|
922
|
+
};
|
|
923
|
+
_clearDates = () => {
|
|
924
|
+
this.date = null;
|
|
925
|
+
this.endDate = null;
|
|
926
|
+
this.draw();
|
|
927
|
+
};
|
|
928
|
+
_handleMonthChange = (e) => {
|
|
929
|
+
this.gotoMonth(e.target.value);
|
|
930
|
+
};
|
|
931
|
+
_handleYearChange = (e) => {
|
|
932
|
+
this.gotoYear(e.target.value);
|
|
933
|
+
};
|
|
934
|
+
// change view to a specific month (zero-index, e.g. 0: January)
|
|
935
|
+
gotoMonth(month) {
|
|
936
|
+
if (!isNaN(month)) {
|
|
937
|
+
this.calendars[0].month = parseInt(month, 10);
|
|
938
|
+
this.adjustCalendars();
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
// change view to a specific full year (e.g. "2012")
|
|
942
|
+
gotoYear(year) {
|
|
943
|
+
if (!isNaN(year)) {
|
|
944
|
+
this.calendars[0].year = parseInt(year, 10);
|
|
945
|
+
this.adjustCalendars();
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
_handleInputChange = (e) => {
|
|
949
|
+
let date;
|
|
950
|
+
const el = e.target;
|
|
951
|
+
// Prevent change event from being fired when triggered by the plugin
|
|
952
|
+
if (e['detail']?.firedBy === this)
|
|
953
|
+
return;
|
|
954
|
+
// Prevent change event from being fired if an end date is set without a start date
|
|
955
|
+
if (el == this.endDateEl && !this.date)
|
|
956
|
+
return;
|
|
957
|
+
if (this.options.parse) {
|
|
958
|
+
date = this.options.parse(e.target.value, typeof this.options.format === 'function'
|
|
959
|
+
? this.options.format(new Date(this.el.value))
|
|
960
|
+
: this.options.format);
|
|
961
|
+
}
|
|
962
|
+
else {
|
|
963
|
+
date = new Date(Date.parse(e.target.value));
|
|
964
|
+
}
|
|
965
|
+
if (Datepicker._isDate(date)) {
|
|
966
|
+
this.setDate(date, false, el == this.endDateEl, true);
|
|
967
|
+
if (e.type == 'date') {
|
|
968
|
+
this.setDataDate(e, date);
|
|
969
|
+
this.setInputValues();
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
renderDayName(opts, day, abbr = false) {
|
|
974
|
+
day += opts.firstDay;
|
|
975
|
+
while (day >= 7) {
|
|
976
|
+
day -= 7;
|
|
977
|
+
}
|
|
978
|
+
return abbr ? opts.i18n.weekdaysAbbrev[day] : opts.i18n.weekdays[day];
|
|
979
|
+
}
|
|
980
|
+
createDateInput() {
|
|
981
|
+
const dateInput = this.el.cloneNode(true);
|
|
982
|
+
dateInput.addEventListener('click', this._handleInputClick);
|
|
983
|
+
dateInput.addEventListener('keypress', this._handleInputKeydown);
|
|
984
|
+
dateInput.addEventListener('change', this._handleInputChange);
|
|
985
|
+
this.el.parentElement.appendChild(dateInput);
|
|
986
|
+
return dateInput;
|
|
987
|
+
}
|
|
988
|
+
// Set input value to the selected date and close Datepicker
|
|
989
|
+
_finishSelection = () => {
|
|
990
|
+
this.setInputValues();
|
|
991
|
+
// Commented out because of function deprecations
|
|
992
|
+
// this.close();
|
|
993
|
+
};
|
|
994
|
+
_confirm = () => {
|
|
995
|
+
this._finishSelection();
|
|
996
|
+
if (this.displayPlugin)
|
|
997
|
+
this.displayPlugin.hide();
|
|
998
|
+
if (typeof this.options.onConfirm === 'function')
|
|
999
|
+
this.options.onConfirm.call(this);
|
|
1000
|
+
};
|
|
1001
|
+
_cancel = () => {
|
|
1002
|
+
if (this.displayPlugin)
|
|
1003
|
+
this.displayPlugin.hide();
|
|
1004
|
+
if (typeof this.options.onCancel === 'function')
|
|
1005
|
+
this.options.onCancel.call(this);
|
|
1006
|
+
};
|
|
1007
|
+
// deprecated
|
|
1008
|
+
open() {
|
|
1009
|
+
console.warn('Datepicker.open() is deprecated. Remove this method and wrap in modal yourself.');
|
|
1010
|
+
return this;
|
|
1011
|
+
}
|
|
1012
|
+
close() {
|
|
1013
|
+
console.warn('Datepicker.close() is deprecated. Remove this method and wrap in modal yourself.');
|
|
1014
|
+
return this;
|
|
1015
|
+
}
|
|
1016
|
+
static {
|
|
1017
|
+
Datepicker._template = `
|
|
1018
|
+
<div class="datepicker-container">
|
|
1019
|
+
<div class="datepicker-date-display">
|
|
1020
|
+
<span class="year-text"></span>
|
|
1021
|
+
<span class="date-text"></span>
|
|
1022
|
+
</div>
|
|
1023
|
+
<div class="datepicker-calendar-container">
|
|
1024
|
+
<div class="datepicker-calendar"></div>
|
|
1025
|
+
<div class="datepicker-footer">
|
|
1026
|
+
<!--<button class="btn-flat datepicker-clear waves-effect" style="visibility: hidden;" type="button"></button>
|
|
1027
|
+
<div class="confirmation-btns">
|
|
1028
|
+
<button class="btn-flat datepicker-cancel waves-effect" type="button"></button>
|
|
1029
|
+
<button class="btn-flat datepicker-done waves-effect" type="button"></button>
|
|
1030
|
+
</div>-->
|
|
1031
|
+
</div>
|
|
1032
|
+
</div>
|
|
1033
|
+
</div>`;
|
|
1034
|
+
}
|
|
1035
|
+
}
|