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.
Files changed (47) hide show
  1. package/components/air-datepicker/air-datepicker.js +152 -0
  2. package/components/alert/alert.js +54 -0
  3. package/components/button/buttons.js +220 -0
  4. package/components/card/cards.js +149 -0
  5. package/components/carousel/carousel.js +574 -0
  6. package/components/carousel/slider.js +340 -0
  7. package/components/chip/chips.js +341 -0
  8. package/components/collapsible/collapsible.js +156 -0
  9. package/components/color-input/color-input.js +166 -0
  10. package/components/datepicker/datepicker.js +1035 -0
  11. package/components/dialog/materialbox.js +377 -0
  12. package/components/dialog/modal.js +72 -0
  13. package/components/dropdown/dropdown.js +505 -0
  14. package/components/file-input/file-input.js +169 -0
  15. package/components/kanban/_kanban.scss +69 -0
  16. package/components/kanban/kanban.js +168 -0
  17. package/components/kanban/kanban.ts +57 -8
  18. package/components/loading/_loading.scss +68 -0
  19. package/components/loading/loading.ts +104 -0
  20. package/components/loading/loadingSpec.js +102 -0
  21. package/components/navigation-drawer/sidenav.js +454 -0
  22. package/components/number-input/number-input.js +68 -0
  23. package/components/password-input/password-input.js +49 -0
  24. package/components/popup/_popup.scss +106 -0
  25. package/components/popup/popup.ts +113 -0
  26. package/components/popup/popupSpec.js +140 -0
  27. package/components/search/autocomplete.js +470 -0
  28. package/components/slider/range.js +169 -0
  29. package/components/snackbar/toasts.js +244 -0
  30. package/components/tabs/tabs.js +289 -0
  31. package/components/textfield/forms.js +172 -0
  32. package/components/textfield/select.js +385 -0
  33. package/components/timepicker/timepicker.js +698 -0
  34. package/components/tom-select/tom-select-field.js +130 -0
  35. package/components/toolbar/toolbar.js +134 -0
  36. package/components/tooltip/tooltip.js +270 -0
  37. package/dist/css/materialize.colors.min.css +1 -1
  38. package/dist/css/materialize.css +322 -1
  39. package/dist/css/materialize.min.css +2 -2
  40. package/dist/css/materialize.min.css.map +1 -1
  41. package/dist/js/materialize.cjs.js +258 -42
  42. package/dist/js/materialize.d.ts +50 -3
  43. package/dist/js/materialize.js +258 -42
  44. package/dist/js/materialize.min.js +2 -2
  45. package/dist/js/materialize.mjs +257 -43
  46. package/package.json +6 -1
  47. 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
+ }