@materializecss/materialize 1.1.0-alpha → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/Gruntfile.js +115 -132
  2. package/LICENSE +21 -21
  3. package/README.md +97 -97
  4. package/dist/css/materialize.css +8462 -8987
  5. package/dist/css/materialize.min.css +7 -7
  6. package/dist/js/materialize.js +12669 -12791
  7. package/dist/js/materialize.min.js +6 -6
  8. package/extras/noUiSlider/nouislider.css +406 -406
  9. package/extras/noUiSlider/nouislider.js +2147 -2147
  10. package/extras/noUiSlider/nouislider.min.js +0 -0
  11. package/js/anime.min.js +34 -34
  12. package/js/autocomplete.js +479 -479
  13. package/js/buttons.js +354 -354
  14. package/js/cards.js +40 -40
  15. package/js/carousel.js +732 -717
  16. package/js/cash.js +960 -960
  17. package/js/characterCounter.js +136 -136
  18. package/js/chips.js +486 -486
  19. package/js/collapsible.js +275 -275
  20. package/js/component.js +44 -44
  21. package/js/datepicker.js +983 -976
  22. package/js/dropdown.js +669 -668
  23. package/js/forms.js +275 -275
  24. package/js/global.js +424 -424
  25. package/js/materialbox.js +453 -453
  26. package/js/modal.js +382 -382
  27. package/js/parallax.js +138 -138
  28. package/js/pushpin.js +148 -148
  29. package/js/range.js +263 -263
  30. package/js/scrollspy.js +295 -295
  31. package/js/select.js +310 -451
  32. package/js/sidenav.js +583 -583
  33. package/js/slider.js +359 -359
  34. package/js/tabs.js +402 -402
  35. package/js/tapTarget.js +315 -315
  36. package/js/timepicker.js +648 -647
  37. package/js/toasts.js +322 -322
  38. package/js/tooltip.js +320 -320
  39. package/js/waves.js +614 -614
  40. package/package.json +82 -74
  41. package/sass/_style.scss +929 -0
  42. package/sass/components/_badges.scss +55 -55
  43. package/sass/components/_buttons.scss +322 -322
  44. package/sass/components/_cards.scss +195 -195
  45. package/sass/components/_carousel.scss +90 -90
  46. package/sass/components/_chips.scss +96 -96
  47. package/sass/components/_collapsible.scss +91 -91
  48. package/sass/components/_collection.scss +107 -0
  49. package/sass/components/_color-classes.scss +32 -32
  50. package/sass/components/_color-variables.scss +370 -370
  51. package/sass/components/_datepicker.scss +191 -191
  52. package/sass/components/_dropdown.scss +84 -84
  53. package/sass/components/_global.scss +642 -771
  54. package/sass/components/_grid.scss +158 -156
  55. package/sass/components/_icons-material-design.scss +5 -5
  56. package/sass/components/_materialbox.scss +42 -42
  57. package/sass/components/_modal.scss +97 -97
  58. package/sass/components/_navbar.scss +208 -208
  59. package/sass/components/_normalize.scss +447 -447
  60. package/sass/components/_preloader.scss +334 -334
  61. package/sass/components/_pulse.scss +34 -34
  62. package/sass/components/_sidenav.scss +214 -214
  63. package/sass/components/_slider.scss +91 -91
  64. package/sass/components/_table_of_contents.scss +33 -33
  65. package/sass/components/_tabs.scss +99 -99
  66. package/sass/components/_tapTarget.scss +103 -103
  67. package/sass/components/_timepicker.scss +183 -183
  68. package/sass/components/_toast.scss +58 -58
  69. package/sass/components/_tooltip.scss +32 -32
  70. package/sass/components/_transitions.scss +12 -12
  71. package/sass/components/_typography.scss +62 -60
  72. package/sass/components/_variables.scss +352 -349
  73. package/sass/components/_waves.scss +187 -187
  74. package/sass/components/forms/_checkboxes.scss +200 -200
  75. package/sass/components/forms/_file-input.scss +44 -44
  76. package/sass/components/forms/_forms.scss +22 -22
  77. package/sass/components/forms/_input-fields.scss +379 -379
  78. package/sass/components/forms/_radio-buttons.scss +115 -115
  79. package/sass/components/forms/_range.scss +161 -161
  80. package/sass/components/forms/_select.scss +199 -199
  81. package/sass/components/forms/_switches.scss +91 -91
  82. package/sass/ghpages-materialize.scss +7 -0
  83. package/sass/materialize.scss +42 -41
  84. package/CHANGELOG.md +0 -76
  85. package/HISTORY.md +0 -527
