@materializecss/materialize 2.0.1-alpha → 2.0.3-alpha

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