@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
package/js/select.js CHANGED
@@ -1,451 +1,310 @@
1
- (function($) {
2
- 'use strict';
3
-
4
- let _defaults = {
5
- classes: '',
6
- dropdownOptions: {}
7
- };
8
-
9
- /**
10
- * @class
11
- *
12
- */
13
- class FormSelect extends Component {
14
- /**
15
- * Construct FormSelect instance
16
- * @constructor
17
- * @param {Element} el
18
- * @param {Object} options
19
- */
20
- constructor(el, options) {
21
- super(FormSelect, el, options);
22
-
23
- // Don't init if browser default version
24
- if (this.$el.hasClass('browser-default')) {
25
- return;
26
- }
27
-
28
- this.el.M_FormSelect = this;
29
-
30
- /**
31
- * Options for the select
32
- * @member FormSelect#options
33
- */
34
- this.options = $.extend({}, FormSelect.defaults, options);
35
-
36
- this.isMultiple = this.$el.prop('multiple');
37
-
38
- // Setup
39
- this.el.tabIndex = -1;
40
- this._keysSelected = {};
41
- this._valueDict = {}; // Maps key to original and generated option element.
42
- this._setupDropdown();
43
-
44
- this._setupEventHandlers();
45
- }
46
-
47
- static get defaults() {
48
- return _defaults;
49
- }
50
-
51
- static init(els, options) {
52
- return super.init(this, els, options);
53
- }
54
-
55
- /**
56
- * Get Instance
57
- */
58
- static getInstance(el) {
59
- let domElem = !!el.jquery ? el[0] : el;
60
- return domElem.M_FormSelect;
61
- }
62
-
63
- /**
64
- * Teardown component
65
- */
66
- destroy() {
67
- this._removeEventHandlers();
68
- this._removeDropdown();
69
- this.el.M_FormSelect = undefined;
70
- }
71
-
72
- /**
73
- * Setup Event Handlers
74
- */
75
- _setupEventHandlers() {
76
- this._handleSelectChangeBound = this._handleSelectChange.bind(this);
77
- this._handleOptionClickBound = this._handleOptionClick.bind(this);
78
- this._handleInputClickBound = this._handleInputClick.bind(this);
79
-
80
- $(this.dropdownOptions)
81
- .find('li:not(.optgroup)')
82
- .each((el) => {
83
- el.addEventListener('click', this._handleOptionClickBound);
84
- });
85
- this.el.addEventListener('change', this._handleSelectChangeBound);
86
- this.input.addEventListener('click', this._handleInputClickBound);
87
- }
88
-
89
- /**
90
- * Remove Event Handlers
91
- */
92
- _removeEventHandlers() {
93
- $(this.dropdownOptions)
94
- .find('li:not(.optgroup)')
95
- .each((el) => {
96
- el.removeEventListener('click', this._handleOptionClickBound);
97
- });
98
- this.el.removeEventListener('change', this._handleSelectChangeBound);
99
- this.input.removeEventListener('click', this._handleInputClickBound);
100
- }
101
-
102
- /**
103
- * Handle Select Change
104
- * @param {Event} e
105
- */
106
- _handleSelectChange(e) {
107
- this._setValueToInput();
108
- }
109
-
110
- /**
111
- * Handle Option Click
112
- * @param {Event} e
113
- */
114
- _handleOptionClick(e) {
115
- e.preventDefault();
116
- let optionEl = $(e.target).closest('li')[0];
117
- this._selectOption(optionEl);
118
- e.stopPropagation();
119
- }
120
-
121
- _selectOption(optionEl) {
122
- let key = optionEl.id;
123
- if (!$(optionEl).hasClass('disabled') && !$(optionEl).hasClass('optgroup') && key.length) {
124
- let selected = true;
125
-
126
- if (this.isMultiple) {
127
- // Deselect placeholder option if still selected.
128
- let placeholderOption = $(this.dropdownOptions).find('li.disabled.selected');
129
- if (placeholderOption.length) {
130
- placeholderOption.removeClass('selected');
131
- placeholderOption.find('input[type="checkbox"]').prop('checked', false);
132
- this._toggleEntryFromArray(placeholderOption[0].id);
133
- }
134
- selected = this._toggleEntryFromArray(key);
135
- } else {
136
- $(this.dropdownOptions)
137
- .find('li')
138
- .removeClass('selected');
139
- $(optionEl).toggleClass('selected', selected);
140
- this._keysSelected = {};
141
- this._keysSelected[optionEl.id] = true;
142
- }
143
-
144
- // Set selected on original select option
145
- // Only trigger if selected state changed
146
- let prevSelected = $(this._valueDict[key].el).prop('selected');
147
- if (prevSelected !== selected) {
148
- $(this._valueDict[key].el).prop('selected', selected);
149
- this.$el.trigger('change');
150
- }
151
- }
152
-
153
- if (!this.isMultiple) {
154
- this.dropdown.close();
155
- }
156
- }
157
-
158
- /**
159
- * Handle Input Click
160
- */
161
- _handleInputClick() {
162
- if (this.dropdown && this.dropdown.isOpen) {
163
- this._setValueToInput();
164
- this._setSelectedStates();
165
- }
166
- }
167
-
168
- /**
169
- * Setup dropdown
170
- */
171
- _setupDropdown() {
172
- this.wrapper = document.createElement('div');
173
- $(this.wrapper).addClass('select-wrapper ' + this.options.classes);
174
- this.$el.before($(this.wrapper));
175
- // Move actual select element into overflow hidden wrapper
176
- let $hideSelect = $('<div class="hide-select"></div>');
177
- $(this.wrapper).append($hideSelect);
178
- $hideSelect[0].appendChild(this.el);
179
-
180
- if (this.el.disabled) {
181
- this.wrapper.classList.add('disabled');
182
- }
183
-
184
- // Create dropdown
185
- this.$selectOptions = this.$el.children('option, optgroup');
186
- this.dropdownOptions = document.createElement('ul');
187
- this.dropdownOptions.id = `select-options-${M.guid()}`;
188
- $(this.dropdownOptions).addClass(
189
- 'dropdown-content select-dropdown ' + (this.isMultiple ? 'multiple-select-dropdown' : '')
190
- );
191
-
192
- // Create dropdown structure.
193
- if (this.$selectOptions.length) {
194
- this.$selectOptions.each((el) => {
195
- if ($(el).is('option')) {
196
- // Direct descendant option.
197
- let optionEl;
198
- if (this.isMultiple) {
199
- optionEl = this._appendOptionWithIcon(this.$el, el, 'multiple');
200
- } else {
201
- optionEl = this._appendOptionWithIcon(this.$el, el);
202
- }
203
-
204
- this._addOptionToValueDict(el, optionEl);
205
- } else if ($(el).is('optgroup')) {
206
- // Optgroup.
207
- let selectOptions = $(el).children('option');
208
- $(this.dropdownOptions).append(
209
- $('<li class="optgroup"><span>' + el.getAttribute('label') + '</span></li>')[0]
210
- );
211
-
212
- selectOptions.each((el) => {
213
- let optionEl = this._appendOptionWithIcon(this.$el, el, 'optgroup-option');
214
- this._addOptionToValueDict(el, optionEl);
215
- });
216
- }
217
- });
218
- }
219
-
220
- $(this.wrapper).append(this.dropdownOptions);
221
-
222
- // Add input dropdown
223
- this.input = document.createElement('input');
224
- $(this.input).addClass('select-dropdown dropdown-trigger');
225
- this.input.setAttribute('type', 'text');
226
- this.input.setAttribute('readonly', 'true');
227
- this.input.setAttribute('data-target', this.dropdownOptions.id);
228
- if (this.el.disabled) {
229
- $(this.input).prop('disabled', 'true');
230
- }
231
-
232
- $(this.wrapper).prepend(this.input);
233
- this._setValueToInput();
234
-
235
- // Add caret
236
- let dropdownIcon = $(
237
- '<svg class="caret" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
238
- );
239
- $(this.wrapper).prepend(dropdownIcon[0]);
240
-
241
- // Initialize dropdown
242
- if (!this.el.disabled) {
243
- let dropdownOptions = $.extend({}, this.options.dropdownOptions);
244
- let userOnOpenEnd = dropdownOptions.onOpenEnd;
245
-
246
- // Add callback for centering selected option when dropdown content is scrollable
247
- dropdownOptions.onOpenEnd = (el) => {
248
- let selectedOption = $(this.dropdownOptions)
249
- .find('.selected')
250
- .first();
251
-
252
- if (selectedOption.length) {
253
- // Focus selected option in dropdown
254
- M.keyDown = true;
255
- this.dropdown.focusedIndex = selectedOption.index();
256
- this.dropdown._focusFocusedItem();
257
- M.keyDown = false;
258
-
259
- // Handle scrolling to selected option
260
- if (this.dropdown.isScrollable) {
261
- let scrollOffset =
262
- selectedOption[0].getBoundingClientRect().top -
263
- this.dropdownOptions.getBoundingClientRect().top; // scroll to selected option
264
- scrollOffset -= this.dropdownOptions.clientHeight / 2; // center in dropdown
265
- this.dropdownOptions.scrollTop = scrollOffset;
266
- }
267
- }
268
-
269
- // Handle user declared onOpenEnd if needed
270
- if (userOnOpenEnd && typeof userOnOpenEnd === 'function') {
271
- userOnOpenEnd.call(this.dropdown, this.el);
272
- }
273
- };
274
-
275
- // Prevent dropdown from closing too early
276
- dropdownOptions.closeOnClick = false;
277
-
278
- this.dropdown = M.Dropdown.init(this.input, dropdownOptions);
279
- }
280
-
281
- // Add initial selections
282
- this._setSelectedStates();
283
- }
284
-
285
- /**
286
- * Add option to value dict
287
- * @param {Element} el original option element
288
- * @param {Element} optionEl generated option element
289
- */
290
- _addOptionToValueDict(el, optionEl) {
291
- let index = Object.keys(this._valueDict).length;
292
- let key = this.dropdownOptions.id + index;
293
- let obj = {};
294
- optionEl.id = key;
295
-
296
- obj.el = el;
297
- obj.optionEl = optionEl;
298
- this._valueDict[key] = obj;
299
- }
300
-
301
- /**
302
- * Remove dropdown
303
- */
304
- _removeDropdown() {
305
- $(this.wrapper)
306
- .find('.caret')
307
- .remove();
308
- $(this.input).remove();
309
- $(this.dropdownOptions).remove();
310
- $(this.wrapper).before(this.$el);
311
- $(this.wrapper).remove();
312
- }
313
-
314
- /**
315
- * Setup dropdown
316
- * @param {Element} select select element
317
- * @param {Element} option option element from select
318
- * @param {String} type
319
- * @return {Element} option element added
320
- */
321
- _appendOptionWithIcon(select, option, type) {
322
- // Add disabled attr if disabled
323
- let disabledClass = option.disabled ? 'disabled ' : '';
324
- let optgroupClass = type === 'optgroup-option' ? 'optgroup-option ' : '';
325
- let multipleCheckbox = this.isMultiple
326
- ? `<label><input type="checkbox"${disabledClass}"/><span>${option.innerHTML}</span></label>`
327
- : option.innerHTML;
328
- let liEl = $('<li></li>');
329
- let spanEl = $('<span></span>');
330
- spanEl.html(multipleCheckbox);
331
- liEl.addClass(`${disabledClass} ${optgroupClass}`);
332
- liEl.append(spanEl);
333
-
334
- // add icons
335
- let iconUrl = option.getAttribute('data-icon');
336
- let classes = option.getAttribute('class');
337
- if (!!iconUrl) {
338
- let imgEl = $(`<img alt="" class="${classes}" src="${iconUrl}">`);
339
- liEl.prepend(imgEl);
340
- }
341
-
342
- // Check for multiple type.
343
- $(this.dropdownOptions).append(liEl[0]);
344
- return liEl[0];
345
- }
346
-
347
- /**
348
- * Toggle entry from option
349
- * @param {String} key Option key
350
- * @return {Boolean} if entry was added or removed
351
- */
352
- _toggleEntryFromArray(key) {
353
- let notAdded = !this._keysSelected.hasOwnProperty(key);
354
- let $optionLi = $(this._valueDict[key].optionEl);
355
-
356
- if (notAdded) {
357
- this._keysSelected[key] = true;
358
- } else {
359
- delete this._keysSelected[key];
360
- }
361
-
362
- $optionLi.toggleClass('selected', notAdded);
363
-
364
- // Set checkbox checked value
365
- $optionLi.find('input[type="checkbox"]').prop('checked', notAdded);
366
-
367
- // use notAdded instead of true (to detect if the option is selected or not)
368
- $optionLi.prop('selected', notAdded);
369
-
370
- return notAdded;
371
- }
372
-
373
- /**
374
- * Set text value to input
375
- */
376
- _setValueToInput() {
377
- let values = [];
378
- let options = this.$el.find('option');
379
-
380
- options.each((el) => {
381
- if ($(el).prop('selected')) {
382
- let text = $(el).text().trim();
383
- values.push(text);
384
- }
385
- });
386
-
387
- if (!values.length) {
388
- let firstDisabled = this.$el.find('option:disabled').eq(0);
389
- if (firstDisabled.length && firstDisabled[0].value === '') {
390
- values.push(firstDisabled.text());
391
- }
392
- }
393
-
394
- this.input.value = values.join(', ');
395
- }
396
-
397
- /**
398
- * Set selected state of dropdown to match actual select element
399
- */
400
- _setSelectedStates() {
401
- this._keysSelected = {};
402
-
403
- for (let key in this._valueDict) {
404
- let option = this._valueDict[key];
405
- let optionIsSelected = $(option.el).prop('selected');
406
- $(option.optionEl)
407
- .find('input[type="checkbox"]')
408
- .prop('checked', optionIsSelected);
409
- if (optionIsSelected) {
410
- this._activateOption($(this.dropdownOptions), $(option.optionEl));
411
- this._keysSelected[key] = true;
412
- } else {
413
- $(option.optionEl).removeClass('selected');
414
- }
415
- }
416
- }
417
-
418
- /**
419
- * Make option as selected and scroll to selected position
420
- * @param {jQuery} collection Select options jQuery element
421
- * @param {Element} newOption element of the new option
422
- */
423
- _activateOption(collection, newOption) {
424
- if (newOption) {
425
- if (!this.isMultiple) {
426
- collection.find('li.selected').removeClass('selected');
427
- }
428
- let option = $(newOption);
429
- option.addClass('selected');
430
- }
431
- }
432
-
433
- /**
434
- * Get Selected Values
435
- * @return {Array} Array of selected values
436
- */
437
- getSelectedValues() {
438
- let selectedValues = [];
439
- for (let key in this._keysSelected) {
440
- selectedValues.push(this._valueDict[key].el.value);
441
- }
442
- return selectedValues;
443
- }
444
- }
445
-
446
- M.FormSelect = FormSelect;
447
-
448
- if (M.jQueryLoaded) {
449
- M.initializeJqueryWrapper(FormSelect, 'formSelect', 'M_FormSelect');
450
- }
451
- })(cash);
1
+ (function($) {
2
+ 'use strict';
3
+
4
+ let _defaults = {
5
+ classes: '',
6
+ dropdownOptions: {}
7
+ };
8
+
9
+ class FormSelect extends Component {
10
+ constructor(el, options) {
11
+ super(FormSelect, el, options);
12
+ if (this.$el.hasClass('browser-default')) return;
13
+ this.el.M_FormSelect = this;
14
+ this.options = $.extend({}, FormSelect.defaults, options);
15
+ this.isMultiple = this.$el.prop('multiple');
16
+ this.el.tabIndex = -1;
17
+ this._values = [];
18
+ this._setupDropdown();
19
+ this._setupEventHandlers();
20
+ }
21
+ static get defaults() {
22
+ return _defaults;
23
+ }
24
+ static init(els, options) {
25
+ return super.init(this, els, options);
26
+ }
27
+ static getInstance(el) {
28
+ let domElem = !!el.jquery ? el[0] : el;
29
+ return domElem.M_FormSelect;
30
+ }
31
+ destroy() {
32
+ this._removeEventHandlers();
33
+ this._removeDropdown();
34
+ this.el.M_FormSelect = undefined;
35
+ }
36
+ _setupEventHandlers() {
37
+ this._handleSelectChangeBound = this._handleSelectChange.bind(this);
38
+ this._handleOptionClickBound = this._handleOptionClick.bind(this);
39
+ this._handleInputClickBound = this._handleInputClick.bind(this);
40
+ $(this.dropdownOptions)
41
+ .find('li:not(.optgroup)')
42
+ .each((el) => {
43
+ el.addEventListener('click', this._handleOptionClickBound);
44
+ });
45
+ this.el.addEventListener('change', this._handleSelectChangeBound);
46
+ this.input.addEventListener('click', this._handleInputClickBound);
47
+ }
48
+ _removeEventHandlers() {
49
+ $(this.dropdownOptions)
50
+ .find('li:not(.optgroup)')
51
+ .each((el) => {
52
+ el.removeEventListener('click', this._handleOptionClickBound);
53
+ });
54
+ this.el.removeEventListener('change', this._handleSelectChangeBound);
55
+ this.input.removeEventListener('click', this._handleInputClickBound);
56
+ }
57
+ _handleSelectChange(e) {
58
+ this._setValueToInput();
59
+ }
60
+ _handleOptionClick(e) {
61
+ e.preventDefault();
62
+ let virtualOption = $(e.target).closest('li')[0];
63
+ this._selectOptionElement(virtualOption);
64
+ e.stopPropagation();
65
+ }
66
+ _arraysEqual(a, b) {
67
+ if (a === b) return true;
68
+ if (a == null || b == null) return false;
69
+ if (a.length !== b.length) return false;
70
+ for (let i = 0; i < a.length; ++i) if (a[i] !== b[i]) return false;
71
+ return true;
72
+ }
73
+ _selectOptionElement(virtualOption) {
74
+ if (!$(virtualOption).hasClass('disabled') && !$(virtualOption).hasClass('optgroup')) {
75
+ const value = this._values.filter((value) => value.optionEl === virtualOption)[0];
76
+ const previousSelectedValues = this.getSelectedValues();
77
+ if (this.isMultiple) {
78
+ // Multi-Select
79
+ this._toggleEntryFromArray(value);
80
+ } else {
81
+ // Single-Select
82
+ this._deselectAll();
83
+ this._selectValue(value);
84
+ }
85
+ // Refresh Input-Text
86
+ this._setValueToInput();
87
+ // Trigger Change-Event only when data is different
88
+ const actualSelectedValues = this.getSelectedValues();
89
+ const selectionHasChanged = !this._arraysEqual(
90
+ previousSelectedValues,
91
+ actualSelectedValues
92
+ );
93
+ if (selectionHasChanged) this.$el.trigger('change');
94
+ }
95
+ if (!this.isMultiple) this.dropdown.close();
96
+ }
97
+ _handleInputClick() {
98
+ if (this.dropdown && this.dropdown.isOpen) {
99
+ this._setValueToInput();
100
+ this._setSelectedStates();
101
+ }
102
+ }
103
+ _setupDropdown() {
104
+ this.wrapper = document.createElement('div');
105
+ $(this.wrapper).addClass('select-wrapper ' + this.options.classes);
106
+ this.$el.before($(this.wrapper));
107
+
108
+ // Move actual select element into overflow hidden wrapper
109
+ let $hideSelect = $('<div class="hide-select"></div>');
110
+ $(this.wrapper).append($hideSelect);
111
+ $hideSelect[0].appendChild(this.el);
112
+
113
+ if (this.el.disabled) this.wrapper.classList.add('disabled');
114
+
115
+ // Create dropdown
116
+ this.$selectOptions = this.$el.children('option, optgroup');
117
+ this.dropdownOptions = document.createElement('ul');
118
+ this.dropdownOptions.id = `select-options-${M.guid()}`;
119
+ $(this.dropdownOptions).addClass(
120
+ 'dropdown-content select-dropdown ' + (this.isMultiple ? 'multiple-select-dropdown' : '')
121
+ );
122
+
123
+ // Create dropdown structure
124
+ if (this.$selectOptions.length) {
125
+ this.$selectOptions.each((realOption) => {
126
+ if ($(realOption).is('option')) {
127
+ // Option
128
+ const virtualOption = this._createAndAppendOptionWithIcon(
129
+ realOption,
130
+ this.isMultiple ? 'multiple' : undefined
131
+ );
132
+ this._addOptionToValues(realOption, virtualOption);
133
+ } else if ($(realOption).is('optgroup')) {
134
+ // Optgroup
135
+ const selectOptions = $(realOption).children('option');
136
+ $(this.dropdownOptions).append(
137
+ $(
138
+ '<li class="optgroup"><span>' + realOption.getAttribute('label') + '</span></li>'
139
+ )[0]
140
+ );
141
+ selectOptions.each((realOption) => {
142
+ const virtualOption = this._createAndAppendOptionWithIcon(
143
+ realOption,
144
+ 'optgroup-option'
145
+ );
146
+ this._addOptionToValues(realOption, virtualOption);
147
+ });
148
+ }
149
+ });
150
+ }
151
+ $(this.wrapper).append(this.dropdownOptions);
152
+
153
+ // Add input dropdown
154
+ this.input = document.createElement('input');
155
+ $(this.input).addClass('select-dropdown dropdown-trigger');
156
+ this.input.setAttribute('type', 'text');
157
+ this.input.setAttribute('readonly', 'true');
158
+ this.input.setAttribute('data-target', this.dropdownOptions.id);
159
+ if (this.el.disabled) $(this.input).prop('disabled', 'true');
160
+
161
+ $(this.wrapper).prepend(this.input);
162
+ this._setValueToInput();
163
+
164
+ // Add caret
165
+ let dropdownIcon = $(
166
+ '<svg class="caret" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
167
+ );
168
+ $(this.wrapper).prepend(dropdownIcon[0]);
169
+ // Initialize dropdown
170
+ if (!this.el.disabled) {
171
+ let dropdownOptions = $.extend({}, this.options.dropdownOptions);
172
+ dropdownOptions.coverTrigger = false;
173
+ let userOnOpenEnd = dropdownOptions.onOpenEnd;
174
+ // Add callback for centering selected option when dropdown content is scrollable
175
+ dropdownOptions.onOpenEnd = (el) => {
176
+ let selectedOption = $(this.dropdownOptions)
177
+ .find('.selected')
178
+ .first();
179
+ if (selectedOption.length) {
180
+ // Focus selected option in dropdown
181
+ M.keyDown = true;
182
+ this.dropdown.focusedIndex = selectedOption.index();
183
+ this.dropdown._focusFocusedItem();
184
+ M.keyDown = false;
185
+ // Handle scrolling to selected option
186
+ if (this.dropdown.isScrollable) {
187
+ let scrollOffset =
188
+ selectedOption[0].getBoundingClientRect().top -
189
+ this.dropdownOptions.getBoundingClientRect().top; // scroll to selected option
190
+ scrollOffset -= this.dropdownOptions.clientHeight / 2; // center in dropdown
191
+ this.dropdownOptions.scrollTop = scrollOffset;
192
+ }
193
+ }
194
+ // Handle user declared onOpenEnd if needed
195
+ if (userOnOpenEnd && typeof userOnOpenEnd === 'function')
196
+ userOnOpenEnd.call(this.dropdown, this.el);
197
+ };
198
+ // Prevent dropdown from closing too early
199
+ dropdownOptions.closeOnClick = false;
200
+ this.dropdown = M.Dropdown.init(this.input, dropdownOptions);
201
+ }
202
+ // Add initial selections
203
+ this._setSelectedStates();
204
+ }
205
+ _addOptionToValues(realOption, virtualOption) {
206
+ this._values.push({ el: realOption, optionEl: virtualOption });
207
+ }
208
+ _removeDropdown() {
209
+ $(this.wrapper)
210
+ .find('.caret')
211
+ .remove();
212
+ $(this.input).remove();
213
+ $(this.dropdownOptions).remove();
214
+ $(this.wrapper).before(this.$el);
215
+ $(this.wrapper).remove();
216
+ }
217
+ _createAndAppendOptionWithIcon(realOption, type) {
218
+ const li = document.createElement('li');
219
+ if (realOption.disabled) li.classList.add('disabled');
220
+ if (type === 'optgroup-option') li.classList.add(type);
221
+ // Text / Checkbox
222
+ const span = document.createElement('span');
223
+ if (this.isMultiple)
224
+ span.innerHTML = `<label><input type="checkbox"${
225
+ realOption.disabled ? ' disabled="disabled"' : ''
226
+ }><span>${realOption.innerHTML}</span></label>`;
227
+ else span.innerHTML = realOption.innerHTML;
228
+ li.appendChild(span);
229
+ // add Icon
230
+ const iconUrl = realOption.getAttribute('data-icon');
231
+ const classes = realOption.getAttribute('class');
232
+ if (iconUrl) {
233
+ const img = $(`<img alt="" class="${classes}" src="${iconUrl}">`);
234
+ li.prepend(img[0]);
235
+ }
236
+ // Check for multiple type
237
+ $(this.dropdownOptions).append(li);
238
+ return li;
239
+ }
240
+
241
+ _selectValue(value) {
242
+ value.el.selected = true;
243
+ value.optionEl.classList.add('selected');
244
+ const checkbox = value.optionEl.querySelector('input[type="checkbox"]');
245
+ if (checkbox) checkbox.checked = true;
246
+ }
247
+ _deselectValue(value) {
248
+ value.el.selected = false;
249
+ value.optionEl.classList.remove('selected');
250
+ const checkbox = value.optionEl.querySelector('input[type="checkbox"]');
251
+ if (checkbox) checkbox.checked = false;
252
+ }
253
+ _deselectAll() {
254
+ this._values.forEach((value) => {
255
+ this._deselectValue(value);
256
+ });
257
+ }
258
+ _isValueSelected(value) {
259
+ const realValues = this.getSelectedValues();
260
+ return realValues.some((realValue) => realValue === value.el.value);
261
+ }
262
+ _toggleEntryFromArray(value) {
263
+ const isSelected = this._isValueSelected(value);
264
+ if (isSelected) this._deselectValue(value);
265
+ else this._selectValue(value);
266
+ }
267
+ _getSelectedOptions() {
268
+ return Array.prototype.filter.call(this.el.selectedOptions, (realOption) => realOption);
269
+ }
270
+
271
+ _setValueToInput() {
272
+ const realOptions = this._getSelectedOptions();
273
+ const values = this._values.filter((value) => realOptions.indexOf(value.el) >= 0);
274
+ const texts = values.map((value) => value.optionEl.querySelector('span').innerText.trim());
275
+ // Set input-text to first Option with empty value which indicates a description like "choose your option"
276
+ if (texts.length === 0) {
277
+ const firstDisabledOption = this.$el.find('option:disabled').eq(0);
278
+ if (firstDisabledOption.length > 0 && firstDisabledOption[0].value === '') {
279
+ this.input.value = firstDisabledOption.text();
280
+ return;
281
+ }
282
+ }
283
+ this.input.value = texts.join(', ');
284
+ }
285
+ _setSelectedStates() {
286
+ this._values.forEach((value) => {
287
+ const optionIsSelected = $(value.el).prop('selected');
288
+ $(value.optionEl)
289
+ .find('input[type="checkbox"]')
290
+ .prop('checked', optionIsSelected);
291
+ if (optionIsSelected) {
292
+ this._activateOption($(this.dropdownOptions), $(value.optionEl));
293
+ } else $(value.optionEl).removeClass('selected');
294
+ });
295
+ }
296
+ _activateOption(ul, li) {
297
+ if (!li) return;
298
+ if (!this.isMultiple) ul.find('li.selected').removeClass('selected');
299
+ $(li).addClass('selected');
300
+ }
301
+
302
+ getSelectedValues() {
303
+ return this._getSelectedOptions().map((realOption) => realOption.value);
304
+ }
305
+ }
306
+
307
+ M.FormSelect = FormSelect;
308
+
309
+ if (M.jQueryLoaded) M.initializeJqueryWrapper(FormSelect, 'formSelect', 'M_FormSelect');
310
+ })(cash);