kmaterialize 2.3.3-1.0.21 → 2.3.3-1.0.23
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/components/air-datepicker/air-datepicker.js +152 -0
- package/components/alert/alert.js +54 -0
- package/components/button/buttons.js +220 -0
- package/components/card/cards.js +149 -0
- package/components/carousel/carousel.js +574 -0
- package/components/carousel/slider.js +340 -0
- package/components/chip/chips.js +341 -0
- package/components/collapsible/collapsible.js +156 -0
- package/components/color-input/color-input.js +166 -0
- package/components/datepicker/datepicker.js +1035 -0
- package/components/dialog/materialbox.js +377 -0
- package/components/dialog/modal.js +72 -0
- package/components/dropdown/dropdown.js +505 -0
- package/components/file-input/file-input.js +169 -0
- package/components/kanban/_kanban.scss +69 -0
- package/components/kanban/kanban.js +168 -0
- package/components/kanban/kanban.ts +57 -8
- package/components/loading/_loading.scss +68 -0
- package/components/loading/loading.ts +104 -0
- package/components/loading/loadingSpec.js +102 -0
- package/components/navigation-drawer/sidenav.js +454 -0
- package/components/number-input/number-input.js +68 -0
- package/components/password-input/password-input.js +49 -0
- package/components/popup/_popup.scss +106 -0
- package/components/popup/popup.ts +113 -0
- package/components/popup/popupSpec.js +140 -0
- package/components/search/autocomplete.js +470 -0
- package/components/slider/range.js +169 -0
- package/components/snackbar/toasts.js +244 -0
- package/components/tabs/tabs.js +289 -0
- package/components/textfield/forms.js +172 -0
- package/components/textfield/select.js +385 -0
- package/components/timepicker/timepicker.js +698 -0
- package/components/tom-select/tom-select-field.js +130 -0
- package/components/toolbar/toolbar.js +134 -0
- package/components/tooltip/tooltip.js +270 -0
- package/dist/css/materialize.colors.min.css +1 -1
- package/dist/css/materialize.css +322 -1
- package/dist/css/materialize.min.css +2 -2
- package/dist/css/materialize.min.css.map +1 -1
- package/dist/js/materialize.cjs.js +258 -42
- package/dist/js/materialize.d.ts +50 -3
- package/dist/js/materialize.js +258 -42
- package/dist/js/materialize.min.js +2 -2
- package/dist/js/materialize.mjs +257 -43
- package/package.json +6 -1
- package/sass/materialize.scss +2 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { Utils } from '../../src/utils';
|
|
2
|
+
import { Component } from '../../src/component';
|
|
3
|
+
const _defaults = {
|
|
4
|
+
indicators: true,
|
|
5
|
+
height: 400,
|
|
6
|
+
duration: 500,
|
|
7
|
+
interval: 6000,
|
|
8
|
+
pauseOnFocus: true,
|
|
9
|
+
pauseOnHover: true,
|
|
10
|
+
indicatorLabelFunc: null // Function which will generate a label for the indicators (ARIA)
|
|
11
|
+
};
|
|
12
|
+
export class Slider extends Component {
|
|
13
|
+
/** Index of current slide. */
|
|
14
|
+
activeIndex;
|
|
15
|
+
interval;
|
|
16
|
+
eventPause;
|
|
17
|
+
_slider;
|
|
18
|
+
_slides;
|
|
19
|
+
_activeSlide;
|
|
20
|
+
_indicators;
|
|
21
|
+
_hovered;
|
|
22
|
+
_focused;
|
|
23
|
+
_focusCurrent;
|
|
24
|
+
_sliderId;
|
|
25
|
+
constructor(el, options) {
|
|
26
|
+
super(el, options, Slider);
|
|
27
|
+
this.el['M_Slider'] = this;
|
|
28
|
+
this.options = {
|
|
29
|
+
...Slider.defaults,
|
|
30
|
+
...options
|
|
31
|
+
};
|
|
32
|
+
// init props
|
|
33
|
+
this.interval = null;
|
|
34
|
+
this.eventPause = false;
|
|
35
|
+
this._hovered = false;
|
|
36
|
+
this._focused = false;
|
|
37
|
+
this._focusCurrent = false;
|
|
38
|
+
// setup
|
|
39
|
+
this._slider = this.el.querySelector('.slides');
|
|
40
|
+
this._slides = Array.from(this._slider.querySelectorAll('li'));
|
|
41
|
+
this.activeIndex = this._slides.findIndex((li) => li.classList.contains('active'));
|
|
42
|
+
if (this.activeIndex !== -1) {
|
|
43
|
+
this._activeSlide = this._slides[this.activeIndex];
|
|
44
|
+
}
|
|
45
|
+
this._setSliderHeight();
|
|
46
|
+
// Sets element id if it does not have one
|
|
47
|
+
if (this._slider.hasAttribute('id'))
|
|
48
|
+
this._sliderId = this._slider.getAttribute('id');
|
|
49
|
+
else {
|
|
50
|
+
this._sliderId = 'slider-' + Utils.guid();
|
|
51
|
+
this._slider.setAttribute('id', this._sliderId);
|
|
52
|
+
}
|
|
53
|
+
const placeholderBase64 = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
|
54
|
+
// Set initial positions of captions
|
|
55
|
+
this._slides.forEach((slide) => {
|
|
56
|
+
// Caption
|
|
57
|
+
//const caption = <HTMLElement|null>slide.querySelector('.caption');
|
|
58
|
+
//if (caption) this._animateCaptionIn(caption, 0);
|
|
59
|
+
// Set Images as Background Images
|
|
60
|
+
const img = slide.querySelector('img');
|
|
61
|
+
if (img) {
|
|
62
|
+
if (img.src !== placeholderBase64) {
|
|
63
|
+
img.style.backgroundImage = 'url(' + img.src + ')';
|
|
64
|
+
img.src = placeholderBase64;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Sets slide as focusable by code
|
|
68
|
+
if (!slide.hasAttribute('tabindex'))
|
|
69
|
+
slide.setAttribute('tabindex', '-1');
|
|
70
|
+
// Removes initial visibility from "inactive" slides
|
|
71
|
+
slide.style.visibility = 'hidden';
|
|
72
|
+
});
|
|
73
|
+
this._setupIndicators();
|
|
74
|
+
// Show active slide
|
|
75
|
+
if (this._activeSlide) {
|
|
76
|
+
this._activeSlide.style.display = 'block';
|
|
77
|
+
this._activeSlide.style.visibility = 'visible';
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.activeIndex = 0;
|
|
81
|
+
this._slides[0].classList.add('active');
|
|
82
|
+
this._slides[0].style.visibility = 'visible';
|
|
83
|
+
this._activeSlide = this._slides[0];
|
|
84
|
+
this._animateSlide(this._slides[0], true);
|
|
85
|
+
// Update indicators
|
|
86
|
+
if (this.options.indicators) {
|
|
87
|
+
this._indicators[this.activeIndex].children[0].classList.add('active');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this._setupEventHandlers();
|
|
91
|
+
// auto scroll
|
|
92
|
+
this.start();
|
|
93
|
+
}
|
|
94
|
+
static get defaults() {
|
|
95
|
+
return _defaults;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Initializes instances of Slider.
|
|
99
|
+
* @param els HTML elements.
|
|
100
|
+
* @param options Component options.
|
|
101
|
+
*/
|
|
102
|
+
static init(els, options = {}) {
|
|
103
|
+
return super.init(els, options, Slider);
|
|
104
|
+
}
|
|
105
|
+
static getInstance(el) {
|
|
106
|
+
return el['M_Slider'];
|
|
107
|
+
}
|
|
108
|
+
destroy() {
|
|
109
|
+
this.pause();
|
|
110
|
+
this._removeIndicators();
|
|
111
|
+
this._removeEventHandlers();
|
|
112
|
+
this.el['M_Slider'] = undefined;
|
|
113
|
+
}
|
|
114
|
+
_setupEventHandlers() {
|
|
115
|
+
if (this.options.pauseOnFocus) {
|
|
116
|
+
this.el.addEventListener('focusin', this._handleAutoPauseFocus);
|
|
117
|
+
this.el.addEventListener('focusout', this._handleAutoStartFocus);
|
|
118
|
+
}
|
|
119
|
+
if (this.options.pauseOnHover) {
|
|
120
|
+
this.el.addEventListener('mouseenter', this._handleAutoPauseHover);
|
|
121
|
+
this.el.addEventListener('mouseleave', this._handleAutoStartHover);
|
|
122
|
+
}
|
|
123
|
+
if (this.options.indicators) {
|
|
124
|
+
this._indicators.forEach((el) => {
|
|
125
|
+
el.addEventListener('click', this._handleIndicatorClick);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
_removeEventHandlers() {
|
|
130
|
+
if (this.options.pauseOnFocus) {
|
|
131
|
+
this.el.removeEventListener('focusin', this._handleAutoPauseFocus);
|
|
132
|
+
this.el.removeEventListener('focusout', this._handleAutoStartFocus);
|
|
133
|
+
}
|
|
134
|
+
if (this.options.pauseOnHover) {
|
|
135
|
+
this.el.removeEventListener('mouseenter', this._handleAutoPauseHover);
|
|
136
|
+
this.el.removeEventListener('mouseleave', this._handleAutoStartHover);
|
|
137
|
+
}
|
|
138
|
+
if (this.options.indicators) {
|
|
139
|
+
this._indicators.forEach((el) => {
|
|
140
|
+
el.removeEventListener('click', this._handleIndicatorClick);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
_handleIndicatorClick = (e) => {
|
|
145
|
+
const el = e.target.parentElement;
|
|
146
|
+
const currIndex = [...el.parentNode.children].indexOf(el);
|
|
147
|
+
this._focusCurrent = true;
|
|
148
|
+
this.set(currIndex);
|
|
149
|
+
};
|
|
150
|
+
_handleAutoPauseHover = () => {
|
|
151
|
+
this._hovered = true;
|
|
152
|
+
if (this.interval != null) {
|
|
153
|
+
this._pause(true);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
_handleAutoPauseFocus = () => {
|
|
157
|
+
this._focused = true;
|
|
158
|
+
if (this.interval != null) {
|
|
159
|
+
this._pause(true);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
_handleAutoStartHover = () => {
|
|
163
|
+
this._hovered = false;
|
|
164
|
+
if (!(this.options.pauseOnFocus && this._focused) && this.eventPause) {
|
|
165
|
+
this.start();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
_handleAutoStartFocus = () => {
|
|
169
|
+
this._focused = false;
|
|
170
|
+
if (!(this.options.pauseOnHover && this._hovered) && this.eventPause) {
|
|
171
|
+
this.start();
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
_handleInterval = () => {
|
|
175
|
+
const activeElem = this._slider.querySelector('.active');
|
|
176
|
+
let newActiveIndex = [...activeElem.parentNode.children].indexOf(activeElem);
|
|
177
|
+
if (this._slides.length === newActiveIndex + 1)
|
|
178
|
+
newActiveIndex = 0; // loop to start
|
|
179
|
+
else
|
|
180
|
+
newActiveIndex += 1;
|
|
181
|
+
this.set(newActiveIndex);
|
|
182
|
+
};
|
|
183
|
+
_animateSlide(slide, isDirectionIn) {
|
|
184
|
+
let dx = 0, dy = 0;
|
|
185
|
+
// from
|
|
186
|
+
slide.style.opacity = isDirectionIn ? '0' : '1';
|
|
187
|
+
setTimeout(() => {
|
|
188
|
+
slide.style.transition = `opacity ${this.options.duration}ms ease`;
|
|
189
|
+
// to
|
|
190
|
+
slide.style.opacity = isDirectionIn ? '1' : '0';
|
|
191
|
+
}, 1);
|
|
192
|
+
// Caption
|
|
193
|
+
const caption = slide.querySelector('.caption');
|
|
194
|
+
if (!caption)
|
|
195
|
+
return;
|
|
196
|
+
if (caption.classList.contains('center-align'))
|
|
197
|
+
dy = -100;
|
|
198
|
+
else if (caption.classList.contains('right-align'))
|
|
199
|
+
dx = 100;
|
|
200
|
+
else if (caption.classList.contains('left-align'))
|
|
201
|
+
dx = -100;
|
|
202
|
+
// from
|
|
203
|
+
caption.style.opacity = isDirectionIn ? '0' : '1';
|
|
204
|
+
caption.style.transform = isDirectionIn ? `translate(${dx}px, ${dy}px)` : `translate(0, 0)`;
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
caption.style.transition = `opacity ${this.options.duration}ms ease, transform ${this.options.duration}ms ease`;
|
|
207
|
+
// to
|
|
208
|
+
caption.style.opacity = isDirectionIn ? '1' : '0';
|
|
209
|
+
caption.style.transform = isDirectionIn ? `translate(0, 0)` : `translate(${dx}px, ${dy}px)`;
|
|
210
|
+
}, this.options.duration); // delay
|
|
211
|
+
}
|
|
212
|
+
_setSliderHeight() {
|
|
213
|
+
// If fullscreen, do nothing
|
|
214
|
+
if (!this.el.classList.contains('fullscreen')) {
|
|
215
|
+
if (this.options.indicators) {
|
|
216
|
+
// Add height if indicators are present
|
|
217
|
+
this.el.style.height = this.options.height + 40 + 'px'; //.css('height', this.options.height + 40 + 'px');
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
this.el.style.height = this.options.height + 'px';
|
|
221
|
+
}
|
|
222
|
+
this._slider.style.height = this.options.height + 'px';
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
_setupIndicators() {
|
|
226
|
+
if (this.options.indicators) {
|
|
227
|
+
const ul = document.createElement('ul');
|
|
228
|
+
ul.classList.add('indicators');
|
|
229
|
+
const arrLi = [];
|
|
230
|
+
this._slides.forEach((el, i) => {
|
|
231
|
+
const label = this.options.indicatorLabelFunc
|
|
232
|
+
? this.options.indicatorLabelFunc.call(this, i + 1, i === 0)
|
|
233
|
+
: `${i + 1}`;
|
|
234
|
+
const li = document.createElement('li');
|
|
235
|
+
li.classList.add('indicator-item');
|
|
236
|
+
li.innerHTML = `<button type="button" class="indicator-item-btn" aria-label="${label}" aria-controls="${this._sliderId}"></button>`;
|
|
237
|
+
arrLi.push(li);
|
|
238
|
+
ul.append(li);
|
|
239
|
+
});
|
|
240
|
+
this.el.append(ul);
|
|
241
|
+
this._indicators = arrLi;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
_removeIndicators() {
|
|
245
|
+
this.el.querySelector('ul.indicators').remove(); //find('ul.indicators').remove();
|
|
246
|
+
}
|
|
247
|
+
set(index) {
|
|
248
|
+
// Wrap around indices.
|
|
249
|
+
if (index >= this._slides.length)
|
|
250
|
+
index = 0;
|
|
251
|
+
else if (index < 0)
|
|
252
|
+
index = this._slides.length - 1;
|
|
253
|
+
// Only do if index changes
|
|
254
|
+
if (this.activeIndex === index)
|
|
255
|
+
return;
|
|
256
|
+
this._activeSlide = this._slides[this.activeIndex];
|
|
257
|
+
const _caption = this._activeSlide.querySelector('.caption');
|
|
258
|
+
this._activeSlide.classList.remove('active');
|
|
259
|
+
// Enables every slide
|
|
260
|
+
this._slides.forEach((slide) => (slide.style.visibility = 'visible'));
|
|
261
|
+
//--- Hide active Slide + Caption
|
|
262
|
+
this._activeSlide.style.opacity = '0';
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
this._slides.forEach((slide) => {
|
|
265
|
+
if (slide.classList.contains('active'))
|
|
266
|
+
return;
|
|
267
|
+
slide.style.opacity = '0';
|
|
268
|
+
slide.style.transform = 'translate(0, 0)';
|
|
269
|
+
// Disables invisible slides (for assistive technologies)
|
|
270
|
+
slide.style.visibility = 'hidden';
|
|
271
|
+
});
|
|
272
|
+
}, this.options.duration);
|
|
273
|
+
// Hide active Caption
|
|
274
|
+
//this._animateCaptionIn(_caption, this.options.duration);
|
|
275
|
+
_caption.style.opacity = '0';
|
|
276
|
+
// Update indicators
|
|
277
|
+
if (this.options.indicators) {
|
|
278
|
+
const activeIndicator = this._indicators[this.activeIndex].children[0];
|
|
279
|
+
const nextIndicator = this._indicators[index].children[0];
|
|
280
|
+
activeIndicator.classList.remove('active');
|
|
281
|
+
nextIndicator.classList.add('active');
|
|
282
|
+
if (typeof this.options.indicatorLabelFunc === 'function') {
|
|
283
|
+
activeIndicator.ariaLabel = this.options.indicatorLabelFunc.call(this, this.activeIndex, false);
|
|
284
|
+
nextIndicator.ariaLabel = this.options.indicatorLabelFunc.call(this, index, true);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
//--- Show new Slide + Caption
|
|
288
|
+
this._animateSlide(this._slides[index], true);
|
|
289
|
+
this._slides[index].classList.add('active');
|
|
290
|
+
this.activeIndex = index;
|
|
291
|
+
// Reset interval, if allowed. This check prevents autostart
|
|
292
|
+
// when slider is paused, since it can be changed though indicators.
|
|
293
|
+
if (this.interval != null) {
|
|
294
|
+
this.start();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
_pause(fromEvent) {
|
|
298
|
+
clearInterval(this.interval);
|
|
299
|
+
this.eventPause = fromEvent;
|
|
300
|
+
this.interval = null;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Pause slider autoslide.
|
|
304
|
+
*/
|
|
305
|
+
pause = () => {
|
|
306
|
+
this._pause(false);
|
|
307
|
+
};
|
|
308
|
+
/**
|
|
309
|
+
* Start slider autoslide.
|
|
310
|
+
*/
|
|
311
|
+
start = () => {
|
|
312
|
+
clearInterval(this.interval);
|
|
313
|
+
this.interval = setInterval(this._handleInterval, this.options.duration + this.options.interval);
|
|
314
|
+
this.eventPause = false;
|
|
315
|
+
};
|
|
316
|
+
/**
|
|
317
|
+
* Move to next slider.
|
|
318
|
+
*/
|
|
319
|
+
next = () => {
|
|
320
|
+
let newIndex = this.activeIndex + 1;
|
|
321
|
+
// Wrap around indices.
|
|
322
|
+
if (newIndex >= this._slides.length)
|
|
323
|
+
newIndex = 0;
|
|
324
|
+
else if (newIndex < 0)
|
|
325
|
+
newIndex = this._slides.length - 1;
|
|
326
|
+
this.set(newIndex);
|
|
327
|
+
};
|
|
328
|
+
/**
|
|
329
|
+
* Move to prev slider.
|
|
330
|
+
*/
|
|
331
|
+
prev = () => {
|
|
332
|
+
let newIndex = this.activeIndex - 1;
|
|
333
|
+
// Wrap around indices.
|
|
334
|
+
if (newIndex >= this._slides.length)
|
|
335
|
+
newIndex = 0;
|
|
336
|
+
else if (newIndex < 0)
|
|
337
|
+
newIndex = this._slides.length - 1;
|
|
338
|
+
this.set(newIndex);
|
|
339
|
+
};
|
|
340
|
+
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import { Utils } from '../../src/utils';
|
|
3
|
+
import { Autocomplete } from '../search/autocomplete';
|
|
4
|
+
import { Component } from '../../src/component';
|
|
5
|
+
const _defaults = {
|
|
6
|
+
data: [],
|
|
7
|
+
placeholder: '',
|
|
8
|
+
secondaryPlaceholder: '',
|
|
9
|
+
closeIconClass: 'material-icons',
|
|
10
|
+
autocompleteOptions: {},
|
|
11
|
+
autocompleteOnly: false,
|
|
12
|
+
limit: Infinity,
|
|
13
|
+
allowUserInput: false,
|
|
14
|
+
onChipAdd: null,
|
|
15
|
+
onChipSelect: null,
|
|
16
|
+
onChipDelete: null
|
|
17
|
+
};
|
|
18
|
+
function gGetIndex(el) {
|
|
19
|
+
return [...el.parentNode.children].indexOf(el);
|
|
20
|
+
}
|
|
21
|
+
class Chips extends Component {
|
|
22
|
+
/** Array of the current chips data. */
|
|
23
|
+
chipsData;
|
|
24
|
+
/** If the chips has autocomplete enabled. */
|
|
25
|
+
hasAutocomplete;
|
|
26
|
+
/** Autocomplete instance, if any. */
|
|
27
|
+
autocomplete;
|
|
28
|
+
#input;
|
|
29
|
+
#label;
|
|
30
|
+
#chips;
|
|
31
|
+
static #keydown;
|
|
32
|
+
#selectedChip;
|
|
33
|
+
constructor(el, options) {
|
|
34
|
+
super(el, options, _a);
|
|
35
|
+
this.el['M_Chips'] = this;
|
|
36
|
+
this.options = {
|
|
37
|
+
..._a.defaults,
|
|
38
|
+
...options
|
|
39
|
+
};
|
|
40
|
+
this.el.classList.add('chips');
|
|
41
|
+
this.chipsData = [];
|
|
42
|
+
this.#chips = [];
|
|
43
|
+
// Render initial chips
|
|
44
|
+
if (this.options.data.length) {
|
|
45
|
+
this.chipsData = this.options.data;
|
|
46
|
+
this.#renderChips();
|
|
47
|
+
}
|
|
48
|
+
// Render input element, setup event handlers
|
|
49
|
+
if (this.options.allowUserInput) {
|
|
50
|
+
this.#setupLabel();
|
|
51
|
+
this.el.classList.add('input-field');
|
|
52
|
+
this.#setupInput();
|
|
53
|
+
this.#setupEventHandlers();
|
|
54
|
+
// move input to end
|
|
55
|
+
this.el.append(this.#input);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
static get defaults() {
|
|
59
|
+
return _defaults;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Initializes instances of Chips.
|
|
63
|
+
* @param els HTML elements.
|
|
64
|
+
* @param options Component options.
|
|
65
|
+
*/
|
|
66
|
+
static init(els, options = {}) {
|
|
67
|
+
return super.init(els, options, _a);
|
|
68
|
+
}
|
|
69
|
+
static getInstance(el) {
|
|
70
|
+
return el['M_Chips'];
|
|
71
|
+
}
|
|
72
|
+
getData() {
|
|
73
|
+
return this.chipsData;
|
|
74
|
+
}
|
|
75
|
+
destroy() {
|
|
76
|
+
if (this.options.allowUserInput)
|
|
77
|
+
this.#removeEventHandlers();
|
|
78
|
+
this.#chips.forEach((c) => c.remove());
|
|
79
|
+
this.#chips = [];
|
|
80
|
+
this.el['M_Chips'] = undefined;
|
|
81
|
+
}
|
|
82
|
+
#setupEventHandlers() {
|
|
83
|
+
this.el.addEventListener('click', this.#handleChipClick);
|
|
84
|
+
// @todo why do we need this as document event listener, shouldn't we apply it to the element wrapper itself?
|
|
85
|
+
document.addEventListener('keydown', _a.#handleChipsKeydown);
|
|
86
|
+
document.addEventListener('keyup', _a.#handleChipsKeyup);
|
|
87
|
+
this.el.addEventListener('blur', _a.#handleChipsBlur, true);
|
|
88
|
+
this.#input.addEventListener('focus', this.#handleInputFocus);
|
|
89
|
+
this.#input.addEventListener('blur', this.#handleInputBlur);
|
|
90
|
+
this.#input.addEventListener('keydown', this.#handleInputKeydown);
|
|
91
|
+
}
|
|
92
|
+
#removeEventHandlers() {
|
|
93
|
+
this.el.removeEventListener('click', this.#handleChipClick);
|
|
94
|
+
document.removeEventListener('keydown', _a.#handleChipsKeydown);
|
|
95
|
+
document.removeEventListener('keyup', _a.#handleChipsKeyup);
|
|
96
|
+
this.el.removeEventListener('blur', _a.#handleChipsBlur, true);
|
|
97
|
+
this.#input.removeEventListener('focus', this.#handleInputFocus);
|
|
98
|
+
this.#input.removeEventListener('blur', this.#handleInputBlur);
|
|
99
|
+
this.#input.removeEventListener('keydown', this.#handleInputKeydown);
|
|
100
|
+
}
|
|
101
|
+
#handleChipClick = (e) => {
|
|
102
|
+
const _chip = e.target.closest('.chip');
|
|
103
|
+
const clickedClose = e.target.classList.contains('close');
|
|
104
|
+
if (_chip) {
|
|
105
|
+
const index = [..._chip.parentNode.children].indexOf(_chip);
|
|
106
|
+
if (clickedClose) {
|
|
107
|
+
this.deleteChip(index);
|
|
108
|
+
this.#input.focus();
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.selectChip(index);
|
|
112
|
+
}
|
|
113
|
+
// Default handle click to focus on input
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.#input.focus();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
static #handleChipsKeydown(e) {
|
|
120
|
+
_a.#keydown = true;
|
|
121
|
+
const chips = e.target.closest('.chips');
|
|
122
|
+
const chipsKeydown = e.target && chips;
|
|
123
|
+
// Don't handle keydown inputs on input and textarea
|
|
124
|
+
const tag = e.target.tagName;
|
|
125
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA' || !chipsKeydown)
|
|
126
|
+
return;
|
|
127
|
+
const currChips = chips['M_Chips'];
|
|
128
|
+
if (Utils.keys.BACKSPACE.includes(e.key) || Utils.keys.DELETE.includes(e.key)) {
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
let selectIndex = currChips.chipsData.length;
|
|
131
|
+
if (currChips.#selectedChip) {
|
|
132
|
+
const index = gGetIndex(currChips.#selectedChip);
|
|
133
|
+
currChips.deleteChip(index);
|
|
134
|
+
currChips.#selectedChip = null;
|
|
135
|
+
// Make sure selectIndex doesn't go negative
|
|
136
|
+
selectIndex = Math.max(index - 1, 0);
|
|
137
|
+
}
|
|
138
|
+
if (currChips.chipsData.length)
|
|
139
|
+
currChips.selectChip(selectIndex);
|
|
140
|
+
else
|
|
141
|
+
currChips.#input.focus();
|
|
142
|
+
}
|
|
143
|
+
else if (Utils.keys.ARROW_LEFT.includes(e.key)) {
|
|
144
|
+
if (currChips.#selectedChip) {
|
|
145
|
+
const selectIndex = gGetIndex(currChips.#selectedChip) - 1;
|
|
146
|
+
if (selectIndex < 0)
|
|
147
|
+
return;
|
|
148
|
+
currChips.selectChip(selectIndex);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (Utils.keys.ARROW_RIGHT.includes(e.key)) {
|
|
152
|
+
if (currChips.#selectedChip) {
|
|
153
|
+
const selectIndex = gGetIndex(currChips.#selectedChip) + 1;
|
|
154
|
+
if (selectIndex >= currChips.chipsData.length)
|
|
155
|
+
currChips.#input.focus();
|
|
156
|
+
else
|
|
157
|
+
currChips.selectChip(selectIndex);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
static #handleChipsKeyup() {
|
|
162
|
+
_a.#keydown = false;
|
|
163
|
+
}
|
|
164
|
+
static #handleChipsBlur(e) {
|
|
165
|
+
if (!_a.#keydown && document.hidden) {
|
|
166
|
+
const chips = e.target.closest('.chips');
|
|
167
|
+
const currChips = chips['M_Chips'];
|
|
168
|
+
currChips.#selectedChip = null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
#handleInputFocus = () => {
|
|
172
|
+
this.el.classList.add('focus');
|
|
173
|
+
};
|
|
174
|
+
#handleInputBlur = () => {
|
|
175
|
+
this.el.classList.remove('focus');
|
|
176
|
+
};
|
|
177
|
+
#handleInputKeydown = (e) => {
|
|
178
|
+
_a.#keydown = true;
|
|
179
|
+
if (Utils.keys.ENTER.includes(e.key)) {
|
|
180
|
+
// Override enter if autocompleting.
|
|
181
|
+
if (this.hasAutocomplete && this.autocomplete && this.autocomplete.isOpen) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
if (!this.hasAutocomplete || (this.hasAutocomplete && !this.options.autocompleteOnly)) {
|
|
186
|
+
this.addChip({ id: this.#input.value });
|
|
187
|
+
}
|
|
188
|
+
this.#input.value = '';
|
|
189
|
+
}
|
|
190
|
+
else if ((Utils.keys.BACKSPACE.includes(e.key) || Utils.keys.ARROW_LEFT.includes(e.key)) &&
|
|
191
|
+
this.#input.value === '' &&
|
|
192
|
+
this.chipsData.length) {
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
this.selectChip(this.chipsData.length - 1);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
#renderChip(chip) {
|
|
198
|
+
if (!chip.id)
|
|
199
|
+
return;
|
|
200
|
+
const renderedChip = document.createElement('li');
|
|
201
|
+
renderedChip.classList.add('chip');
|
|
202
|
+
renderedChip.innerText = chip.text || chip.id;
|
|
203
|
+
// attach image if needed
|
|
204
|
+
if (chip.image) {
|
|
205
|
+
const img = document.createElement('img');
|
|
206
|
+
img.setAttribute('src', chip.image);
|
|
207
|
+
renderedChip.insertBefore(img, renderedChip.firstChild);
|
|
208
|
+
}
|
|
209
|
+
if (this.options.allowUserInput) {
|
|
210
|
+
const closeButton = document.createElement('button');
|
|
211
|
+
closeButton.classList.add(this.options.closeIconClass, 'close');
|
|
212
|
+
closeButton.innerText = 'close';
|
|
213
|
+
renderedChip.appendChild(closeButton);
|
|
214
|
+
}
|
|
215
|
+
return renderedChip;
|
|
216
|
+
}
|
|
217
|
+
#renderChips() {
|
|
218
|
+
this.#chips = []; //.remove();
|
|
219
|
+
for (let i = 0; i < this.chipsData.length; i++) {
|
|
220
|
+
const chipElem = this.#renderChip(this.chipsData[i]);
|
|
221
|
+
this.el.appendChild(chipElem);
|
|
222
|
+
this.#chips.push(chipElem);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
#setupAutocomplete() {
|
|
226
|
+
this.options.autocompleteOptions.onAutocomplete = (items) => {
|
|
227
|
+
if (items.length > 0)
|
|
228
|
+
this.addChip({
|
|
229
|
+
id: items[0].id,
|
|
230
|
+
text: items[0].text,
|
|
231
|
+
image: items[0].image
|
|
232
|
+
});
|
|
233
|
+
this.#input.value = '';
|
|
234
|
+
this.#input.focus();
|
|
235
|
+
};
|
|
236
|
+
this.autocomplete = Autocomplete.init(this.#input, this.options.autocompleteOptions);
|
|
237
|
+
}
|
|
238
|
+
#setupInput() {
|
|
239
|
+
this.#input = this.el.querySelector('input');
|
|
240
|
+
if (!this.#input) {
|
|
241
|
+
this.#input = document.createElement('input');
|
|
242
|
+
this.el.append(this.#input);
|
|
243
|
+
}
|
|
244
|
+
this.#input.classList.add('input');
|
|
245
|
+
this.hasAutocomplete = Object.keys(this.options.autocompleteOptions).length > 0;
|
|
246
|
+
// Setup autocomplete if needed
|
|
247
|
+
if (this.hasAutocomplete)
|
|
248
|
+
this.#setupAutocomplete();
|
|
249
|
+
this.#setPlaceholder();
|
|
250
|
+
// Set input id
|
|
251
|
+
if (!this.#input.getAttribute('id'))
|
|
252
|
+
this.#input.setAttribute('id', Utils.guid());
|
|
253
|
+
}
|
|
254
|
+
#setupLabel() {
|
|
255
|
+
this.#label = this.el.querySelector('label');
|
|
256
|
+
if (this.#label)
|
|
257
|
+
this.#label.setAttribute('for', this.#input.getAttribute('id'));
|
|
258
|
+
}
|
|
259
|
+
#setPlaceholder() {
|
|
260
|
+
if (this.chipsData !== undefined && !this.chipsData.length && this.options.placeholder) {
|
|
261
|
+
this.#input.placeholder = this.options.placeholder;
|
|
262
|
+
}
|
|
263
|
+
else if ((this.chipsData === undefined || !!this.chipsData.length) &&
|
|
264
|
+
this.options.secondaryPlaceholder) {
|
|
265
|
+
this.#input.placeholder = this.options.secondaryPlaceholder;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
#isValidAndNotExist(chip) {
|
|
269
|
+
const isValid = !!chip.id;
|
|
270
|
+
const doesNotExist = !this.chipsData.some((item) => item.id == chip.id);
|
|
271
|
+
return isValid && doesNotExist;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Add chip to input.
|
|
275
|
+
* @param chip Chip data object
|
|
276
|
+
*/
|
|
277
|
+
addChip(chip) {
|
|
278
|
+
if (!this.#isValidAndNotExist(chip) || this.chipsData.length >= this.options.limit)
|
|
279
|
+
return;
|
|
280
|
+
const renderedChip = this.#renderChip(chip);
|
|
281
|
+
this.#chips.push(renderedChip);
|
|
282
|
+
this.chipsData.push(chip);
|
|
283
|
+
//$(this._input).before(renderedChip);
|
|
284
|
+
this.#input.before(renderedChip);
|
|
285
|
+
this.#setPlaceholder();
|
|
286
|
+
// fire chipAdd callback
|
|
287
|
+
if (typeof this.options.onChipAdd === 'function') {
|
|
288
|
+
this.options.onChipAdd(this.el, renderedChip);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Delete nth chip.
|
|
293
|
+
* @param chipIndex Index of chip
|
|
294
|
+
*/
|
|
295
|
+
deleteChip(chipIndex) {
|
|
296
|
+
const chip = this.#chips[chipIndex];
|
|
297
|
+
this.#chips[chipIndex].remove();
|
|
298
|
+
this.#chips.splice(chipIndex, 1);
|
|
299
|
+
this.chipsData.splice(chipIndex, 1);
|
|
300
|
+
this.#setPlaceholder();
|
|
301
|
+
// fire chipDelete callback
|
|
302
|
+
if (typeof this.options.onChipDelete === 'function') {
|
|
303
|
+
this.options.onChipDelete(this.el, chip);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Select nth chip.
|
|
308
|
+
* @param chipIndex Index of chip
|
|
309
|
+
*/
|
|
310
|
+
selectChip(chipIndex) {
|
|
311
|
+
const chip = this.#chips[chipIndex];
|
|
312
|
+
this.#selectedChip = chip;
|
|
313
|
+
chip.focus();
|
|
314
|
+
// fire chipSelect callback
|
|
315
|
+
if (typeof this.options.onChipSelect === 'function') {
|
|
316
|
+
this.options.onChipSelect(this.el, chip);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
static Init() {
|
|
320
|
+
if (typeof document !== 'undefined')
|
|
321
|
+
// Handle removal of static chips.
|
|
322
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
323
|
+
const chips = document.querySelectorAll('.chips');
|
|
324
|
+
chips.forEach((el) => {
|
|
325
|
+
// if (el && (el['M_Chips == undefined) return;
|
|
326
|
+
el.addEventListener('click', (e) => {
|
|
327
|
+
if (e.target.classList.contains('close')) {
|
|
328
|
+
const chip = e.target.closest('.chip');
|
|
329
|
+
if (chip)
|
|
330
|
+
chip.remove();
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
static {
|
|
337
|
+
this.#keydown = false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
_a = Chips;
|
|
341
|
+
export { Chips };
|