@@ -1,479 +1,479 @@
1
- (function($) {
2
- 'use strict';
3
-
4
- let _defaults = {
5
- data: {}, // Autocomplete data set
6
- limit: Infinity, // Limit of results the autocomplete shows
7
- onAutocomplete: null, // Callback for when autocompleted
8
- dropdownOptions: {
9
- // Default dropdown options
10
- autoFocus: false,
11
- closeOnClick: false,
12
- coverTrigger: false
13
- },
14
- minLength: 1, // Min characters before autocomplete starts
15
- sortFunction: function(a, b, inputString) {
16
- // Sort function for sorting autocomplete results
17
- return a.indexOf(inputString) - b.indexOf(inputString);
18
- },
19
- allowUnsafeHTML: false
20
- };
21
-
22
- /**
23
- * @class
24
- *
25
- */
26
- class Autocomplete extends Component {
27
- /**
28
- * Construct Autocomplete instance
29
- * @constructor
30
- * @param {Element} el
31
- * @param {Object} options
32
- */
33
- constructor(el, options) {
34
- super(Autocomplete, el, options);
35
-
36
- this.el.M_Autocomplete = this;
37
-
38
- /**
39
- * Options for the autocomplete
40
- * @member Autocomplete#options
41
- * @prop {Number} duration
42
- * @prop {Number} dist
43
- * @prop {number} shift
44
- * @prop {number} padding
45
- * @prop {Boolean} fullWidth
46
- * @prop {Boolean} indicators
47
- * @prop {Boolean} noWrap
48
- * @prop {Function} onCycleTo
49
- */
50
- this.options = $.extend({}, Autocomplete.defaults, options);
51
-
52
- // Setup
53
- this.isOpen = false;
54
- this.count = 0;
55
- this.activeIndex = -1;
56
- this.oldVal;
57
- this.$inputField = this.$el.closest('.input-field');
58
- this.$active = $();
59
- this._mousedown = false;
60
- this._setupDropdown();
61
-
62
- this._setupEventHandlers();
63
- }
64
-
65
- static get defaults() {
66
- return _defaults;
67
- }
68
-
69
- static init(els, options) {
70
- return super.init(this, els, options);
71
- }
72
-
73
- /**
74
- * Get Instance
75
- */
76
- static getInstance(el) {
77
- let domElem = !!el.jquery ? el[0] : el;
78
- return domElem.M_Autocomplete;
79
- }
80
-
81
- /**
82
- * Teardown component
83
- */
84
- destroy() {
85
- this._removeEventHandlers();
86
- this._removeDropdown();
87
- this.el.M_Autocomplete = undefined;
88
- }
89
-
90
- /**
91
- * Setup Event Handlers
92
- */
93
- _setupEventHandlers() {
94
- this._handleInputBlurBound = this._handleInputBlur.bind(this);
95
- this._handleInputKeyupAndFocusBound = this._handleInputKeyupAndFocus.bind(this);
96
- this._handleInputKeydownBound = this._handleInputKeydown.bind(this);
97
- this._handleInputClickBound = this._handleInputClick.bind(this);
98
- this._handleContainerMousedownAndTouchstartBound = this._handleContainerMousedownAndTouchstart.bind(
99
- this
100
- );
101
- this._handleContainerMouseupAndTouchendBound = this._handleContainerMouseupAndTouchend.bind(
102
- this
103
- );
104
-
105
- this.el.addEventListener('blur', this._handleInputBlurBound);
106
- this.el.addEventListener('keyup', this._handleInputKeyupAndFocusBound);
107
- this.el.addEventListener('focus', this._handleInputKeyupAndFocusBound);
108
- this.el.addEventListener('keydown', this._handleInputKeydownBound);
109
- this.el.addEventListener('click', this._handleInputClickBound);
110
- this.container.addEventListener(
111
- 'mousedown',
112
- this._handleContainerMousedownAndTouchstartBound
113
- );
114
- this.container.addEventListener('mouseup', this._handleContainerMouseupAndTouchendBound);
115
-
116
- if (typeof window.ontouchstart !== 'undefined') {
117
- this.container.addEventListener(
118
- 'touchstart',
119
- this._handleContainerMousedownAndTouchstartBound
120
- );
121
- this.container.addEventListener('touchend', this._handleContainerMouseupAndTouchendBound);
122
- }
123
- }
124
-
125
- /**
126
- * Remove Event Handlers
127
- */
128
- _removeEventHandlers() {
129
- this.el.removeEventListener('blur', this._handleInputBlurBound);
130
- this.el.removeEventListener('keyup', this._handleInputKeyupAndFocusBound);
131
- this.el.removeEventListener('focus', this._handleInputKeyupAndFocusBound);
132
- this.el.removeEventListener('keydown', this._handleInputKeydownBound);
133
- this.el.removeEventListener('click', this._handleInputClickBound);
134
- this.container.removeEventListener(
135
- 'mousedown',
136
- this._handleContainerMousedownAndTouchstartBound
137
- );
138
- this.container.removeEventListener('mouseup', this._handleContainerMouseupAndTouchendBound);
139
-
140
- if (typeof window.ontouchstart !== 'undefined') {
141
- this.container.removeEventListener(
142
- 'touchstart',
143
- this._handleContainerMousedownAndTouchstartBound
144
- );
145
- this.container.removeEventListener(
146
- 'touchend',
147
- this._handleContainerMouseupAndTouchendBound
148
- );
149
- }
150
- }
151
-
152
- /**
153
- * Setup dropdown
154
- */
155
- _setupDropdown() {
156
- this.container = document.createElement('ul');
157
- this.container.id = `autocomplete-options-${M.guid()}`;
158
- $(this.container).addClass('autocomplete-content dropdown-content');
159
- this.$inputField.append(this.container);
160
- this.el.setAttribute('data-target', this.container.id);
161
-
162
- // Initialize dropdown
163
- let dropdownOptions = $.extend(
164
- {},
165
- Autocomplete.defaults.dropdownOptions,
166
- this.options.dropdownOptions
167
- );
168
- let userOnItemClick = dropdownOptions.onItemClick;
169
-
170
- // Ensuring the selectOption call when user passes custom onItemClick function to dropdown
171
- dropdownOptions.onItemClick = (el) => {
172
- this.selectOption($(el));
173
-
174
- // Handle user declared onItemClick if needed
175
- if (userOnItemClick && typeof userOnItemClick === 'function') {
176
- userOnItemClick.call(this.dropdown, this.el);
177
- }
178
- };
179
-
180
- this.dropdown = M.Dropdown.init(this.el, dropdownOptions);
181
-
182
- // Sketchy removal of dropdown click handler
183
- this.el.removeEventListener('click', this.dropdown._handleClickBound);
184
- }
185
-
186
- /**
187
- * Remove dropdown
188
- */
189
- _removeDropdown() {
190
- this.container.parentNode.removeChild(this.container);
191
- }
192
-
193
- /**
194
- * Handle Input Blur
195
- */
196
- _handleInputBlur() {
197
- if (!this._mousedown) {
198
- this.close();
199
- this._resetAutocomplete();
200
- }
201
- }
202
-
203
- /**
204
- * Handle Input Keyup and Focus
205
- * @param {Event} e
206
- */
207
- _handleInputKeyupAndFocus(e) {
208
- if (e.type === 'keyup') {
209
- Autocomplete._keydown = false;
210
- }
211
-
212
- this.count = 0;
213
- let val = this.el.value.toLowerCase();
214
-
215
- // Don't capture enter or arrow key usage.
216
- if (e.keyCode === 13 || e.keyCode === 38 || e.keyCode === 40) {
217
- return;
218
- }
219
-
220
- // Check if the input isn't empty
221
- // Check if focus triggered by tab
222
- if (this.oldVal !== val && (M.tabPressed || e.type !== 'focus')) {
223
- this.open();
224
- }
225
-
226
- // Update oldVal
227
- this.oldVal = val;
228
- }
229
-
230
- /**
231
- * Handle Input Keydown
232
- * @param {Event} e
233
- */
234
- _handleInputKeydown(e) {
235
- Autocomplete._keydown = true;
236
-
237
- // Arrow keys and enter key usage
238
- let keyCode = e.keyCode,
239
- liElement,
240
- numItems = $(this.container).children('li').length;
241
-
242
- // select element on Enter
243
- if (keyCode === M.keys.ENTER && this.activeIndex >= 0) {
244
- liElement = $(this.container)
245
- .children('li')
246
- .eq(this.activeIndex);
247
- if (liElement.length) {
248
- this.selectOption(liElement);
249
- e.preventDefault();
250
- }
251
- return;
252
- }
253
-
254
- // Capture up and down key
255
- if (keyCode === M.keys.ARROW_UP || keyCode === M.keys.ARROW_DOWN) {
256
- e.preventDefault();
257
-
258
- if (keyCode === M.keys.ARROW_UP && this.activeIndex > 0) {
259
- this.activeIndex--;
260
- }
261
-
262
- if (keyCode === M.keys.ARROW_DOWN && this.activeIndex < numItems - 1) {
263
- this.activeIndex++;
264
- }
265
-
266
- this.$active.removeClass('active');
267
- if (this.activeIndex >= 0) {
268
- this.$active = $(this.container)
269
- .children('li')
270
- .eq(this.activeIndex);
271
- this.$active.addClass('active');
272
-
273
- // Focus selected
274
- this.container.children[this.activeIndex].scrollIntoView({
275
- behavior: 'smooth',
276
- block: 'nearest',
277
- inline: 'nearest'
278
- });
279
- }
280
- }
281
- }
282
-
283
- /**
284
- * Handle Input Click
285
- * @param {Event} e
286
- */
287
- _handleInputClick(e) {
288
- this.open();
289
- }
290
-
291
- /**
292
- * Handle Container Mousedown and Touchstart
293
- * @param {Event} e
294
- */
295
- _handleContainerMousedownAndTouchstart(e) {
296
- this._mousedown = true;
297
- }
298
-
299
- /**
300
- * Handle Container Mouseup and Touchend
301
- * @param {Event} e
302
- */
303
- _handleContainerMouseupAndTouchend(e) {
304
- this._mousedown = false;
305
- }
306
-
307
- /**
308
- * Highlight partial match
309
- */
310
- _highlight(input, label) {
311
- const start = label.toLowerCase().indexOf('' + input.toLowerCase() + '');
312
- const end = start + input.length - 1;
313
- //custom filters may return results where the string does not match any part
314
- if (start == -1 || end == -1) {
315
- return [label, '', ''];
316
- }
317
- return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];
318
- }
319
-
320
- /**
321
- * Reset current element position
322
- */
323
- _resetCurrentElement() {
324
- this.activeIndex = -1;
325
- this.$active.removeClass('active');
326
- }
327
-
328
- /**
329
- * Reset autocomplete elements
330
- */
331
- _resetAutocomplete() {
332
- $(this.container).empty();
333
- this._resetCurrentElement();
334
- this.oldVal = null;
335
- this.isOpen = false;
336
- this._mousedown = false;
337
- }
338
-
339
- /**
340
- * Select autocomplete option
341
- * @param {Element} el Autocomplete option list item element
342
- */
343
- selectOption(el) {
344
- let text = el.text().trim();
345
- this.el.value = text;
346
- this.$el.trigger('change');
347
- this._resetAutocomplete();
348
- this.close();
349
-
350
- // Handle onAutocomplete callback.
351
- if (typeof this.options.onAutocomplete === 'function') {
352
- this.options.onAutocomplete.call(this, text);
353
- }
354
- }
355
-
356
- /**
357
- * Render dropdown content
358
- * @param {Object} data data set
359
- * @param {String} val current input value
360
- */
361
- _renderDropdown(data, val) {
362
- this._resetAutocomplete();
363
-
364
- let matchingData = [];
365
-
366
- // Gather all matching data
367
- for (let key in data) {
368
- if (data.hasOwnProperty(key) && key.toLowerCase().indexOf(val) !== -1) {
369
- let entry = {
370
- data: data[key],
371
- key: key
372
- };
373
- matchingData.push(entry);
374
-
375
- this.count++;
376
- }
377
- }
378
-
379
- // Sort
380
- if (this.options.sortFunction) {
381
- let sortFunctionBound = (a, b) => {
382
- return this.options.sortFunction(
383
- a.key.toLowerCase(),
384
- b.key.toLowerCase(),
385
- val.toLowerCase()
386
- );
387
- };
388
- matchingData.sort(sortFunctionBound);
389
- }
390
-
391
- // Limit
392
- matchingData = matchingData.slice(0, this.options.limit);
393
-
394
- // Render
395
- for (let i = 0; i < matchingData.length; i++) {
396
- const entry = matchingData[i];
397
- const item = document.createElement('li');
398
- if (!!entry.data) {
399
- const img = document.createElement('img');
400
- img.classList.add('right', 'circle');
401
- img.src = entry.data;
402
- item.appendChild(img);
403
- }
404
-
405
- const parts = this._highlight(val, entry.key);
406
- const s = document.createElement('span');
407
- if (this.options.allowUnsafeHTML) {
408
- s.innerHTML = parts[0] + '<span class="highlight">' + parts[1] + '</span>' + parts[2];
409
- } else {
410
- s.appendChild(document.createTextNode(parts[0]));
411
- if (!!parts[1]) {
412
- const highlight = document.createElement('span');
413
- highlight.textContent = parts[1];
414
- highlight.classList.add('highlight');
415
- s.appendChild(highlight);
416
- s.appendChild(document.createTextNode(parts[2]));
417
- }
418
- }
419
- item.appendChild(s);
420
-
421
- $(this.container).append(item);
422
- }
423
- }
424
-
425
- /**
426
- * Open Autocomplete Dropdown
427
- */
428
- open() {
429
- let val = this.el.value.toLowerCase();
430
-
431
- this._resetAutocomplete();
432
-
433
- if (val.length >= this.options.minLength) {
434
- this.isOpen = true;
435
- this._renderDropdown(this.options.data, val);
436
- }
437
-
438
- // Open dropdown
439
- if (!this.dropdown.isOpen) {
440
- this.dropdown.open();
441
- } else {
442
- // Recalculate dropdown when its already open
443
- this.dropdown.recalculateDimensions();
444
- }
445
- }
446
-
447
- /**
448
- * Close Autocomplete Dropdown
449
- */
450
- close() {
451
- this.dropdown.close();
452
- }
453
-
454
- /**
455
- * Update Data
456
- * @param {Object} data
457
- */
458
- updateData(data) {
459
- let val = this.el.value.toLowerCase();
460
- this.options.data = data;
461
-
462
- if (this.isOpen) {
463
- this._renderDropdown(data, val);
464
- }
465
- }
466
- }
467
-
468
- /**
469
- * @static
470
- * @memberof Autocomplete
471
- */
472
- Autocomplete._keydown = false;
473
-
474
- M.Autocomplete = Autocomplete;
475
-
476
- if (M.jQueryLoaded) {
477
- M.initializeJqueryWrapper(Autocomplete, 'autocomplete', 'M_Autocomplete');
478
- }
479
- })(cash);
1
+ (function($) {
2
+ 'use strict';
3
+
4
+ let _defaults = {
5
+ data: {}, // Autocomplete data set
6
+ limit: Infinity, // Limit of results the autocomplete shows
7
+ onAutocomplete: null, // Callback for when autocompleted
8
+ dropdownOptions: {
9
+ // Default dropdown options
10
+ autoFocus: false,
11
+ closeOnClick: false,
12
+ coverTrigger: false
13
+ },
14
+ minLength: 1, // Min characters before autocomplete starts
15
+ sortFunction: function(a, b, inputString) {
16
+ // Sort function for sorting autocomplete results
17
+ return a.indexOf(inputString) - b.indexOf(inputString);
18
+ },
19
+ allowUnsafeHTML: false
20
+ };
21
+
22
+ /**
23
+ * @class
24
+ *
25
+ */
26
+ class Autocomplete extends Component {
27
+ /**
28
+ * Construct Autocomplete instance
29
+ * @constructor
30
+ * @param {Element} el
31
+ * @param {Object} options
32
+ */
33
+ constructor(el, options) {
34
+ super(Autocomplete, el, options);
35
+
36
+ this.el.M_Autocomplete = this;
37
+
38
+ /**
39
+ * Options for the autocomplete
40
+ * @member Autocomplete#options
41
+ * @prop {Number} duration
42
+ * @prop {Number} dist
43
+ * @prop {number} shift
44
+ * @prop {number} padding
45
+ * @prop {Boolean} fullWidth
46
+ * @prop {Boolean} indicators
47
+ * @prop {Boolean} noWrap
48
+ * @prop {Function} onCycleTo
49
+ */
50
+ this.options = $.extend({}, Autocomplete.defaults, options);
51
+
52
+ // Setup
53
+ this.isOpen = false;
54
+ this.count = 0;
55
+ this.activeIndex = -1;
56
+ this.oldVal;
57
+ this.$inputField = this.$el.closest('.input-field');
58
+ this.$active = $();
59
+ this._mousedown = false;
60
+ this._setupDropdown();
61
+
62
+ this._setupEventHandlers();
63
+ }
64
+
65
+ static get defaults() {
66
+ return _defaults;
67
+ }
68
+
69
+ static init(els, options) {
70
+ return super.init(this, els, options);
71
+ }
72
+
73
+ /**
74
+ * Get Instance
75
+ */
76
+ static getInstance(el) {
77
+ let domElem = !!el.jquery ? el[0] : el;
78
+ return domElem.M_Autocomplete;
79
+ }
80
+
81
+ /**
82
+ * Teardown component
83
+ */
84
+ destroy() {
85
+ this._removeEventHandlers();
86
+ this._removeDropdown();
87
+ this.el.M_Autocomplete = undefined;
88
+ }
89
+
90
+ /**
91
+ * Setup Event Handlers
92
+ */
93
+ _setupEventHandlers() {
94
+ this._handleInputBlurBound = this._handleInputBlur.bind(this);
95
+ this._handleInputKeyupAndFocusBound = this._handleInputKeyupAndFocus.bind(this);
96
+ this._handleInputKeydownBound = this._handleInputKeydown.bind(this);
97
+ this._handleInputClickBound = this._handleInputClick.bind(this);
98
+ this._handleContainerMousedownAndTouchstartBound = this._handleContainerMousedownAndTouchstart.bind(
99
+ this
100
+ );
101
+ this._handleContainerMouseupAndTouchendBound = this._handleContainerMouseupAndTouchend.bind(
102
+ this
103
+ );
104
+
105
+ this.el.addEventListener('blur', this._handleInputBlurBound);
106
+ this.el.addEventListener('keyup', this._handleInputKeyupAndFocusBound);
107
+ this.el.addEventListener('focus', this._handleInputKeyupAndFocusBound);
108
+ this.el.addEventListener('keydown', this._handleInputKeydownBound);
109
+ this.el.addEventListener('click', this._handleInputClickBound);
110
+ this.container.addEventListener(
111
+ 'mousedown',
112
+ this._handleContainerMousedownAndTouchstartBound
113
+ );
114
+ this.container.addEventListener('mouseup', this._handleContainerMouseupAndTouchendBound);
115
+
116
+ if (typeof window.ontouchstart !== 'undefined') {
117
+ this.container.addEventListener(
118
+ 'touchstart',
119
+ this._handleContainerMousedownAndTouchstartBound
120
+ );
121
+ this.container.addEventListener('touchend', this._handleContainerMouseupAndTouchendBound);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Remove Event Handlers
127
+ */
128
+ _removeEventHandlers() {
129
+ this.el.removeEventListener('blur', this._handleInputBlurBound);
130
+ this.el.removeEventListener('keyup', this._handleInputKeyupAndFocusBound);
131
+ this.el.removeEventListener('focus', this._handleInputKeyupAndFocusBound);
132
+ this.el.removeEventListener('keydown', this._handleInputKeydownBound);
133
+ this.el.removeEventListener('click', this._handleInputClickBound);
134
+ this.container.removeEventListener(
135
+ 'mousedown',
136
+ this._handleContainerMousedownAndTouchstartBound
137
+ );
138
+ this.container.removeEventListener('mouseup', this._handleContainerMouseupAndTouchendBound);
139
+
140
+ if (typeof window.ontouchstart !== 'undefined') {
141
+ this.container.removeEventListener(
142
+ 'touchstart',
143
+ this._handleContainerMousedownAndTouchstartBound
144
+ );
145
+ this.container.removeEventListener(
146
+ 'touchend',
147
+ this._handleContainerMouseupAndTouchendBound
148
+ );
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Setup dropdown
154
+ */
155
+ _setupDropdown() {
156
+ this.container = document.createElement('ul');
157
+ this.container.id = `autocomplete-options-${M.guid()}`;
158
+ $(this.container).addClass('autocomplete-content dropdown-content');
159
+ this.$inputField.append(this.container);
160
+ this.el.setAttribute('data-target', this.container.id);
161
+
162
+ // Initialize dropdown
163
+ let dropdownOptions = $.extend(
164
+ {},
165
+ Autocomplete.defaults.dropdownOptions,
166
+ this.options.dropdownOptions
167
+ );
168
+ let userOnItemClick = dropdownOptions.onItemClick;
169
+
170
+ // Ensuring the selectOption call when user passes custom onItemClick function to dropdown
171
+ dropdownOptions.onItemClick = (el) => {
172
+ this.selectOption($(el));
173
+
174
+ // Handle user declared onItemClick if needed
175
+ if (userOnItemClick && typeof userOnItemClick === 'function') {
176
+ userOnItemClick.call(this.dropdown, this.el);
177
+ }
178
+ };
179
+
180
+ this.dropdown = M.Dropdown.init(this.el, dropdownOptions);
181
+
182
+ // Sketchy removal of dropdown click handler
183
+ this.el.removeEventListener('click', this.dropdown._handleClickBound);
184
+ }
185
+
186
+ /**
187
+ * Remove dropdown
188
+ */
189
+ _removeDropdown() {
190
+ this.container.parentNode.removeChild(this.container);
191
+ }
192
+
193
+ /**
194
+ * Handle Input Blur
195
+ */
196
+ _handleInputBlur() {
197
+ if (!this._mousedown) {
198
+ this.close();
199
+ this._resetAutocomplete();
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Handle Input Keyup and Focus
205
+ * @param {Event} e
206
+ */
207
+ _handleInputKeyupAndFocus(e) {
208
+ if (e.type === 'keyup') {
209
+ Autocomplete._keydown = false;
210
+ }
211
+
212
+ this.count = 0;
213
+ let val = this.el.value.toLowerCase();
214
+
215
+ // Don't capture enter or arrow key usage.
216
+ if (e.keyCode === 13 || e.keyCode === 38 || e.keyCode === 40) {
217
+ return;
218
+ }
219
+
220
+ // Check if the input isn't empty
221
+ // Check if focus triggered by tab
222
+ if (this.oldVal !== val && (M.tabPressed || e.type !== 'focus')) {
223
+ this.open();
224
+ }
225
+
226
+ // Update oldVal
227
+ this.oldVal = val;
228
+ }
229
+
230
+ /**
231
+ * Handle Input Keydown
232
+ * @param {Event} e
233
+ */
234
+ _handleInputKeydown(e) {
235
+ Autocomplete._keydown = true;
236
+
237
+ // Arrow keys and enter key usage
238
+ let keyCode = e.keyCode,
239
+ liElement,
240
+ numItems = $(this.container).children('li').length;
241
+
242
+ // select element on Enter
243
+ if (keyCode === M.keys.ENTER && this.activeIndex >= 0) {
244
+ liElement = $(this.container)
245
+ .children('li')
246
+ .eq(this.activeIndex);
247
+ if (liElement.length) {
248
+ this.selectOption(liElement);
249
+ e.preventDefault();
250
+ }
251
+ return;
252
+ }
253
+
254
+ // Capture up and down key
255
+ if (keyCode === M.keys.ARROW_UP || keyCode === M.keys.ARROW_DOWN) {
256
+ e.preventDefault();
257
+
258
+ if (keyCode === M.keys.ARROW_UP && this.activeIndex > 0) {
259
+ this.activeIndex--;
260
+ }
261
+
262
+ if (keyCode === M.keys.ARROW_DOWN && this.activeIndex < numItems - 1) {
263
+ this.activeIndex++;
264
+ }
265
+
266
+ this.$active.removeClass('active');
267
+ if (this.activeIndex >= 0) {
268
+ this.$active = $(this.container)
269
+ .children('li')
270
+ .eq(this.activeIndex);
271
+ this.$active.addClass('active');
272
+
273
+ // Focus selected
274
+ this.container.children[this.activeIndex].scrollIntoView({
275
+ behavior: 'smooth',
276
+ block: 'nearest',
277
+ inline: 'nearest'
278
+ });
279
+ }
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Handle Input Click
285
+ * @param {Event} e
286
+ */
287
+ _handleInputClick(e) {
288
+ this.open();
289
+ }
290
+
291
+ /**
292
+ * Handle Container Mousedown and Touchstart
293
+ * @param {Event} e
294
+ */
295
+ _handleContainerMousedownAndTouchstart(e) {
296
+ this._mousedown = true;
297
+ }
298
+
299
+ /**
300
+ * Handle Container Mouseup and Touchend
301
+ * @param {Event} e
302
+ */
303
+ _handleContainerMouseupAndTouchend(e) {
304
+ this._mousedown = false;
305
+ }
306
+
307
+ /**
308
+ * Highlight partial match
309
+ */
310
+ _highlight(input, label) {
311
+ const start = label.toLowerCase().indexOf('' + input.toLowerCase() + '');
312
+ const end = start + input.length - 1;
313
+ //custom filters may return results where the string does not match any part
314
+ if (start == -1 || end == -1) {
315
+ return [label, '', ''];
316
+ }
317
+ return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];
318
+ }
319
+
320
+ /**
321
+ * Reset current element position
322
+ */
323
+ _resetCurrentElement() {
324
+ this.activeIndex = -1;
325
+ this.$active.removeClass('active');
326
+ }
327
+
328
+ /**
329
+ * Reset autocomplete elements
330
+ */
331
+ _resetAutocomplete() {
332
+ $(this.container).empty();
333
+ this._resetCurrentElement();
334
+ this.oldVal = null;
335
+ this.isOpen = false;
336
+ this._mousedown = false;
337
+ }
338
+
339
+ /**
340
+ * Select autocomplete option
341
+ * @param {Element} el Autocomplete option list item element
342
+ */
343
+ selectOption(el) {
344
+ let text = el.text().trim();
345
+ this.el.value = text;
346
+ this.$el.trigger('change');
347
+ this._resetAutocomplete();
348
+ this.close();
349
+
350
+ // Handle onAutocomplete callback.
351
+ if (typeof this.options.onAutocomplete === 'function') {
352
+ this.options.onAutocomplete.call(this, text);
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Render dropdown content
358
+ * @param {Object} data data set
359
+ * @param {String} val current input value
360
+ */
361
+ _renderDropdown(data, val) {
362
+ this._resetAutocomplete();
363
+
364
+ let matchingData = [];
365
+
366
+ // Gather all matching data
367
+ for (let key in data) {
368
+ if (data.hasOwnProperty(key) && key.toLowerCase().indexOf(val) !== -1) {
369
+ let entry = {
370
+ data: data[key],
371
+ key: key
372
+ };
373
+ matchingData.push(entry);
374
+
375
+ this.count++;
376
+ }
377
+ }
378
+
379
+ // Sort
380
+ if (this.options.sortFunction) {
381
+ let sortFunctionBound = (a, b) => {
382
+ return this.options.sortFunction(
383
+ a.key.toLowerCase(),
384
+ b.key.toLowerCase(),
385
+ val.toLowerCase()
386
+ );
387
+ };
388
+ matchingData.sort(sortFunctionBound);
389
+ }
390
+
391
+ // Limit
392
+ matchingData = matchingData.slice(0, this.options.limit);
393
+
394
+ // Render
395
+ for (let i = 0; i < matchingData.length; i++) {
396
+ const entry = matchingData[i];
397
+ const item = document.createElement('li');
398
+ if (!!entry.data) {
399
+ const img = document.createElement('img');
400
+ img.classList.add('right', 'circle');
401
+ img.src = entry.data;
402
+ item.appendChild(img);
403
+ }
404
+
405
+ const parts = this._highlight(val, entry.key);
406
+ const s = document.createElement('span');
407
+ if (this.options.allowUnsafeHTML) {
408
+ s.innerHTML = parts[0] + '<span class="highlight">' + parts[1] + '</span>' + parts[2];
409
+ } else {
410
+ s.appendChild(document.createTextNode(parts[0]));
411
+ if (!!parts[1]) {
412
+ const highlight = document.createElement('span');
413
+ highlight.textContent = parts[1];
414
+ highlight.classList.add('highlight');
415
+ s.appendChild(highlight);
416
+ s.appendChild(document.createTextNode(parts[2]));
417
+ }
418
+ }
419
+ item.appendChild(s);
420
+
421
+ $(this.container).append(item);
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Open Autocomplete Dropdown
427
+ */
428
+ open() {
429
+ let val = this.el.value.toLowerCase();
430
+
431
+ this._resetAutocomplete();
432
+
433
+ if (val.length >= this.options.minLength) {
434
+ this.isOpen = true;
435
+ this._renderDropdown(this.options.data, val);
436
+ }
437
+
438
+ // Open dropdown
439
+ if (!this.dropdown.isOpen) {
440
+ this.dropdown.open();
441
+ } else {
442
+ // Recalculate dropdown when its already open
443
+ this.dropdown.recalculateDimensions();
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Close Autocomplete Dropdown
449
+ */
450
+ close() {
451
+ this.dropdown.close();
452
+ }
453
+
454
+ /**
455
+ * Update Data
456
+ * @param {Object} data
457
+ */
458
+ updateData(data) {
459
+ let val = this.el.value.toLowerCase();
460
+ this.options.data = data;
461
+
462
+ if (this.isOpen) {
463
+ this._renderDropdown(data, val);
464
+ }
465
+ }
466
+ }
467
+
468
+ /**
469
+ * @static
470
+ * @memberof Autocomplete
471
+ */
472
+ Autocomplete._keydown = false;
473
+
474
+ M.Autocomplete = Autocomplete;
475
+
476
+ if (M.jQueryLoaded) {
477
+ M.initializeJqueryWrapper(Autocomplete, 'autocomplete', 'M_Autocomplete');
478
+ }
479
+ })(cash);