@materializecss/materialize 1.2.2 → 2.0.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Gruntfile.js +68 -313
- package/README.md +2 -2
- package/dist/css/materialize.css +1009 -1822
- package/dist/css/materialize.min.css +2 -8
- package/dist/js/materialize.js +8402 -12300
- package/dist/js/materialize.min.js +3 -2
- package/dist/js/materialize.min.js.map +1 -0
- package/package.json +13 -9
- package/sass/components/_badges.scss +12 -2
- package/sass/components/_buttons.scss +16 -11
- package/sass/components/_cards.scss +14 -9
- package/sass/components/_carousel.scss +5 -2
- package/sass/components/_chips.scss +3 -3
- package/sass/components/_collapsible.scss +22 -8
- package/sass/components/_collection.scss +14 -6
- package/sass/components/_datepicker.scss +30 -11
- package/sass/components/_dropdown.scss +6 -4
- package/sass/components/_global.scss +132 -111
- package/sass/components/_grid.scss +119 -98
- package/sass/components/_modal.scss +3 -3
- package/sass/components/_navbar.scss +31 -17
- package/sass/components/_normalize.scss +26 -124
- package/sass/components/_sidenav.scss +21 -20
- package/sass/components/_slider.scss +27 -7
- package/sass/components/_table_of_contents.scss +12 -12
- package/sass/components/_tabs.scss +47 -16
- package/sass/components/_tapTarget.scss +6 -6
- package/sass/components/_timepicker.scss +54 -46
- package/sass/components/_toast.scss +3 -3
- package/sass/components/_tooltip.scss +4 -5
- package/sass/components/_typography.scss +1 -1
- package/sass/components/_variables.scss +185 -120
- package/sass/components/forms/_checkboxes.scss +9 -9
- package/sass/components/forms/_file-input.scss +9 -7
- package/sass/components/forms/_input-fields.scss +173 -234
- package/sass/components/forms/_radio-buttons.scss +1 -1
- package/sass/components/forms/_range.scss +11 -11
- package/sass/components/forms/_select.scss +29 -19
- package/sass/components/forms/_switches.scss +22 -18
- package/sass/materialize.scss +1 -1
- package/src/autocomplete.ts +459 -0
- package/src/bounding.ts +6 -0
- package/{js/buttons.js → src/buttons.ts} +103 -162
- package/src/cards.ts +54 -0
- package/{js/carousel.js → src/carousel.ts} +137 -262
- package/src/characterCounter.ts +88 -0
- package/src/chips.ts +350 -0
- package/src/collapsible.ts +184 -0
- package/{js/component.js → src/component.ts} +6 -19
- package/{js/datepicker.js → src/datepicker.ts} +213 -299
- package/{js/dropdown.js → src/dropdown.ts} +140 -254
- package/src/edges.ts +6 -0
- package/src/forms.ts +120 -0
- package/src/global.ts +385 -0
- package/src/materialbox.ts +348 -0
- package/src/modal.ts +256 -0
- package/{js/parallax.js → src/parallax.ts} +47 -60
- package/{js/pushpin.js → src/pushpin.ts} +19 -47
- package/{js/range.js → src/range.ts} +58 -139
- package/{js/scrollspy.js → src/scrollspy.ts} +81 -153
- package/src/select.ts +448 -0
- package/{js/sidenav.js → src/sidenav.ts} +96 -202
- package/src/slider.ts +415 -0
- package/src/tabs.ts +290 -0
- package/src/tapTarget.ts +240 -0
- package/{js/timepicker.js → src/timepicker.ts} +268 -272
- package/{js/toasts.js → src/toasts.ts} +75 -134
- package/{js/tooltip.js → src/tooltip.ts} +59 -96
- package/src/waves.ts +70 -0
- package/extras/noUiSlider/nouislider.css +0 -404
- package/extras/noUiSlider/nouislider.js +0 -2147
- package/extras/noUiSlider/nouislider.min.js +0 -1
- package/js/anime.min.js +0 -34
- package/js/autocomplete.js +0 -479
- package/js/cards.js +0 -40
- package/js/cash.js +0 -960
- package/js/characterCounter.js +0 -136
- package/js/chips.js +0 -486
- package/js/collapsible.js +0 -275
- package/js/forms.js +0 -285
- package/js/global.js +0 -428
- package/js/materialbox.js +0 -453
- package/js/modal.js +0 -382
- package/js/select.js +0 -391
- package/js/slider.js +0 -497
- package/js/tabs.js +0 -402
- package/js/tapTarget.js +0 -315
- package/js/waves.js +0 -615
- package/sass/components/_waves.scss +0 -187
package/src/select.ts
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { Component } from "./component";
|
|
2
|
+
import { Dropdown } from "./dropdown";
|
|
3
|
+
import { M } from "./global";
|
|
4
|
+
|
|
5
|
+
let _defaults = {
|
|
6
|
+
classes: '',
|
|
7
|
+
dropdownOptions: {}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type ValueStruct = {
|
|
11
|
+
el: any,
|
|
12
|
+
optionEl: HTMLOptionElement,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class FormSelect extends Component {
|
|
16
|
+
el: HTMLSelectElement;
|
|
17
|
+
isMultiple: boolean;
|
|
18
|
+
private _values: ValueStruct[];
|
|
19
|
+
labelEl: HTMLLabelElement;
|
|
20
|
+
//private _labelFor: boolean;
|
|
21
|
+
dropdownOptions: HTMLUListElement;
|
|
22
|
+
input: HTMLInputElement;
|
|
23
|
+
dropdown: Dropdown;
|
|
24
|
+
wrapper: HTMLDivElement;
|
|
25
|
+
selectOptions: HTMLElement[];
|
|
26
|
+
private _handleSelectChangeBound: any;
|
|
27
|
+
private _handleOptionClickBound: any;
|
|
28
|
+
private _handleInputClickBound: any;
|
|
29
|
+
|
|
30
|
+
constructor(el, options) {
|
|
31
|
+
super(FormSelect, el, options);
|
|
32
|
+
if (this.el.classList.contains('browser-default')) return;
|
|
33
|
+
(this.el as any).M_FormSelect = this;
|
|
34
|
+
this.options = {...FormSelect.defaults, ...options};
|
|
35
|
+
this.isMultiple = this.el.multiple;
|
|
36
|
+
this.el.tabIndex = -1;
|
|
37
|
+
this._values = [];
|
|
38
|
+
//this.labelEl = null;
|
|
39
|
+
//this._labelFor = false;
|
|
40
|
+
this._setupDropdown();
|
|
41
|
+
this._setupEventHandlers();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static get defaults() {
|
|
45
|
+
return _defaults;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static init(els, options) {
|
|
49
|
+
return super.init(this, els, options);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static getInstance(el) {
|
|
53
|
+
let domElem = !!el.jquery ? el[0] : el;
|
|
54
|
+
return domElem.M_FormSelect;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
destroy() {
|
|
58
|
+
// Returns label to its original owner
|
|
59
|
+
//if (this._labelFor) this.labelEl.setAttribute("for", this.el.id);
|
|
60
|
+
this._removeEventHandlers();
|
|
61
|
+
this._removeDropdown();
|
|
62
|
+
(this.el as any).M_FormSelect = undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_setupEventHandlers() {
|
|
66
|
+
this._handleSelectChangeBound = this._handleSelectChange.bind(this);
|
|
67
|
+
this._handleOptionClickBound = this._handleOptionClick.bind(this);
|
|
68
|
+
this._handleInputClickBound = this._handleInputClick.bind(this);
|
|
69
|
+
this.dropdownOptions.querySelectorAll('li:not(.optgroup)').forEach((el) => {
|
|
70
|
+
el.addEventListener('click', this._handleOptionClickBound);
|
|
71
|
+
el.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
72
|
+
if (e.key === " " || e.key === "Enter") this._handleOptionClickBound(e);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
this.el.addEventListener('change', this._handleSelectChangeBound);
|
|
76
|
+
this.input.addEventListener('click', this._handleInputClickBound);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_removeEventHandlers() {
|
|
80
|
+
this.dropdownOptions.querySelectorAll('li:not(.optgroup)').forEach((el) => {
|
|
81
|
+
el.removeEventListener('click', this._handleOptionClickBound);
|
|
82
|
+
});
|
|
83
|
+
this.el.removeEventListener('change', this._handleSelectChangeBound);
|
|
84
|
+
this.input.removeEventListener('click', this._handleInputClickBound);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_handleSelectChange(e) {
|
|
88
|
+
this._setValueToInput();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_handleOptionClick(e) {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
const virtualOption = e.target.closest('li');
|
|
94
|
+
this._selectOptionElement(virtualOption);
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_arraysEqual(a, b) {
|
|
99
|
+
if (a === b) return true;
|
|
100
|
+
if (a == null || b == null) return false;
|
|
101
|
+
if (a.length !== b.length) return false;
|
|
102
|
+
for (let i = 0; i < a.length; ++i) if (a[i] !== b[i]) return false;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_selectOptionElement(virtualOption: HTMLElement) {
|
|
107
|
+
if (!virtualOption.classList.contains('disabled') && !virtualOption.classList.contains('optgroup')) {
|
|
108
|
+
const value = this._values.find((value) => value.optionEl === virtualOption);
|
|
109
|
+
const previousSelectedValues = this.getSelectedValues();
|
|
110
|
+
if (this.isMultiple) {
|
|
111
|
+
// Multi-Select
|
|
112
|
+
this._toggleEntryFromArray(value);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Single-Select
|
|
116
|
+
this._deselectAll();
|
|
117
|
+
this._selectValue(value);
|
|
118
|
+
}
|
|
119
|
+
// Refresh Input-Text
|
|
120
|
+
this._setValueToInput();
|
|
121
|
+
// Trigger Change-Event only when data is different
|
|
122
|
+
const actualSelectedValues = this.getSelectedValues();
|
|
123
|
+
const selectionHasChanged = !this._arraysEqual(
|
|
124
|
+
previousSelectedValues,
|
|
125
|
+
actualSelectedValues
|
|
126
|
+
);
|
|
127
|
+
if (selectionHasChanged) this.el.dispatchEvent(new Event('change')); // trigger('change');
|
|
128
|
+
}
|
|
129
|
+
if (!this.isMultiple) this.dropdown.close();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
_handleInputClick() {
|
|
133
|
+
if (this.dropdown && this.dropdown.isOpen) {
|
|
134
|
+
this._setValueToInput();
|
|
135
|
+
this._setSelectedStates();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_setupDropdown() {
|
|
140
|
+
// Get Label
|
|
141
|
+
this.labelEl = this.el.parentElement.querySelector('label');
|
|
142
|
+
|
|
143
|
+
// Create Wrapper
|
|
144
|
+
this.wrapper = document.createElement('div');
|
|
145
|
+
this.wrapper.classList.add('select-wrapper', 'input-field');
|
|
146
|
+
if (this.options.classes.length > 0) {
|
|
147
|
+
this.wrapper.classList.add(this.options.classes.split(' '));
|
|
148
|
+
}
|
|
149
|
+
this.el.before(this.wrapper);
|
|
150
|
+
|
|
151
|
+
// Move actual select element into overflow hidden wrapper
|
|
152
|
+
const hideSelect = document.createElement('div');
|
|
153
|
+
hideSelect.classList.add('hide-select');
|
|
154
|
+
this.wrapper.append(hideSelect);
|
|
155
|
+
hideSelect.appendChild(this.el);
|
|
156
|
+
|
|
157
|
+
if (this.el.disabled) this.wrapper.classList.add('disabled');
|
|
158
|
+
|
|
159
|
+
this.selectOptions = <HTMLElement[]>Array.from(this.el.children).filter(el => ['OPTION','OPTGROUP'].includes(el.tagName));
|
|
160
|
+
|
|
161
|
+
// Create dropdown
|
|
162
|
+
this.dropdownOptions = document.createElement('ul');
|
|
163
|
+
this.dropdownOptions.id = `select-options-${M.guid()}`;
|
|
164
|
+
this.dropdownOptions.classList.add('dropdown-content', 'select-dropdown');
|
|
165
|
+
this.dropdownOptions.setAttribute('role', 'listbox');
|
|
166
|
+
this.dropdownOptions.ariaMultiSelectable = this.isMultiple.toString();
|
|
167
|
+
if (this.isMultiple) this.dropdownOptions.classList.add('multiple-select-dropdown');
|
|
168
|
+
|
|
169
|
+
// Create dropdown structure
|
|
170
|
+
if (this.selectOptions.length > 0) {
|
|
171
|
+
this.selectOptions.forEach((realOption) => {
|
|
172
|
+
if (realOption.tagName === 'OPTION') {
|
|
173
|
+
// Option
|
|
174
|
+
const virtualOption = this._createAndAppendOptionWithIcon(realOption, this.isMultiple ? 'multiple' : undefined);
|
|
175
|
+
this._addOptionToValues(realOption, virtualOption);
|
|
176
|
+
}
|
|
177
|
+
else if (realOption.tagName === 'OPTGROUP') {
|
|
178
|
+
// Optgroup
|
|
179
|
+
const groupId = "opt-group-"+M.guid();
|
|
180
|
+
const groupParent = document.createElement('li');
|
|
181
|
+
groupParent.classList.add('optgroup');
|
|
182
|
+
groupParent.tabIndex = -1;
|
|
183
|
+
groupParent.setAttribute('role', 'group');
|
|
184
|
+
groupParent.setAttribute('aria-labelledby', groupId);
|
|
185
|
+
groupParent.innerHTML = `<span id="${groupId}" role="presentation">${realOption.getAttribute('label')}</span>`;
|
|
186
|
+
this.dropdownOptions.append(groupParent);
|
|
187
|
+
|
|
188
|
+
const groupChildren = [];
|
|
189
|
+
const selectOptions = <HTMLOptionElement[]>Array.from(realOption.children).filter(el => el.tagName === 'OPTION');
|
|
190
|
+
selectOptions.forEach(realOption => {
|
|
191
|
+
const virtualOption = this._createAndAppendOptionWithIcon(realOption, 'optgroup-option');
|
|
192
|
+
const childId = "opt-child-"+M.guid();
|
|
193
|
+
virtualOption.id = childId;
|
|
194
|
+
groupChildren.push(childId);
|
|
195
|
+
this._addOptionToValues(realOption, virtualOption);
|
|
196
|
+
});
|
|
197
|
+
groupParent.setAttribute("aria-owns", groupChildren.join(" "));
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
this.wrapper.append(this.dropdownOptions);
|
|
202
|
+
|
|
203
|
+
// Add input dropdown
|
|
204
|
+
this.input = document.createElement('input');
|
|
205
|
+
this.input.id = "m_select-input-" + M.guid();
|
|
206
|
+
this.input.classList.add('select-dropdown', 'dropdown-trigger');
|
|
207
|
+
this.input.type = 'text';
|
|
208
|
+
this.input.readOnly = true;
|
|
209
|
+
this.input.setAttribute('data-target', this.dropdownOptions.id);
|
|
210
|
+
this.input.ariaReadOnly = 'true';
|
|
211
|
+
this.input.ariaRequired = this.el.hasAttribute("required").toString(); //setAttribute("aria-required", this.el.hasAttribute("required"));
|
|
212
|
+
if (this.el.disabled) this.input.disabled = true; // 'true');
|
|
213
|
+
|
|
214
|
+
// Place Label after input
|
|
215
|
+
if (this.labelEl) {
|
|
216
|
+
this.input.after(this.labelEl);
|
|
217
|
+
this.labelEl.setAttribute('for', this.input.id);
|
|
218
|
+
this.labelEl.id = "m_select-label-" + M.guid();
|
|
219
|
+
this.dropdownOptions.setAttribute("aria-labelledby", this.labelEl.id);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Makes new element to assume HTML's select label and aria-attributes, if exists
|
|
223
|
+
/*
|
|
224
|
+
if (this.el.hasAttribute("aria-labelledby")){
|
|
225
|
+
console.log(1);
|
|
226
|
+
this.labelEl = <HTMLLabelElement>document.getElementById(this.el.getAttribute("aria-labelledby"));
|
|
227
|
+
}
|
|
228
|
+
else if (this.el.id != ""){
|
|
229
|
+
console.log(2);
|
|
230
|
+
const label = document.createElement('label');
|
|
231
|
+
label.setAttribute('for', this.el.id);
|
|
232
|
+
if (label){
|
|
233
|
+
this.labelEl = label;
|
|
234
|
+
this.labelEl.removeAttribute("for");
|
|
235
|
+
this._labelFor = true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
*/
|
|
239
|
+
// Tries to find a valid label in parent element
|
|
240
|
+
// if (!this.labelEl) {
|
|
241
|
+
// this.labelEl = this.el.parentElement.querySelector('label');
|
|
242
|
+
// }
|
|
243
|
+
// if (this.labelEl && this.labelEl.id == "") {
|
|
244
|
+
// this.labelEl.id = "m_select-label-" + M.guid();
|
|
245
|
+
// }
|
|
246
|
+
// if (this.labelEl) {
|
|
247
|
+
// this.labelEl.setAttribute("for", this.input.id);
|
|
248
|
+
// this.dropdownOptions.setAttribute("aria-labelledby", this.labelEl.id);
|
|
249
|
+
// }
|
|
250
|
+
// else
|
|
251
|
+
// this.dropdownOptions.ariaLabel = '';
|
|
252
|
+
|
|
253
|
+
const attrs = this.el.attributes;
|
|
254
|
+
for (let i = 0; i < attrs.length; ++i){
|
|
255
|
+
const attr = attrs[i];
|
|
256
|
+
if (attr.name.startsWith("aria-"))
|
|
257
|
+
this.input.setAttribute(attr.name, attr.value);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Adds aria-attributes to input element
|
|
261
|
+
this.input.setAttribute('role', 'combobox');
|
|
262
|
+
this.input.ariaExpanded = 'false';
|
|
263
|
+
this.input.setAttribute("aria-owns", this.dropdownOptions.id);
|
|
264
|
+
this.input.setAttribute("aria-controls", this.dropdownOptions.id);
|
|
265
|
+
this.input.placeholder = " ";
|
|
266
|
+
|
|
267
|
+
this.wrapper.prepend(this.input);
|
|
268
|
+
this._setValueToInput();
|
|
269
|
+
|
|
270
|
+
// Add caret
|
|
271
|
+
const dropdownIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); //document.createElement('svg')
|
|
272
|
+
dropdownIcon.classList.add('caret');
|
|
273
|
+
dropdownIcon.setAttribute('height', '24');
|
|
274
|
+
dropdownIcon.setAttribute('width', '24');
|
|
275
|
+
dropdownIcon.setAttribute('viewBox', '0 0 24 24');
|
|
276
|
+
dropdownIcon.ariaHidden = 'true';
|
|
277
|
+
dropdownIcon.innerHTML = `<path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/>`;
|
|
278
|
+
this.wrapper.prepend(dropdownIcon);
|
|
279
|
+
|
|
280
|
+
// Initialize dropdown
|
|
281
|
+
if (!this.el.disabled) {
|
|
282
|
+
const dropdownOptions = {...this.options.dropdownOptions}; // TODO:
|
|
283
|
+
dropdownOptions.coverTrigger = false;
|
|
284
|
+
const userOnOpenEnd = dropdownOptions.onOpenEnd;
|
|
285
|
+
const userOnCloseEnd = dropdownOptions.onCloseEnd;
|
|
286
|
+
// Add callback for centering selected option when dropdown content is scrollable
|
|
287
|
+
dropdownOptions.onOpenEnd = (el) => {
|
|
288
|
+
const selectedOption = this.dropdownOptions.querySelector('.selected');
|
|
289
|
+
if (selectedOption) {
|
|
290
|
+
// Focus selected option in dropdown
|
|
291
|
+
M.keyDown = true;
|
|
292
|
+
this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(selectedOption);
|
|
293
|
+
this.dropdown._focusFocusedItem();
|
|
294
|
+
M.keyDown = false;
|
|
295
|
+
// Handle scrolling to selected option
|
|
296
|
+
if (this.dropdown.isScrollable) {
|
|
297
|
+
let scrollOffset =
|
|
298
|
+
selectedOption.getBoundingClientRect().top -
|
|
299
|
+
(this.dropdownOptions as HTMLElement).getBoundingClientRect().top; // scroll to selected option
|
|
300
|
+
scrollOffset -= this.dropdownOptions.clientHeight / 2; // center in dropdown
|
|
301
|
+
this.dropdownOptions.scrollTop = scrollOffset;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
this.input.ariaExpanded = 'true';
|
|
305
|
+
// Handle user declared onOpenEnd if needed
|
|
306
|
+
if (userOnOpenEnd && typeof userOnOpenEnd === 'function')
|
|
307
|
+
userOnOpenEnd.call(this.dropdown, this.el);
|
|
308
|
+
};
|
|
309
|
+
// Add callback for reseting "expanded" state
|
|
310
|
+
dropdownOptions.onCloseEnd = (el) => {
|
|
311
|
+
this.input.ariaExpanded = 'false';
|
|
312
|
+
// Handle user declared onOpenEnd if needed
|
|
313
|
+
if (userOnCloseEnd && typeof userOnCloseEnd === 'function')
|
|
314
|
+
userOnCloseEnd.call(this.dropdown, this.el);
|
|
315
|
+
};
|
|
316
|
+
// Prevent dropdown from closing too early
|
|
317
|
+
dropdownOptions.closeOnClick = false;
|
|
318
|
+
this.dropdown = M.Dropdown.init(this.input, dropdownOptions);
|
|
319
|
+
}
|
|
320
|
+
// Add initial selections
|
|
321
|
+
this._setSelectedStates();
|
|
322
|
+
|
|
323
|
+
// ! Workaround for Label: move label up again
|
|
324
|
+
if (this.labelEl) this.input.after(this.labelEl);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
_addOptionToValues(realOption, virtualOption) {
|
|
328
|
+
this._values.push({ el: realOption, optionEl: virtualOption });
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
_removeDropdown() {
|
|
332
|
+
this.wrapper.querySelector('.caret').remove();
|
|
333
|
+
this.input.remove();
|
|
334
|
+
this.dropdownOptions.remove();
|
|
335
|
+
this.wrapper.before(this.el);
|
|
336
|
+
this.wrapper.remove();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
_createAndAppendOptionWithIcon(realOption, type: string) {
|
|
340
|
+
const li = document.createElement('li');
|
|
341
|
+
li.setAttribute('role', 'option');
|
|
342
|
+
if (realOption.disabled){
|
|
343
|
+
li.classList.add('disabled');
|
|
344
|
+
li.ariaDisabled = 'true';
|
|
345
|
+
}
|
|
346
|
+
if (type === 'optgroup-option') li.classList.add(type);
|
|
347
|
+
// Text / Checkbox
|
|
348
|
+
const span = document.createElement('span');
|
|
349
|
+
if (this.isMultiple)
|
|
350
|
+
span.innerHTML = `<label><input type="checkbox"${
|
|
351
|
+
realOption.disabled ? ' disabled="disabled"' : ''
|
|
352
|
+
}><span>${realOption.innerHTML}</span></label>`;
|
|
353
|
+
else
|
|
354
|
+
span.innerHTML = realOption.innerHTML;
|
|
355
|
+
li.appendChild(span);
|
|
356
|
+
// add Icon
|
|
357
|
+
const iconUrl = realOption.getAttribute('data-icon');
|
|
358
|
+
const classes = realOption.getAttribute('class')?.split();
|
|
359
|
+
if (iconUrl) {
|
|
360
|
+
const img = document.createElement('img');
|
|
361
|
+
if (classes) img.classList.add(classes);
|
|
362
|
+
img.src = iconUrl;
|
|
363
|
+
img.ariaHidden = 'true';
|
|
364
|
+
li.prepend(img);
|
|
365
|
+
}
|
|
366
|
+
// Check for multiple type
|
|
367
|
+
this.dropdownOptions.append(li);
|
|
368
|
+
return li;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
_selectValue(value) {
|
|
372
|
+
value.el.selected = true;
|
|
373
|
+
value.optionEl.classList.add('selected');
|
|
374
|
+
value.optionEl.ariaSelected = 'true'; // setAttribute("aria-selected", true);
|
|
375
|
+
const checkbox = value.optionEl.querySelector('input[type="checkbox"]');
|
|
376
|
+
if (checkbox) checkbox.checked = true;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
_deselectValue(value) {
|
|
380
|
+
value.el.selected = false;
|
|
381
|
+
value.optionEl.classList.remove('selected');
|
|
382
|
+
value.optionEl.ariaSelected = 'false'; //setAttribute("aria-selected", false);
|
|
383
|
+
const checkbox = value.optionEl.querySelector('input[type="checkbox"]');
|
|
384
|
+
if (checkbox) checkbox.checked = false;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
_deselectAll() {
|
|
388
|
+
this._values.forEach(value => this._deselectValue(value));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
_isValueSelected(value) {
|
|
392
|
+
const realValues = this.getSelectedValues();
|
|
393
|
+
return realValues.some((realValue) => realValue === value.el.value);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
_toggleEntryFromArray(value) {
|
|
397
|
+
if (this._isValueSelected(value))
|
|
398
|
+
this._deselectValue(value);
|
|
399
|
+
else
|
|
400
|
+
this._selectValue(value);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
_getSelectedOptions() {
|
|
404
|
+
// remove null, false, ... values
|
|
405
|
+
return Array.prototype.filter.call(this.el.selectedOptions, (realOption) => realOption);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
_setValueToInput() {
|
|
409
|
+
const realOptions = this._getSelectedOptions();
|
|
410
|
+
const values = this._values.filter((value) => realOptions.indexOf(value.el) >= 0);
|
|
411
|
+
const texts = values.map((value) => value.optionEl.querySelector('span').innerText.trim());
|
|
412
|
+
// Set input-text to first Option with empty value which indicates a description like "choose your option"
|
|
413
|
+
if (texts.length === 0) {
|
|
414
|
+
const firstDisabledOption = <HTMLOptionElement>this.el.querySelector('option:disabled');
|
|
415
|
+
if (firstDisabledOption && firstDisabledOption.value === '') {
|
|
416
|
+
this.input.value = firstDisabledOption.innerText;
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
this.input.value = texts.join(', ');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
_setSelectedStates() {
|
|
424
|
+
this._values.forEach((value) => {
|
|
425
|
+
const optionIsSelected = value.el.selected;
|
|
426
|
+
const cb = <HTMLInputElement>value.optionEl.querySelector('input[type="checkbox"]');
|
|
427
|
+
if (cb) cb.checked = optionIsSelected;
|
|
428
|
+
if (optionIsSelected) {
|
|
429
|
+
this._activateOption(this.dropdownOptions, value.optionEl);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
value.optionEl.classList.remove('selected');
|
|
433
|
+
value.optionEl.ariaSelected = 'false'; // attr("aria-selected", 'false');
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
_activateOption(ul: HTMLElement, li: HTMLElement) {
|
|
439
|
+
if (!li) return;
|
|
440
|
+
if (!this.isMultiple) ul.querySelectorAll('li.selected').forEach(li => li.classList.remove('selected'));
|
|
441
|
+
li.classList.add('selected');
|
|
442
|
+
li.ariaSelected = 'true';
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
getSelectedValues() {
|
|
446
|
+
return this._getSelectedOptions().map((realOption) => realOption.value);
|
|
447
|
+
}
|
|
448
|
+
}
|