activeadmin_materialize_theme 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +26 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/config/activeadmin_materialize_theme_manifest.js +1 -0
  6. data/app/assets/javascripts/activeadmin_materialize_theme.js +65 -0
  7. data/app/assets/javascripts/materialize/anime.min.js +34 -0
  8. data/app/assets/javascripts/materialize/autocomplete.js +450 -0
  9. data/app/assets/javascripts/materialize/bin/materialize.js +12374 -0
  10. data/app/assets/javascripts/materialize/bin/materialize.min.js +6 -0
  11. data/app/assets/javascripts/materialize/buttons.js +354 -0
  12. data/app/assets/javascripts/materialize/cards.js +40 -0
  13. data/app/assets/javascripts/materialize/carousel.js +717 -0
  14. data/app/assets/javascripts/materialize/cash.js +960 -0
  15. data/app/assets/javascripts/materialize/characterCounter.js +136 -0
  16. data/app/assets/javascripts/materialize/chips.js +481 -0
  17. data/app/assets/javascripts/materialize/collapsible.js +275 -0
  18. data/app/assets/javascripts/materialize/component.js +44 -0
  19. data/app/assets/javascripts/materialize/datepicker.js +975 -0
  20. data/app/assets/javascripts/materialize/dropdown.js +617 -0
  21. data/app/assets/javascripts/materialize/forms.js +275 -0
  22. data/app/assets/javascripts/materialize/global.js +427 -0
  23. data/app/assets/javascripts/materialize/materialbox.js +453 -0
  24. data/app/assets/javascripts/materialize/modal.js +382 -0
  25. data/app/assets/javascripts/materialize/parallax.js +138 -0
  26. data/app/assets/javascripts/materialize/pushpin.js +145 -0
  27. data/app/assets/javascripts/materialize/range.js +263 -0
  28. data/app/assets/javascripts/materialize/scrollspy.js +295 -0
  29. data/app/assets/javascripts/materialize/select.js +432 -0
  30. data/app/assets/javascripts/materialize/sidenav.js +580 -0
  31. data/app/assets/javascripts/materialize/slider.js +359 -0
  32. data/app/assets/javascripts/materialize/tabs.js +402 -0
  33. data/app/assets/javascripts/materialize/tapTarget.js +314 -0
  34. data/app/assets/javascripts/materialize/timepicker.js +647 -0
  35. data/app/assets/javascripts/materialize/toasts.js +310 -0
  36. data/app/assets/javascripts/materialize/tooltip.js +303 -0
  37. data/app/assets/javascripts/materialize/waves.js +335 -0
  38. data/app/assets/stylesheets/activeadmin_materialize_theme/base.scss +107 -0
  39. data/app/assets/stylesheets/activeadmin_materialize_theme/components/footer.scss +18 -0
  40. data/app/assets/stylesheets/activeadmin_materialize_theme/components/form.scss +140 -0
  41. data/app/assets/stylesheets/activeadmin_materialize_theme/components/header.scss +61 -0
  42. data/app/assets/stylesheets/activeadmin_materialize_theme/components/layout_index.scss +83 -0
  43. data/app/assets/stylesheets/activeadmin_materialize_theme/components/layout_show.scss +56 -0
  44. data/app/assets/stylesheets/activeadmin_materialize_theme/components/sidebar.scss +37 -0
  45. data/app/assets/stylesheets/activeadmin_materialize_theme/components/title_bar.scss +43 -0
  46. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/LICENSE +21 -0
  47. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/README.md +91 -0
  48. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_badges.scss +55 -0
  49. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_buttons.scss +322 -0
  50. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_cards.scss +195 -0
  51. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_carousel.scss +90 -0
  52. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_chips.scss +90 -0
  53. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_collapsible.scss +91 -0
  54. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_color-classes.scss +32 -0
  55. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_color-variables.scss +370 -0
  56. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_datepicker.scss +191 -0
  57. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_dropdown.scss +85 -0
  58. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_global.scss +769 -0
  59. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_grid.scss +156 -0
  60. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_icons-material-design.scss +5 -0
  61. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_materialbox.scss +43 -0
  62. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_modal.scss +94 -0
  63. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_navbar.scss +208 -0
  64. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_normalize.scss +447 -0
  65. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_preloader.scss +334 -0
  66. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_pulse.scss +34 -0
  67. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_sidenav.scss +216 -0
  68. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_slider.scss +92 -0
  69. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_table_of_contents.scss +33 -0
  70. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_tabs.scss +99 -0
  71. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_tapTarget.scss +103 -0
  72. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_timepicker.scss +183 -0
  73. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_toast.scss +58 -0
  74. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_tooltip.scss +32 -0
  75. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_transitions.scss +13 -0
  76. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_typography.scss +60 -0
  77. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_variables.scss +349 -0
  78. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_waves.scss +114 -0
  79. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_checkboxes.scss +200 -0
  80. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_file-input.scss +44 -0
  81. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_forms.scss +22 -0
  82. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_input-fields.scss +354 -0
  83. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_radio-buttons.scss +115 -0
  84. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_range.scss +161 -0
  85. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_select.scss +180 -0
  86. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_switches.scss +89 -0
  87. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/materialize.scss +41 -0
  88. data/app/assets/stylesheets/activeadmin_materialize_theme/normalize.css +349 -0
  89. data/app/assets/stylesheets/activeadmin_materialize_theme/theme.scss +13 -0
  90. data/app/assets/stylesheets/activeadmin_materialize_theme/variables.scss +14 -0
  91. data/lib/activeadmin_materialize_theme.rb +6 -0
  92. data/lib/activeadmin_materialize_theme/engine.rb +7 -0
  93. data/lib/activeadmin_materialize_theme/version.rb +5 -0
  94. metadata +149 -0
@@ -0,0 +1,275 @@
1
+ (function($, anim) {
2
+ 'use strict';
3
+
4
+ let _defaults = {
5
+ accordion: true,
6
+ onOpenStart: undefined,
7
+ onOpenEnd: undefined,
8
+ onCloseStart: undefined,
9
+ onCloseEnd: undefined,
10
+ inDuration: 300,
11
+ outDuration: 300
12
+ };
13
+
14
+ /**
15
+ * @class
16
+ *
17
+ */
18
+ class Collapsible extends Component {
19
+ /**
20
+ * Construct Collapsible instance
21
+ * @constructor
22
+ * @param {Element} el
23
+ * @param {Object} options
24
+ */
25
+ constructor(el, options) {
26
+ super(Collapsible, el, options);
27
+
28
+ this.el.M_Collapsible = this;
29
+
30
+ /**
31
+ * Options for the collapsible
32
+ * @member Collapsible#options
33
+ * @prop {Boolean} [accordion=false] - Type of the collapsible
34
+ * @prop {Function} onOpenStart - Callback function called before collapsible is opened
35
+ * @prop {Function} onOpenEnd - Callback function called after collapsible is opened
36
+ * @prop {Function} onCloseStart - Callback function called before collapsible is closed
37
+ * @prop {Function} onCloseEnd - Callback function called after collapsible is closed
38
+ * @prop {Number} inDuration - Transition in duration in milliseconds.
39
+ * @prop {Number} outDuration - Transition duration in milliseconds.
40
+ */
41
+ this.options = $.extend({}, Collapsible.defaults, options);
42
+
43
+ // Setup tab indices
44
+ this.$headers = this.$el.children('li').children('.collapsible-header');
45
+ this.$headers.attr('tabindex', 0);
46
+
47
+ this._setupEventHandlers();
48
+
49
+ // Open first active
50
+ let $activeBodies = this.$el.children('li.active').children('.collapsible-body');
51
+ if (this.options.accordion) {
52
+ // Handle Accordion
53
+ $activeBodies.first().css('display', 'block');
54
+ } else {
55
+ // Handle Expandables
56
+ $activeBodies.css('display', 'block');
57
+ }
58
+ }
59
+
60
+ static get defaults() {
61
+ return _defaults;
62
+ }
63
+
64
+ static init(els, options) {
65
+ return super.init(this, els, options);
66
+ }
67
+
68
+ /**
69
+ * Get Instance
70
+ */
71
+ static getInstance(el) {
72
+ let domElem = !!el.jquery ? el[0] : el;
73
+ return domElem.M_Collapsible;
74
+ }
75
+
76
+ /**
77
+ * Teardown component
78
+ */
79
+ destroy() {
80
+ this._removeEventHandlers();
81
+ this.el.M_Collapsible = undefined;
82
+ }
83
+
84
+ /**
85
+ * Setup Event Handlers
86
+ */
87
+ _setupEventHandlers() {
88
+ this._handleCollapsibleClickBound = this._handleCollapsibleClick.bind(this);
89
+ this._handleCollapsibleKeydownBound = this._handleCollapsibleKeydown.bind(this);
90
+ this.el.addEventListener('click', this._handleCollapsibleClickBound);
91
+ this.$headers.each((header) => {
92
+ header.addEventListener('keydown', this._handleCollapsibleKeydownBound);
93
+ });
94
+ }
95
+
96
+ /**
97
+ * Remove Event Handlers
98
+ */
99
+ _removeEventHandlers() {
100
+ this.el.removeEventListener('click', this._handleCollapsibleClickBound);
101
+ this.$headers.each((header) => {
102
+ header.removeEventListener('keydown', this._handleCollapsibleKeydownBound);
103
+ });
104
+ }
105
+
106
+ /**
107
+ * Handle Collapsible Click
108
+ * @param {Event} e
109
+ */
110
+ _handleCollapsibleClick(e) {
111
+ let $header = $(e.target).closest('.collapsible-header');
112
+ if (e.target && $header.length) {
113
+ let $collapsible = $header.closest('.collapsible');
114
+ if ($collapsible[0] === this.el) {
115
+ let $collapsibleLi = $header.closest('li');
116
+ let $collapsibleLis = $collapsible.children('li');
117
+ let isActive = $collapsibleLi[0].classList.contains('active');
118
+ let index = $collapsibleLis.index($collapsibleLi);
119
+
120
+ if (isActive) {
121
+ this.close(index);
122
+ } else {
123
+ this.open(index);
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Handle Collapsible Keydown
131
+ * @param {Event} e
132
+ */
133
+ _handleCollapsibleKeydown(e) {
134
+ if (e.keyCode === 13) {
135
+ this._handleCollapsibleClickBound(e);
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Animate in collapsible slide
141
+ * @param {Number} index - 0th index of slide
142
+ */
143
+ _animateIn(index) {
144
+ let $collapsibleLi = this.$el.children('li').eq(index);
145
+ if ($collapsibleLi.length) {
146
+ let $body = $collapsibleLi.children('.collapsible-body');
147
+
148
+ anim.remove($body[0]);
149
+ $body.css({
150
+ display: 'block',
151
+ overflow: 'hidden',
152
+ height: 0,
153
+ paddingTop: '',
154
+ paddingBottom: ''
155
+ });
156
+
157
+ let pTop = $body.css('padding-top');
158
+ let pBottom = $body.css('padding-bottom');
159
+ let finalHeight = $body[0].scrollHeight;
160
+ $body.css({
161
+ paddingTop: 0,
162
+ paddingBottom: 0
163
+ });
164
+
165
+ anim({
166
+ targets: $body[0],
167
+ height: finalHeight,
168
+ paddingTop: pTop,
169
+ paddingBottom: pBottom,
170
+ duration: this.options.inDuration,
171
+ easing: 'easeInOutCubic',
172
+ complete: (anim) => {
173
+ $body.css({
174
+ overflow: '',
175
+ paddingTop: '',
176
+ paddingBottom: '',
177
+ height: ''
178
+ });
179
+
180
+ // onOpenEnd callback
181
+ if (typeof this.options.onOpenEnd === 'function') {
182
+ this.options.onOpenEnd.call(this, $collapsibleLi[0]);
183
+ }
184
+ }
185
+ });
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Animate out collapsible slide
191
+ * @param {Number} index - 0th index of slide to open
192
+ */
193
+ _animateOut(index) {
194
+ let $collapsibleLi = this.$el.children('li').eq(index);
195
+ if ($collapsibleLi.length) {
196
+ let $body = $collapsibleLi.children('.collapsible-body');
197
+ anim.remove($body[0]);
198
+ $body.css('overflow', 'hidden');
199
+ anim({
200
+ targets: $body[0],
201
+ height: 0,
202
+ paddingTop: 0,
203
+ paddingBottom: 0,
204
+ duration: this.options.outDuration,
205
+ easing: 'easeInOutCubic',
206
+ complete: () => {
207
+ $body.css({
208
+ height: '',
209
+ overflow: '',
210
+ padding: '',
211
+ display: ''
212
+ });
213
+
214
+ // onCloseEnd callback
215
+ if (typeof this.options.onCloseEnd === 'function') {
216
+ this.options.onCloseEnd.call(this, $collapsibleLi[0]);
217
+ }
218
+ }
219
+ });
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Open Collapsible
225
+ * @param {Number} index - 0th index of slide
226
+ */
227
+ open(index) {
228
+ let $collapsibleLi = this.$el.children('li').eq(index);
229
+ if ($collapsibleLi.length && !$collapsibleLi[0].classList.contains('active')) {
230
+ // onOpenStart callback
231
+ if (typeof this.options.onOpenStart === 'function') {
232
+ this.options.onOpenStart.call(this, $collapsibleLi[0]);
233
+ }
234
+
235
+ // Handle accordion behavior
236
+ if (this.options.accordion) {
237
+ let $collapsibleLis = this.$el.children('li');
238
+ let $activeLis = this.$el.children('li.active');
239
+ $activeLis.each((el) => {
240
+ let index = $collapsibleLis.index($(el));
241
+ this.close(index);
242
+ });
243
+ }
244
+
245
+ // Animate in
246
+ $collapsibleLi[0].classList.add('active');
247
+ this._animateIn(index);
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Close Collapsible
253
+ * @param {Number} index - 0th index of slide
254
+ */
255
+ close(index) {
256
+ let $collapsibleLi = this.$el.children('li').eq(index);
257
+ if ($collapsibleLi.length && $collapsibleLi[0].classList.contains('active')) {
258
+ // onCloseStart callback
259
+ if (typeof this.options.onCloseStart === 'function') {
260
+ this.options.onCloseStart.call(this, $collapsibleLi[0]);
261
+ }
262
+
263
+ // Animate out
264
+ $collapsibleLi[0].classList.remove('active');
265
+ this._animateOut(index);
266
+ }
267
+ }
268
+ }
269
+
270
+ M.Collapsible = Collapsible;
271
+
272
+ if (M.jQueryLoaded) {
273
+ M.initializeJqueryWrapper(Collapsible, 'collapsible', 'M_Collapsible');
274
+ }
275
+ })(cash, M.anime);
@@ -0,0 +1,44 @@
1
+ class Component {
2
+ /**
3
+ * Generic constructor for all components
4
+ * @constructor
5
+ * @param {Element} el
6
+ * @param {Object} options
7
+ */
8
+ constructor(classDef, el, options) {
9
+ // Display error if el is valid HTML Element
10
+ if (!(el instanceof Element)) {
11
+ console.error(Error(el + ' is not an HTML Element'));
12
+ }
13
+
14
+ // If exists, destroy and reinitialize in child
15
+ let ins = classDef.getInstance(el);
16
+ if (!!ins) {
17
+ ins.destroy();
18
+ }
19
+
20
+ this.el = el;
21
+ this.$el = cash(el);
22
+ }
23
+
24
+ /**
25
+ * Initializes components
26
+ * @param {class} classDef
27
+ * @param {Element | NodeList | jQuery} els
28
+ * @param {Object} options
29
+ */
30
+ static init(classDef, els, options) {
31
+ let instances = null;
32
+ if (els instanceof Element) {
33
+ instances = new classDef(els, options);
34
+ } else if (!!els && (els.jquery || els.cash || els instanceof NodeList)) {
35
+ let instancesArr = [];
36
+ for (let i = 0; i < els.length; i++) {
37
+ instancesArr.push(new classDef(els[i], options));
38
+ }
39
+ instances = instancesArr;
40
+ }
41
+
42
+ return instances;
43
+ }
44
+ }
@@ -0,0 +1,975 @@
1
+ (function($) {
2
+ 'use strict';
3
+
4
+ let _defaults = {
5
+ // Close when date is selected
6
+ autoClose: false,
7
+
8
+ // the default output format for the input field value
9
+ format: 'mmm dd, yyyy',
10
+
11
+ // Used to create date object from current input string
12
+ parse: null,
13
+
14
+ // The initial date to view when first opened
15
+ defaultDate: null,
16
+
17
+ // Make the `defaultDate` the initial selected value
18
+ setDefaultDate: false,
19
+
20
+ disableWeekends: false,
21
+
22
+ disableDayFn: null,
23
+
24
+ // First day of week (0: Sunday, 1: Monday etc)
25
+ firstDay: 0,
26
+
27
+ // The earliest date that can be selected
28
+ minDate: null,
29
+ // Thelatest date that can be selected
30
+ maxDate: null,
31
+
32
+ // Number of years either side, or array of upper/lower range
33
+ yearRange: 10,
34
+
35
+ // used internally (don't config outside)
36
+ minYear: 0,
37
+ maxYear: 9999,
38
+ minMonth: undefined,
39
+ maxMonth: undefined,
40
+
41
+ startRange: null,
42
+ endRange: null,
43
+
44
+ isRTL: false,
45
+
46
+ // Render the month after year in the calendar title
47
+ showMonthAfterYear: false,
48
+
49
+ // Render days of the calendar grid that fall in the next or previous month
50
+ showDaysInNextAndPreviousMonths: false,
51
+
52
+ // Specify a DOM element to render the calendar in
53
+ container: null,
54
+
55
+ // Show clear button
56
+ showClearBtn: false,
57
+
58
+ // internationalization
59
+ i18n: {
60
+ cancel: 'Cancel',
61
+ clear: 'Clear',
62
+ done: 'Ok',
63
+ previousMonth: '‹',
64
+ nextMonth: '›',
65
+ months: [
66
+ 'January',
67
+ 'February',
68
+ 'March',
69
+ 'April',
70
+ 'May',
71
+ 'June',
72
+ 'July',
73
+ 'August',
74
+ 'September',
75
+ 'October',
76
+ 'November',
77
+ 'December'
78
+ ],
79
+ monthsShort: [
80
+ 'Jan',
81
+ 'Feb',
82
+ 'Mar',
83
+ 'Apr',
84
+ 'May',
85
+ 'Jun',
86
+ 'Jul',
87
+ 'Aug',
88
+ 'Sep',
89
+ 'Oct',
90
+ 'Nov',
91
+ 'Dec'
92
+ ],
93
+ weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
94
+ weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
95
+ weekdaysAbbrev: ['S', 'M', 'T', 'W', 'T', 'F', 'S']
96
+ },
97
+
98
+ // events array
99
+ events: [],
100
+
101
+ // callback function
102
+ onSelect: null,
103
+ onOpen: null,
104
+ onClose: null,
105
+ onDraw: null
106
+ };
107
+
108
+ /**
109
+ * @class
110
+ *
111
+ */
112
+ class Datepicker extends Component {
113
+ /**
114
+ * Construct Datepicker instance and set up overlay
115
+ * @constructor
116
+ * @param {Element} el
117
+ * @param {Object} options
118
+ */
119
+ constructor(el, options) {
120
+ super(Datepicker, el, options);
121
+
122
+ this.el.M_Datepicker = this;
123
+
124
+ this.options = $.extend({}, Datepicker.defaults, options);
125
+
126
+ // make sure i18n defaults are not lost when only few i18n option properties are passed
127
+ if (!!options && options.hasOwnProperty('i18n') && typeof options.i18n === 'object') {
128
+ this.options.i18n = $.extend({}, Datepicker.defaults.i18n, options.i18n);
129
+ }
130
+
131
+ // Remove time component from minDate and maxDate options
132
+ if (this.options.minDate) this.options.minDate.setHours(0, 0, 0, 0);
133
+ if (this.options.maxDate) this.options.maxDate.setHours(0, 0, 0, 0);
134
+
135
+ this.id = M.guid();
136
+
137
+ this._setupVariables();
138
+ this._insertHTMLIntoDOM();
139
+ this._setupModal();
140
+
141
+ this._setupEventHandlers();
142
+
143
+ if (!this.options.defaultDate) {
144
+ this.options.defaultDate = new Date(Date.parse(this.el.value));
145
+ }
146
+
147
+ let defDate = this.options.defaultDate;
148
+ if (Datepicker._isDate(defDate)) {
149
+ if (this.options.setDefaultDate) {
150
+ this.setDate(defDate, true);
151
+ this.setInputValue();
152
+ } else {
153
+ this.gotoDate(defDate);
154
+ }
155
+ } else {
156
+ this.gotoDate(new Date());
157
+ }
158
+
159
+ /**
160
+ * Describes open/close state of datepicker
161
+ * @type {Boolean}
162
+ */
163
+ this.isOpen = false;
164
+ }
165
+
166
+ static get defaults() {
167
+ return _defaults;
168
+ }
169
+
170
+ static init(els, options) {
171
+ return super.init(this, els, options);
172
+ }
173
+
174
+ static _isDate(obj) {
175
+ return /Date/.test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
176
+ }
177
+
178
+ static _isWeekend(date) {
179
+ let day = date.getDay();
180
+ return day === 0 || day === 6;
181
+ }
182
+
183
+ static _setToStartOfDay(date) {
184
+ if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0);
185
+ }
186
+
187
+ static _getDaysInMonth(year, month) {
188
+ return [31, Datepicker._isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][
189
+ month
190
+ ];
191
+ }
192
+
193
+ static _isLeapYear(year) {
194
+ // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
195
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
196
+ }
197
+
198
+ static _compareDates(a, b) {
199
+ // weak date comparison (use setToStartOfDay(date) to ensure correct result)
200
+ return a.getTime() === b.getTime();
201
+ }
202
+
203
+ static _setToStartOfDay(date) {
204
+ if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0);
205
+ }
206
+
207
+ /**
208
+ * Get Instance
209
+ */
210
+ static getInstance(el) {
211
+ let domElem = !!el.jquery ? el[0] : el;
212
+ return domElem.M_Datepicker;
213
+ }
214
+
215
+ /**
216
+ * Teardown component
217
+ */
218
+ destroy() {
219
+ this._removeEventHandlers();
220
+ this.modal.destroy();
221
+ $(this.modalEl).remove();
222
+ this.destroySelects();
223
+ this.el.M_Datepicker = undefined;
224
+ }
225
+
226
+ destroySelects() {
227
+ let oldYearSelect = this.calendarEl.querySelector('.orig-select-year');
228
+ if (oldYearSelect) {
229
+ M.FormSelect.getInstance(oldYearSelect).destroy();
230
+ }
231
+ let oldMonthSelect = this.calendarEl.querySelector('.orig-select-month');
232
+ if (oldMonthSelect) {
233
+ M.FormSelect.getInstance(oldMonthSelect).destroy();
234
+ }
235
+ }
236
+
237
+ _insertHTMLIntoDOM() {
238
+ if (this.options.showClearBtn) {
239
+ $(this.clearBtn).css({ visibility: '' });
240
+ this.clearBtn.innerHTML = this.options.i18n.clear;
241
+ }
242
+
243
+ this.doneBtn.innerHTML = this.options.i18n.done;
244
+ this.cancelBtn.innerHTML = this.options.i18n.cancel;
245
+
246
+ if (this.options.container) {
247
+ this.$modalEl.appendTo(this.options.container);
248
+ } else {
249
+ this.$modalEl.insertBefore(this.el);
250
+ }
251
+ }
252
+
253
+ _setupModal() {
254
+ this.modalEl.id = 'modal-' + this.id;
255
+ this.modal = M.Modal.init(this.modalEl, {
256
+ onCloseEnd: () => {
257
+ this.isOpen = false;
258
+ }
259
+ });
260
+ }
261
+
262
+ toString(format) {
263
+ format = format || this.options.format;
264
+ if (!Datepicker._isDate(this.date)) {
265
+ return '';
266
+ }
267
+
268
+ let formatArray = format.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g);
269
+ let formattedDate = formatArray
270
+ .map((label) => {
271
+ if (this.formats[label]) {
272
+ return this.formats[label]();
273
+ }
274
+
275
+ return label;
276
+ })
277
+ .join('');
278
+ return formattedDate;
279
+ }
280
+
281
+ setDate(date, preventOnSelect) {
282
+ if (!date) {
283
+ this.date = null;
284
+ this._renderDateDisplay();
285
+ return this.draw();
286
+ }
287
+ if (typeof date === 'string') {
288
+ date = new Date(Date.parse(date));
289
+ }
290
+ if (!Datepicker._isDate(date)) {
291
+ return;
292
+ }
293
+
294
+ let min = this.options.minDate,
295
+ max = this.options.maxDate;
296
+
297
+ if (Datepicker._isDate(min) && date < min) {
298
+ date = min;
299
+ } else if (Datepicker._isDate(max) && date > max) {
300
+ date = max;
301
+ }
302
+
303
+ this.date = new Date(date.getTime());
304
+
305
+ this._renderDateDisplay();
306
+
307
+ Datepicker._setToStartOfDay(this.date);
308
+ this.gotoDate(this.date);
309
+
310
+ if (!preventOnSelect && typeof this.options.onSelect === 'function') {
311
+ this.options.onSelect.call(this, this.date);
312
+ }
313
+ }
314
+
315
+ setInputValue() {
316
+ this.el.value = this.toString();
317
+ this.$el.trigger('change', { firedBy: this });
318
+ }
319
+
320
+ _renderDateDisplay() {
321
+ let displayDate = Datepicker._isDate(this.date) ? this.date : new Date();
322
+ let i18n = this.options.i18n;
323
+ let day = i18n.weekdaysShort[displayDate.getDay()];
324
+ let month = i18n.monthsShort[displayDate.getMonth()];
325
+ let date = displayDate.getDate();
326
+ this.yearTextEl.innerHTML = displayDate.getFullYear();
327
+ this.dateTextEl.innerHTML = `${day}, ${month} ${date}`;
328
+ }
329
+
330
+ /**
331
+ * change view to a specific date
332
+ */
333
+ gotoDate(date) {
334
+ let newCalendar = true;
335
+
336
+ if (!Datepicker._isDate(date)) {
337
+ return;
338
+ }
339
+
340
+ if (this.calendars) {
341
+ let firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1),
342
+ lastVisibleDate = new Date(
343
+ this.calendars[this.calendars.length - 1].year,
344
+ this.calendars[this.calendars.length - 1].month,
345
+ 1
346
+ ),
347
+ visibleDate = date.getTime();
348
+ // get the end of the month
349
+ lastVisibleDate.setMonth(lastVisibleDate.getMonth() + 1);
350
+ lastVisibleDate.setDate(lastVisibleDate.getDate() - 1);
351
+ newCalendar =
352
+ visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate;
353
+ }
354
+
355
+ if (newCalendar) {
356
+ this.calendars = [
357
+ {
358
+ month: date.getMonth(),
359
+ year: date.getFullYear()
360
+ }
361
+ ];
362
+ }
363
+
364
+ this.adjustCalendars();
365
+ }
366
+
367
+ adjustCalendars() {
368
+ this.calendars[0] = this.adjustCalendar(this.calendars[0]);
369
+ this.draw();
370
+ }
371
+
372
+ adjustCalendar(calendar) {
373
+ if (calendar.month < 0) {
374
+ calendar.year -= Math.ceil(Math.abs(calendar.month) / 12);
375
+ calendar.month += 12;
376
+ }
377
+ if (calendar.month > 11) {
378
+ calendar.year += Math.floor(Math.abs(calendar.month) / 12);
379
+ calendar.month -= 12;
380
+ }
381
+ return calendar;
382
+ }
383
+
384
+ nextMonth() {
385
+ this.calendars[0].month++;
386
+ this.adjustCalendars();
387
+ }
388
+
389
+ prevMonth() {
390
+ this.calendars[0].month--;
391
+ this.adjustCalendars();
392
+ }
393
+
394
+ render(year, month, randId) {
395
+ let opts = this.options,
396
+ now = new Date(),
397
+ days = Datepicker._getDaysInMonth(year, month),
398
+ before = new Date(year, month, 1).getDay(),
399
+ data = [],
400
+ row = [];
401
+ Datepicker._setToStartOfDay(now);
402
+ if (opts.firstDay > 0) {
403
+ before -= opts.firstDay;
404
+ if (before < 0) {
405
+ before += 7;
406
+ }
407
+ }
408
+ let previousMonth = month === 0 ? 11 : month - 1,
409
+ nextMonth = month === 11 ? 0 : month + 1,
410
+ yearOfPreviousMonth = month === 0 ? year - 1 : year,
411
+ yearOfNextMonth = month === 11 ? year + 1 : year,
412
+ daysInPreviousMonth = Datepicker._getDaysInMonth(yearOfPreviousMonth, previousMonth);
413
+ let cells = days + before,
414
+ after = cells;
415
+ while (after > 7) {
416
+ after -= 7;
417
+ }
418
+ cells += 7 - after;
419
+ let isWeekSelected = false;
420
+ for (let i = 0, r = 0; i < cells; i++) {
421
+ let day = new Date(year, month, 1 + (i - before)),
422
+ isSelected = Datepicker._isDate(this.date)
423
+ ? Datepicker._compareDates(day, this.date)
424
+ : false,
425
+ isToday = Datepicker._compareDates(day, now),
426
+ hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false,
427
+ isEmpty = i < before || i >= days + before,
428
+ dayNumber = 1 + (i - before),
429
+ monthNumber = month,
430
+ yearNumber = year,
431
+ isStartRange = opts.startRange && Datepicker._compareDates(opts.startRange, day),
432
+ isEndRange = opts.endRange && Datepicker._compareDates(opts.endRange, day),
433
+ isInRange =
434
+ opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange,
435
+ isDisabled =
436
+ (opts.minDate && day < opts.minDate) ||
437
+ (opts.maxDate && day > opts.maxDate) ||
438
+ (opts.disableWeekends && Datepicker._isWeekend(day)) ||
439
+ (opts.disableDayFn && opts.disableDayFn(day));
440
+
441
+ if (isEmpty) {
442
+ if (i < before) {
443
+ dayNumber = daysInPreviousMonth + dayNumber;
444
+ monthNumber = previousMonth;
445
+ yearNumber = yearOfPreviousMonth;
446
+ } else {
447
+ dayNumber = dayNumber - days;
448
+ monthNumber = nextMonth;
449
+ yearNumber = yearOfNextMonth;
450
+ }
451
+ }
452
+
453
+ let dayConfig = {
454
+ day: dayNumber,
455
+ month: monthNumber,
456
+ year: yearNumber,
457
+ hasEvent: hasEvent,
458
+ isSelected: isSelected,
459
+ isToday: isToday,
460
+ isDisabled: isDisabled,
461
+ isEmpty: isEmpty,
462
+ isStartRange: isStartRange,
463
+ isEndRange: isEndRange,
464
+ isInRange: isInRange,
465
+ showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths
466
+ };
467
+
468
+ row.push(this.renderDay(dayConfig));
469
+
470
+ if (++r === 7) {
471
+ data.push(this.renderRow(row, opts.isRTL, isWeekSelected));
472
+ row = [];
473
+ r = 0;
474
+ isWeekSelected = false;
475
+ }
476
+ }
477
+ return this.renderTable(opts, data, randId);
478
+ }
479
+
480
+ renderDay(opts) {
481
+ let arr = [];
482
+ let ariaSelected = 'false';
483
+ if (opts.isEmpty) {
484
+ if (opts.showDaysInNextAndPreviousMonths) {
485
+ arr.push('is-outside-current-month');
486
+ arr.push('is-selection-disabled');
487
+ } else {
488
+ return '<td class="is-empty"></td>';
489
+ }
490
+ }
491
+ if (opts.isDisabled) {
492
+ arr.push('is-disabled');
493
+ }
494
+
495
+ if (opts.isToday) {
496
+ arr.push('is-today');
497
+ }
498
+ if (opts.isSelected) {
499
+ arr.push('is-selected');
500
+ ariaSelected = 'true';
501
+ }
502
+ if (opts.hasEvent) {
503
+ arr.push('has-event');
504
+ }
505
+ if (opts.isInRange) {
506
+ arr.push('is-inrange');
507
+ }
508
+ if (opts.isStartRange) {
509
+ arr.push('is-startrange');
510
+ }
511
+ if (opts.isEndRange) {
512
+ arr.push('is-endrange');
513
+ }
514
+ return (
515
+ `<td data-day="${opts.day}" class="${arr.join(' ')}" aria-selected="${ariaSelected}">` +
516
+ `<button class="datepicker-day-button" type="button" data-year="${opts.year}" data-month="${
517
+ opts.month
518
+ }" data-day="${opts.day}">${opts.day}</button>` +
519
+ '</td>'
520
+ );
521
+ }
522
+
523
+ renderRow(days, isRTL, isRowSelected) {
524
+ return (
525
+ '<tr class="datepicker-row' +
526
+ (isRowSelected ? ' is-selected' : '') +
527
+ '">' +
528
+ (isRTL ? days.reverse() : days).join('') +
529
+ '</tr>'
530
+ );
531
+ }
532
+
533
+ renderTable(opts, data, randId) {
534
+ return (
535
+ '<div class="datepicker-table-wrapper"><table cellpadding="0" cellspacing="0" class="datepicker-table" role="grid" aria-labelledby="' +
536
+ randId +
537
+ '">' +
538
+ this.renderHead(opts) +
539
+ this.renderBody(data) +
540
+ '</table></div>'
541
+ );
542
+ }
543
+
544
+ renderHead(opts) {
545
+ let i,
546
+ arr = [];
547
+ for (i = 0; i < 7; i++) {
548
+ arr.push(
549
+ `<th scope="col"><abbr title="${this.renderDayName(opts, i)}">${this.renderDayName(
550
+ opts,
551
+ i,
552
+ true
553
+ )}</abbr></th>`
554
+ );
555
+ }
556
+ return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
557
+ }
558
+
559
+ renderBody(rows) {
560
+ return '<tbody>' + rows.join('') + '</tbody>';
561
+ }
562
+
563
+ renderTitle(instance, c, year, month, refYear, randId) {
564
+ let i,
565
+ j,
566
+ arr,
567
+ opts = this.options,
568
+ isMinYear = year === opts.minYear,
569
+ isMaxYear = year === opts.maxYear,
570
+ html =
571
+ '<div id="' +
572
+ randId +
573
+ '" class="datepicker-controls" role="heading" aria-live="assertive">',
574
+ monthHtml,
575
+ yearHtml,
576
+ prev = true,
577
+ next = true;
578
+
579
+ for (arr = [], i = 0; i < 12; i++) {
580
+ arr.push(
581
+ '<option value="' +
582
+ (year === refYear ? i - c : 12 + i - c) +
583
+ '"' +
584
+ (i === month ? ' selected="selected"' : '') +
585
+ ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth)
586
+ ? 'disabled="disabled"'
587
+ : '') +
588
+ '>' +
589
+ opts.i18n.months[i] +
590
+ '</option>'
591
+ );
592
+ }
593
+
594
+ monthHtml =
595
+ '<select class="datepicker-select orig-select-month" tabindex="-1">' +
596
+ arr.join('') +
597
+ '</select>';
598
+
599
+ if ($.isArray(opts.yearRange)) {
600
+ i = opts.yearRange[0];
601
+ j = opts.yearRange[1] + 1;
602
+ } else {
603
+ i = year - opts.yearRange;
604
+ j = 1 + year + opts.yearRange;
605
+ }
606
+
607
+ for (arr = []; i < j && i <= opts.maxYear; i++) {
608
+ if (i >= opts.minYear) {
609
+ arr.push(`<option value="${i}" ${i === year ? 'selected="selected"' : ''}>${i}</option>`);
610
+ }
611
+ }
612
+
613
+ yearHtml = `<select class="datepicker-select orig-select-year" tabindex="-1">${arr.join(
614
+ ''
615
+ )}</select>`;
616
+
617
+ let leftArrow =
618
+ '<svg fill="#000000" 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>';
619
+ html += `<button class="month-prev${
620
+ prev ? '' : ' is-disabled'
621
+ }" type="button">${leftArrow}</button>`;
622
+
623
+ html += '<div class="selects-container">';
624
+ if (opts.showMonthAfterYear) {
625
+ html += yearHtml + monthHtml;
626
+ } else {
627
+ html += monthHtml + yearHtml;
628
+ }
629
+ html += '</div>';
630
+
631
+ if (isMinYear && (month === 0 || opts.minMonth >= month)) {
632
+ prev = false;
633
+ }
634
+
635
+ if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
636
+ next = false;
637
+ }
638
+
639
+ let rightArrow =
640
+ '<svg fill="#000000" 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>';
641
+ html += `<button class="month-next${
642
+ next ? '' : ' is-disabled'
643
+ }" type="button">${rightArrow}</button>`;
644
+
645
+ return (html += '</div>');
646
+ }
647
+
648
+ /**
649
+ * refresh the HTML
650
+ */
651
+ draw(force) {
652
+ if (!this.isOpen && !force) {
653
+ return;
654
+ }
655
+ let opts = this.options,
656
+ minYear = opts.minYear,
657
+ maxYear = opts.maxYear,
658
+ minMonth = opts.minMonth,
659
+ maxMonth = opts.maxMonth,
660
+ html = '',
661
+ randId;
662
+
663
+ if (this._y <= minYear) {
664
+ this._y = minYear;
665
+ if (!isNaN(minMonth) && this._m < minMonth) {
666
+ this._m = minMonth;
667
+ }
668
+ }
669
+ if (this._y >= maxYear) {
670
+ this._y = maxYear;
671
+ if (!isNaN(maxMonth) && this._m > maxMonth) {
672
+ this._m = maxMonth;
673
+ }
674
+ }
675
+
676
+ randId =
677
+ 'datepicker-title-' +
678
+ Math.random()
679
+ .toString(36)
680
+ .replace(/[^a-z]+/g, '')
681
+ .substr(0, 2);
682
+
683
+ for (let c = 0; c < 1; c++) {
684
+ this._renderDateDisplay();
685
+ html +=
686
+ this.renderTitle(
687
+ this,
688
+ c,
689
+ this.calendars[c].year,
690
+ this.calendars[c].month,
691
+ this.calendars[0].year,
692
+ randId
693
+ ) + this.render(this.calendars[c].year, this.calendars[c].month, randId);
694
+ }
695
+
696
+ this.destroySelects();
697
+
698
+ this.calendarEl.innerHTML = html;
699
+
700
+ // Init Materialize Select
701
+ let yearSelect = this.calendarEl.querySelector('.orig-select-year');
702
+ let monthSelect = this.calendarEl.querySelector('.orig-select-month');
703
+ M.FormSelect.init(yearSelect, {
704
+ classes: 'select-year',
705
+ dropdownOptions: { container: document.body, constrainWidth: false }
706
+ });
707
+ M.FormSelect.init(monthSelect, {
708
+ classes: 'select-month',
709
+ dropdownOptions: { container: document.body, constrainWidth: false }
710
+ });
711
+
712
+ // Add change handlers for select
713
+ yearSelect.addEventListener('change', this._handleYearChange.bind(this));
714
+ monthSelect.addEventListener('change', this._handleMonthChange.bind(this));
715
+
716
+ if (typeof this.options.onDraw === 'function') {
717
+ this.options.onDraw(this);
718
+ }
719
+ }
720
+
721
+ /**
722
+ * Setup Event Handlers
723
+ */
724
+ _setupEventHandlers() {
725
+ this._handleInputKeydownBound = this._handleInputKeydown.bind(this);
726
+ this._handleInputClickBound = this._handleInputClick.bind(this);
727
+ this._handleInputChangeBound = this._handleInputChange.bind(this);
728
+ this._handleCalendarClickBound = this._handleCalendarClick.bind(this);
729
+ this._finishSelectionBound = this._finishSelection.bind(this);
730
+ this._handleMonthChange = this._handleMonthChange.bind(this);
731
+ this._closeBound = this.close.bind(this);
732
+
733
+ this.el.addEventListener('click', this._handleInputClickBound);
734
+ this.el.addEventListener('keydown', this._handleInputKeydownBound);
735
+ this.el.addEventListener('change', this._handleInputChangeBound);
736
+ this.calendarEl.addEventListener('click', this._handleCalendarClickBound);
737
+ this.doneBtn.addEventListener('click', this._finishSelectionBound);
738
+ this.cancelBtn.addEventListener('click', this._closeBound);
739
+
740
+ if (this.options.showClearBtn) {
741
+ this._handleClearClickBound = this._handleClearClick.bind(this);
742
+ this.clearBtn.addEventListener('click', this._handleClearClickBound);
743
+ }
744
+ }
745
+
746
+ _setupVariables() {
747
+ this.$modalEl = $(Datepicker._template);
748
+ this.modalEl = this.$modalEl[0];
749
+
750
+ this.calendarEl = this.modalEl.querySelector('.datepicker-calendar');
751
+
752
+ this.yearTextEl = this.modalEl.querySelector('.year-text');
753
+ this.dateTextEl = this.modalEl.querySelector('.date-text');
754
+ if (this.options.showClearBtn) {
755
+ this.clearBtn = this.modalEl.querySelector('.datepicker-clear');
756
+ }
757
+ this.doneBtn = this.modalEl.querySelector('.datepicker-done');
758
+ this.cancelBtn = this.modalEl.querySelector('.datepicker-cancel');
759
+
760
+ this.formats = {
761
+ d: () => {
762
+ return this.date.getDate();
763
+ },
764
+ dd: () => {
765
+ let d = this.date.getDate();
766
+ return (d < 10 ? '0' : '') + d;
767
+ },
768
+ ddd: () => {
769
+ return this.options.i18n.weekdaysShort[this.date.getDay()];
770
+ },
771
+ dddd: () => {
772
+ return this.options.i18n.weekdays[this.date.getDay()];
773
+ },
774
+ m: () => {
775
+ return this.date.getMonth() + 1;
776
+ },
777
+ mm: () => {
778
+ let m = this.date.getMonth() + 1;
779
+ return (m < 10 ? '0' : '') + m;
780
+ },
781
+ mmm: () => {
782
+ return this.options.i18n.monthsShort[this.date.getMonth()];
783
+ },
784
+ mmmm: () => {
785
+ return this.options.i18n.months[this.date.getMonth()];
786
+ },
787
+ yy: () => {
788
+ return ('' + this.date.getFullYear()).slice(2);
789
+ },
790
+ yyyy: () => {
791
+ return this.date.getFullYear();
792
+ }
793
+ };
794
+ }
795
+
796
+ /**
797
+ * Remove Event Handlers
798
+ */
799
+ _removeEventHandlers() {
800
+ this.el.removeEventListener('click', this._handleInputClickBound);
801
+ this.el.removeEventListener('keydown', this._handleInputKeydownBound);
802
+ this.el.removeEventListener('change', this._handleInputChangeBound);
803
+ this.calendarEl.removeEventListener('click', this._handleCalendarClickBound);
804
+ }
805
+
806
+ _handleInputClick() {
807
+ this.open();
808
+ }
809
+
810
+ _handleInputKeydown(e) {
811
+ if (e.which === M.keys.ENTER) {
812
+ e.preventDefault();
813
+ this.open();
814
+ }
815
+ }
816
+
817
+ _handleCalendarClick(e) {
818
+ if (!this.isOpen) {
819
+ return;
820
+ }
821
+
822
+ let $target = $(e.target);
823
+ if (!$target.hasClass('is-disabled')) {
824
+ if (
825
+ $target.hasClass('datepicker-day-button') &&
826
+ !$target.hasClass('is-empty') &&
827
+ !$target.parent().hasClass('is-disabled')
828
+ ) {
829
+ this.setDate(
830
+ new Date(
831
+ e.target.getAttribute('data-year'),
832
+ e.target.getAttribute('data-month'),
833
+ e.target.getAttribute('data-day')
834
+ )
835
+ );
836
+ if (this.options.autoClose) {
837
+ this._finishSelection();
838
+ }
839
+ } else if ($target.closest('.month-prev').length) {
840
+ this.prevMonth();
841
+ } else if ($target.closest('.month-next').length) {
842
+ this.nextMonth();
843
+ }
844
+ }
845
+ }
846
+
847
+ _handleClearClick() {
848
+ this.date = null;
849
+ this.setInputValue();
850
+ this.close();
851
+ }
852
+
853
+ _handleMonthChange(e) {
854
+ this.gotoMonth(e.target.value);
855
+ }
856
+
857
+ _handleYearChange(e) {
858
+ this.gotoYear(e.target.value);
859
+ }
860
+
861
+ /**
862
+ * change view to a specific month (zero-index, e.g. 0: January)
863
+ */
864
+ gotoMonth(month) {
865
+ if (!isNaN(month)) {
866
+ this.calendars[0].month = parseInt(month, 10);
867
+ this.adjustCalendars();
868
+ }
869
+ }
870
+
871
+ /**
872
+ * change view to a specific full year (e.g. "2012")
873
+ */
874
+ gotoYear(year) {
875
+ if (!isNaN(year)) {
876
+ this.calendars[0].year = parseInt(year, 10);
877
+ this.adjustCalendars();
878
+ }
879
+ }
880
+
881
+ _handleInputChange(e) {
882
+ let date;
883
+
884
+ // Prevent change event from being fired when triggered by the plugin
885
+ if (e.firedBy === this) {
886
+ return;
887
+ }
888
+ if (this.options.parse) {
889
+ date = this.options.parse(this.el.value, this.options.format);
890
+ } else {
891
+ date = new Date(Date.parse(this.el.value));
892
+ }
893
+
894
+ if (Datepicker._isDate(date)) {
895
+ this.setDate(date);
896
+ }
897
+ }
898
+
899
+ renderDayName(opts, day, abbr) {
900
+ day += opts.firstDay;
901
+ while (day >= 7) {
902
+ day -= 7;
903
+ }
904
+ return abbr ? opts.i18n.weekdaysAbbrev[day] : opts.i18n.weekdays[day];
905
+ }
906
+
907
+ /**
908
+ * Set input value to the selected date and close Datepicker
909
+ */
910
+ _finishSelection() {
911
+ this.setInputValue();
912
+ this.close();
913
+ }
914
+
915
+ /**
916
+ * Open Datepicker
917
+ */
918
+ open() {
919
+ if (this.isOpen) {
920
+ return;
921
+ }
922
+
923
+ this.isOpen = true;
924
+ if (typeof this.options.onOpen === 'function') {
925
+ this.options.onOpen.call(this);
926
+ }
927
+ this.draw();
928
+ this.modal.open();
929
+ return this;
930
+ }
931
+
932
+ /**
933
+ * Close Datepicker
934
+ */
935
+ close() {
936
+ if (!this.isOpen) {
937
+ return;
938
+ }
939
+
940
+ this.isOpen = false;
941
+ if (typeof this.options.onClose === 'function') {
942
+ this.options.onClose.call(this);
943
+ }
944
+ this.modal.close();
945
+ return this;
946
+ }
947
+ }
948
+
949
+ Datepicker._template = [
950
+ '<div class= "modal datepicker-modal">',
951
+ '<div class="modal-content datepicker-container">',
952
+ '<div class="datepicker-date-display">',
953
+ '<span class="year-text"></span>',
954
+ '<span class="date-text"></span>',
955
+ '</div>',
956
+ '<div class="datepicker-calendar-container">',
957
+ '<div class="datepicker-calendar"></div>',
958
+ '<div class="datepicker-footer">',
959
+ '<button class="btn-flat datepicker-clear waves-effect" style="visibility: hidden;" type="button"></button>',
960
+ '<div class="confirmation-btns">',
961
+ '<button class="btn-flat datepicker-cancel waves-effect" type="button"></button>',
962
+ '<button class="btn-flat datepicker-done waves-effect" type="button"></button>',
963
+ '</div>',
964
+ '</div>',
965
+ '</div>',
966
+ '</div>',
967
+ '</div>'
968
+ ].join('');
969
+
970
+ M.Datepicker = Datepicker;
971
+
972
+ if (M.jQueryLoaded) {
973
+ M.initializeJqueryWrapper(Datepicker, 'datepicker', 'M_Datepicker');
974
+ }
975
+ })(cash);