@lemonadejs/dropdown 3.1.9 → 3.1.12
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/README.md +114 -100
- package/dist/index.d.ts +84 -82
- package/dist/index.js +805 -778
- package/dist/react.d.ts +15 -15
- package/dist/react.js +36 -36
- package/dist/style.css +307 -307
- package/dist/vue.d.ts +14 -14
- package/dist/vue.js +45 -45
- package/package.json +23 -23
package/dist/index.js
CHANGED
|
@@ -1,779 +1,806 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Implementar o page up and down
|
|
3
|
-
* botao reset e done
|
|
4
|
-
* traducoes
|
|
5
|
-
*/
|
|
6
|
-
if (!lemonade && typeof (require) === 'function') {
|
|
7
|
-
var lemonade = require('lemonadejs');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (!Modal && typeof (require) === 'function') {
|
|
11
|
-
var Modal = require('@lemonadejs/modal');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
; (function (global, factory) {
|
|
15
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}(this, (function () {
|
|
19
|
-
|
|
20
|
-
// Default row height
|
|
21
|
-
let defaultRowHeight = 24;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Compare two arrays to see if contains exact the same elements
|
|
25
|
-
* @param {number|number[]} a1
|
|
26
|
-
* @param {number|number[]} a2
|
|
27
|
-
*/
|
|
28
|
-
const compareValues = function (a1, a2) {
|
|
29
|
-
if (!
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
if (!
|
|
33
|
-
if (a1 === a2) {
|
|
34
|
-
return true;
|
|
35
|
-
} else {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
let i = a1.length;
|
|
40
|
-
if (i !== a2.length) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
while (i--) {
|
|
44
|
-
if (a1[i] !== a2[i]) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const lazyLoading = function(self) {
|
|
53
|
-
/**
|
|
54
|
-
* Get the position from top of a row by its index
|
|
55
|
-
* @param item
|
|
56
|
-
* @returns {number}
|
|
57
|
-
*/
|
|
58
|
-
const getRowPosition = function(item) {
|
|
59
|
-
// Position from top
|
|
60
|
-
let top = 0;
|
|
61
|
-
if (item) {
|
|
62
|
-
let items = self.rows;
|
|
63
|
-
if (items && items.length) {
|
|
64
|
-
let index = self.rows.indexOf(item);
|
|
65
|
-
// Go through the items
|
|
66
|
-
for (let j = 0; j < index; j++) {
|
|
67
|
-
top += items[j].height || defaultRowHeight;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return top;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const updateScroll = function() {
|
|
75
|
-
let items = self.rows;
|
|
76
|
-
if (items) {
|
|
77
|
-
// Before control
|
|
78
|
-
let before = true;
|
|
79
|
-
// Total of items in the container
|
|
80
|
-
let numOfItems = items.length;
|
|
81
|
-
// Position from top
|
|
82
|
-
let height = 0;
|
|
83
|
-
// Size of the adjustment
|
|
84
|
-
let size = 0;
|
|
85
|
-
// Go through the items
|
|
86
|
-
for (let j = 0; j < numOfItems; j++) {
|
|
87
|
-
let h = items[j].height || defaultRowHeight;
|
|
88
|
-
// Height
|
|
89
|
-
height += h;
|
|
90
|
-
// Start tracking all items as before
|
|
91
|
-
if (items[j] === self.result[0]) {
|
|
92
|
-
before = false;
|
|
93
|
-
}
|
|
94
|
-
// Adjustment
|
|
95
|
-
if (before) {
|
|
96
|
-
size += h;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// Update height
|
|
100
|
-
scroll.style.height = height + 'px';
|
|
101
|
-
// Adjust scroll position
|
|
102
|
-
return size;
|
|
103
|
-
}
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const getVisibleRows = function(reset) {
|
|
108
|
-
let items = self.rows;
|
|
109
|
-
if (items) {
|
|
110
|
-
let adjust;
|
|
111
|
-
// Total of items in the container
|
|
112
|
-
let numOfItems = items.length;
|
|
113
|
-
// Get the position from top
|
|
114
|
-
let y = el.scrollTop;
|
|
115
|
-
// Get the height
|
|
116
|
-
let h = null;
|
|
117
|
-
if (self.type === 'searchbar' || self.type === 'picker') {
|
|
118
|
-
// Priority should be the size used on the viewport
|
|
119
|
-
h = y + (el.offsetHeight || self.height);
|
|
120
|
-
} else {
|
|
121
|
-
// Priority is the height define during initialization
|
|
122
|
-
h = y + (self.height || el.offsetHeight);
|
|
123
|
-
}
|
|
124
|
-
// Go through the items
|
|
125
|
-
let rows = [];
|
|
126
|
-
// Height
|
|
127
|
-
let height = 0;
|
|
128
|
-
// Go through all items
|
|
129
|
-
for (let j = 0; j < numOfItems; j++) {
|
|
130
|
-
if (items[j].visible !== false) {
|
|
131
|
-
// Height
|
|
132
|
-
let rowHeight = items[j].height || defaultRowHeight;
|
|
133
|
-
// Return on partial width
|
|
134
|
-
if (height + rowHeight > y && height < h) {
|
|
135
|
-
rows.push(items[j]);
|
|
136
|
-
}
|
|
137
|
-
height += rowHeight;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Update visible rows
|
|
142
|
-
if (reset || !
|
|
143
|
-
// Render the items
|
|
144
|
-
self.result = rows;
|
|
145
|
-
// Adjust scroll height
|
|
146
|
-
let adjustScroll = reset;
|
|
147
|
-
// Adjust scrolling
|
|
148
|
-
for (let i = 0; i < rows.length; i++) {
|
|
149
|
-
// Item
|
|
150
|
-
let item = rows[i];
|
|
151
|
-
// Item height
|
|
152
|
-
let h = item.el.offsetHeight;
|
|
153
|
-
// Update row height
|
|
154
|
-
if (!
|
|
155
|
-
// Keep item height
|
|
156
|
-
item.height = h;
|
|
157
|
-
// Adjust total height
|
|
158
|
-
adjustScroll = true;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Update scroll if the height of one element has been changed
|
|
163
|
-
if (adjustScroll) {
|
|
164
|
-
// Adjust the scroll height
|
|
165
|
-
adjust = updateScroll();
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Adjust position of the first element
|
|
170
|
-
let position = getRowPosition(self.result[0]);
|
|
171
|
-
let diff = position - el.scrollTop;
|
|
172
|
-
if (diff > 0) {
|
|
173
|
-
diff = 0;
|
|
174
|
-
}
|
|
175
|
-
self.container.style.top = diff + 'px';
|
|
176
|
-
|
|
177
|
-
return adjust;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Move the position to the top and re-render based on the scroll
|
|
183
|
-
* @param reset
|
|
184
|
-
*/
|
|
185
|
-
const render = function (reset) {
|
|
186
|
-
// Move scroll to the top
|
|
187
|
-
el.scrollTop = 0;
|
|
188
|
-
// Reset scroll
|
|
189
|
-
updateScroll();
|
|
190
|
-
// Append first batch
|
|
191
|
-
getVisibleRows(reset);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Will adjust the items based on the scroll position offset
|
|
196
|
-
*/
|
|
197
|
-
self.adjustPosition = function(item) {
|
|
198
|
-
if (item.el) {
|
|
199
|
-
let h = item.el.offsetHeight;
|
|
200
|
-
let calc = item.el.offsetTop + h;
|
|
201
|
-
if (calc > el.offsetHeight) {
|
|
202
|
-
let size = calc - el.offsetHeight;
|
|
203
|
-
if (size < h) {
|
|
204
|
-
size = h;
|
|
205
|
-
}
|
|
206
|
-
el.scrollTop -= -1 * size;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Controls
|
|
212
|
-
const scrollControls = function() {
|
|
213
|
-
getVisibleRows(false);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Element for scrolling
|
|
217
|
-
let el = self.container.parentNode;
|
|
218
|
-
el.classList.add('lm-lazy');
|
|
219
|
-
// Div to represent the height of the content
|
|
220
|
-
const scroll = document.createElement('div');
|
|
221
|
-
scroll.classList.add('lm-lazy-scroll');
|
|
222
|
-
// Force the height and add scrolling
|
|
223
|
-
el.appendChild(scroll);
|
|
224
|
-
el.addEventListener('scroll', scrollControls);
|
|
225
|
-
el.addEventListener('wheel', scrollControls);
|
|
226
|
-
self.container.classList.add('lm-lazy-items');
|
|
227
|
-
|
|
228
|
-
self.goto = function(item) {
|
|
229
|
-
el.scrollTop = getRowPosition(item);
|
|
230
|
-
let adjust = getVisibleRows(false);
|
|
231
|
-
if (adjust) {
|
|
232
|
-
el.scrollTop = adjust;
|
|
233
|
-
// Last adjust on the visible rows
|
|
234
|
-
getVisibleRows(false);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return (prop) => {
|
|
239
|
-
if (prop === 'rows') {
|
|
240
|
-
render(true);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const Dropdown = function () {
|
|
246
|
-
let self = this;
|
|
247
|
-
// Internal value controllers
|
|
248
|
-
let value = [];
|
|
249
|
-
// Cursor
|
|
250
|
-
let cursor = null;
|
|
251
|
-
// Control events
|
|
252
|
-
let ignoreEvents = false;
|
|
253
|
-
// Default widht
|
|
254
|
-
if (!
|
|
255
|
-
self.width = 260;
|
|
256
|
-
}
|
|
257
|
-
// Lazy loading global instance
|
|
258
|
-
let lazyloading = null;
|
|
259
|
-
// Custom events defined by the user
|
|
260
|
-
let onload = self.onload;
|
|
261
|
-
let onchange = self.onchange;
|
|
262
|
-
|
|
263
|
-
// Cursor controllers
|
|
264
|
-
const setCursor = function(index, force) {
|
|
265
|
-
let item = self.rows[index];
|
|
266
|
-
|
|
267
|
-
if (typeof(item) !== 'undefined') {
|
|
268
|
-
// Set cursor number
|
|
269
|
-
cursor = index;
|
|
270
|
-
// Set visual indication
|
|
271
|
-
item.cursor = true;
|
|
272
|
-
// Go to the item on the scroll in case the item is not on the viewport
|
|
273
|
-
if (!
|
|
274
|
-
// Goto method
|
|
275
|
-
self.goto(item);
|
|
276
|
-
}
|
|
277
|
-
// Adjust cursor position
|
|
278
|
-
setTimeout(function() {
|
|
279
|
-
self.adjustPosition(item);
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const removeCursor = function(reset) {
|
|
285
|
-
if (cursor !== null) {
|
|
286
|
-
if (typeof(self.rows[cursor]) !== 'undefined') {
|
|
287
|
-
self.rows[cursor].cursor = false;
|
|
288
|
-
}
|
|
289
|
-
if (reset) {
|
|
290
|
-
// Cursor is null
|
|
291
|
-
cursor = null;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const moveCursor = function(direction, jump) {
|
|
297
|
-
// Remove cursor
|
|
298
|
-
removeCursor();
|
|
299
|
-
// Last item
|
|
300
|
-
let last = self.rows.length - 1;
|
|
301
|
-
if (jump) {
|
|
302
|
-
if (direction < 0) {
|
|
303
|
-
cursor = 0;
|
|
304
|
-
} else {
|
|
305
|
-
cursor = last;
|
|
306
|
-
}
|
|
307
|
-
} else {
|
|
308
|
-
// Position
|
|
309
|
-
if (cursor === null) {
|
|
310
|
-
cursor = 0;
|
|
311
|
-
} else {
|
|
312
|
-
// Move previous
|
|
313
|
-
cursor = cursor + direction;
|
|
314
|
-
}
|
|
315
|
-
// Reach the boundaries
|
|
316
|
-
if (direction < 0) {
|
|
317
|
-
// Back to the last one
|
|
318
|
-
if (cursor < 0) {
|
|
319
|
-
cursor = last;
|
|
320
|
-
}
|
|
321
|
-
} else {
|
|
322
|
-
// Back to the first one
|
|
323
|
-
if (cursor > last) {
|
|
324
|
-
cursor = 0;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
// Add cursor
|
|
329
|
-
setCursor(cursor);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const setData = function() {
|
|
333
|
-
// Estimate width
|
|
334
|
-
let width = self.width;
|
|
335
|
-
// Re-order to make sure groups are in sequence
|
|
336
|
-
if (self.data && self.data.length) {
|
|
337
|
-
self.data.sort((a, b) => {
|
|
338
|
-
// Compare groups
|
|
339
|
-
if (a.group && b.group) {
|
|
340
|
-
return a.group.localeCompare(b.group);
|
|
341
|
-
}
|
|
342
|
-
return 0;
|
|
343
|
-
});
|
|
344
|
-
let group = '';
|
|
345
|
-
// Define group headers
|
|
346
|
-
self.data.map((v) => {
|
|
347
|
-
// Compare groups
|
|
348
|
-
if (v && v.group && v.group !== group) {
|
|
349
|
-
v.header = true;
|
|
350
|
-
group = v.group;
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
// Width && values
|
|
354
|
-
self.data.map(function (s) {
|
|
355
|
-
// Estimated width of the element
|
|
356
|
-
if (s.text) {
|
|
357
|
-
width = Math.max(width, s.text.length * 8);
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
// Adjust the width
|
|
362
|
-
let w = self.input.offsetWidth;
|
|
363
|
-
if (width < w) {
|
|
364
|
-
width = w;
|
|
365
|
-
}
|
|
366
|
-
// Estimated with based on the text
|
|
367
|
-
if (self.width < width) {
|
|
368
|
-
self.width = width;
|
|
369
|
-
}
|
|
370
|
-
self.el.style.width = self.width + 'px';
|
|
371
|
-
// Height
|
|
372
|
-
self.height = 400;
|
|
373
|
-
// Animation for mobile
|
|
374
|
-
if (document.documentElement.clientWidth < 800) {
|
|
375
|
-
self.animation = true;
|
|
376
|
-
}
|
|
377
|
-
// Data to be listed
|
|
378
|
-
self.rows = self.data;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const updateLabel = function() {
|
|
382
|
-
if (value && value.length) {
|
|
383
|
-
self.input.textContent = value.filter(v => v.selected).map(i => i.text).join('; ');
|
|
384
|
-
} else {
|
|
385
|
-
self.input.textContent = '';
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const setValue = function(v) {
|
|
390
|
-
// Values
|
|
391
|
-
let newValue;
|
|
392
|
-
if (!
|
|
393
|
-
if (typeof(v) === 'string') {
|
|
394
|
-
newValue = v.split(';');
|
|
395
|
-
} else {
|
|
396
|
-
newValue = [v];
|
|
397
|
-
}
|
|
398
|
-
} else {
|
|
399
|
-
newValue = v;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Width && values
|
|
403
|
-
value = [];
|
|
404
|
-
|
|
405
|
-
if (Array.isArray(self.data)) {
|
|
406
|
-
self.data.map(function(s) {
|
|
407
|
-
// Select values
|
|
408
|
-
if (newValue.indexOf(s.value) !== -1) {
|
|
409
|
-
s.selected = true;
|
|
410
|
-
value.push(s);
|
|
411
|
-
} else {
|
|
412
|
-
s.selected = false;
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// Update label
|
|
418
|
-
updateLabel();
|
|
419
|
-
|
|
420
|
-
// Component onchange
|
|
421
|
-
if (typeof(onchange) === 'function') {
|
|
422
|
-
onchange.call(self, self, getValue());
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const getValue = function() {
|
|
427
|
-
if (self.multiple) {
|
|
428
|
-
if (value && value.length) {
|
|
429
|
-
return value.filter(v => v.selected).map(i => i.value);
|
|
430
|
-
}
|
|
431
|
-
return [];
|
|
432
|
-
} else {
|
|
433
|
-
if (value && value.length) {
|
|
434
|
-
return value[0].value;
|
|
435
|
-
} else {
|
|
436
|
-
return '';
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const onclose = function() {
|
|
442
|
-
// Cursor
|
|
443
|
-
removeCursor(true);
|
|
444
|
-
// Reset search
|
|
445
|
-
if (self.autocomplete) {
|
|
446
|
-
// Go to begin of the data
|
|
447
|
-
self.rows = self.data;
|
|
448
|
-
// Remove editable attribute
|
|
449
|
-
self.input.removeAttribute('contenteditable');
|
|
450
|
-
// Clear input
|
|
451
|
-
self.input.textContent = '';
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Current value
|
|
455
|
-
let newValue = getValue();
|
|
456
|
-
|
|
457
|
-
// If that is different from the component value
|
|
458
|
-
if (!
|
|
459
|
-
self.value = newValue;
|
|
460
|
-
} else {
|
|
461
|
-
// Update label
|
|
462
|
-
updateLabel();
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Identify the new state of the dropdown
|
|
466
|
-
self.state = false;
|
|
467
|
-
|
|
468
|
-
if (typeof(self.onclose) === 'function') {
|
|
469
|
-
self.onclose(self);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const onopen = function() {
|
|
474
|
-
self.state = true;
|
|
475
|
-
// Value
|
|
476
|
-
let v = value[value.length-1];
|
|
477
|
-
// Make sure goes back to the top of the scroll
|
|
478
|
-
if (self.container.parentNode.scrollTop > 0) {
|
|
479
|
-
self.container.parentNode.scrollTop = 0;
|
|
480
|
-
}
|
|
481
|
-
// Move to the correct position
|
|
482
|
-
if (v) {
|
|
483
|
-
// Mark the position of the cursor to the same element
|
|
484
|
-
setCursor(self.rows.indexOf(v), true);
|
|
485
|
-
}
|
|
486
|
-
// Prepare search field
|
|
487
|
-
if (self.autocomplete) {
|
|
488
|
-
// Clear input
|
|
489
|
-
self.input.textContent = '';
|
|
490
|
-
// Editable
|
|
491
|
-
self.input.setAttribute('contenteditable', true);
|
|
492
|
-
// Focus on the item
|
|
493
|
-
self.input.focus();
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
if (typeof(self.onopen) === 'function') {
|
|
497
|
-
self.onopen(self);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
self.add = async function(e) {
|
|
503
|
-
if (!
|
|
504
|
-
return false;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
e.preventDefault();
|
|
508
|
-
|
|
509
|
-
// New item
|
|
510
|
-
let s = {
|
|
511
|
-
text: self.input.textContent,
|
|
512
|
-
value: self.input.textContent,
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Event
|
|
516
|
-
if (typeof(self.onbeforeinsert) === 'function') {
|
|
517
|
-
let elClass = self.el.classList;
|
|
518
|
-
elClass.add('lm-dropdown-loading');
|
|
519
|
-
let ret = await self.onbeforeinsert(self, s);
|
|
520
|
-
elClass.remove('lm-dropdown-loading');
|
|
521
|
-
if (ret === false) {
|
|
522
|
-
return;
|
|
523
|
-
} else if (ret) {
|
|
524
|
-
s = ret;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
// Process the data
|
|
529
|
-
self.data.push(s);
|
|
530
|
-
// Select the new item
|
|
531
|
-
self.select(e, s);
|
|
532
|
-
// Close dropdown
|
|
533
|
-
self.close();
|
|
534
|
-
|
|
535
|
-
// Event
|
|
536
|
-
if (typeof(self.oninsert) === 'function') {
|
|
537
|
-
self.oninsert(self, s);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
self.search = function(e) {
|
|
542
|
-
if (self.state && self.autocomplete) {
|
|
543
|
-
// Filter options
|
|
544
|
-
let data;
|
|
545
|
-
if (!
|
|
546
|
-
data = self.data;
|
|
547
|
-
} else {
|
|
548
|
-
data = self.data.filter(item => {
|
|
549
|
-
return item.selected === true ||
|
|
550
|
-
(item.text.toLowerCase().includes(self.input.textContent.toLowerCase())) ||
|
|
551
|
-
(item.group && item.group.toLowerCase().includes(self.input.textContent.toLowerCase()));
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
// Cursor
|
|
555
|
-
removeCursor(true);
|
|
556
|
-
// Update the data from the dropdown
|
|
557
|
-
self.rows = data;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
self.open = function () {
|
|
562
|
-
if (self.modal && self.modal.closed) {
|
|
563
|
-
// Open the modal
|
|
564
|
-
self.modal.closed = false;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
self.close = function () {
|
|
569
|
-
// Close the modal
|
|
570
|
-
if (self.modal) {
|
|
571
|
-
self.modal.closed = true;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
self.toggle = function() {
|
|
576
|
-
if (self.modal) {
|
|
577
|
-
if (self.modal.closed) {
|
|
578
|
-
self.open();
|
|
579
|
-
} else {
|
|
580
|
-
self.close();
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
self.click = function(e) {
|
|
586
|
-
if (self.autocomplete) {
|
|
587
|
-
let x;
|
|
588
|
-
if (e.changedTouches && e.changedTouches[0]) {
|
|
589
|
-
x = e.changedTouches[0].clientX;
|
|
590
|
-
} else {
|
|
591
|
-
x = e.clientX;
|
|
592
|
-
}
|
|
593
|
-
if (e.target.offsetWidth - (x - e.target.offsetLeft) < 20) {
|
|
594
|
-
self.toggle();
|
|
595
|
-
} else {
|
|
596
|
-
self.open();
|
|
597
|
-
}
|
|
598
|
-
} else {
|
|
599
|
-
self.toggle();
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
self.select = function(e, s) {
|
|
604
|
-
if (s) {
|
|
605
|
-
if (self.multiple === true) {
|
|
606
|
-
let position = value.indexOf(s);
|
|
607
|
-
if (position === -1) {
|
|
608
|
-
value.push(s);
|
|
609
|
-
s.selected = true;
|
|
610
|
-
} else {
|
|
611
|
-
value.splice(position, 1);
|
|
612
|
-
s.selected = false;
|
|
613
|
-
}
|
|
614
|
-
} else {
|
|
615
|
-
if (value[0] === s) {
|
|
616
|
-
s.selected = !s.selected;
|
|
617
|
-
} else {
|
|
618
|
-
if (value[0]) {
|
|
619
|
-
value[0].selected = false;
|
|
620
|
-
}
|
|
621
|
-
s.selected = true;
|
|
622
|
-
}
|
|
623
|
-
if (s.selected) {
|
|
624
|
-
value = [s];
|
|
625
|
-
} else {
|
|
626
|
-
value = [];
|
|
627
|
-
}
|
|
628
|
-
// Close the modal
|
|
629
|
-
self.close();
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
self.getGroup = function() {
|
|
635
|
-
if (this.group && this.header) {
|
|
636
|
-
return this.group;
|
|
637
|
-
} else {
|
|
638
|
-
return '';
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
self.onload = function () {
|
|
643
|
-
if (self.type !== "inline") {
|
|
644
|
-
// Create modal instance
|
|
645
|
-
self.modal = {
|
|
646
|
-
closed: true,
|
|
647
|
-
focus: false,
|
|
648
|
-
width: self.width,
|
|
649
|
-
onopen: onopen,
|
|
650
|
-
onclose: onclose,
|
|
651
|
-
position: 'absolute',
|
|
652
|
-
'auto-adjust': true,
|
|
653
|
-
'auto-close': false,
|
|
654
|
-
};
|
|
655
|
-
// Generate modal
|
|
656
|
-
Modal(self.el.children[1], self.modal);
|
|
657
|
-
} else {
|
|
658
|
-
// For inline dropdown
|
|
659
|
-
self.el.setAttribute('tabindex', 0);
|
|
660
|
-
// Remove search
|
|
661
|
-
self.input.remove();
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (e.key === '
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Implementar o page up and down
|
|
3
|
+
* botao reset e done
|
|
4
|
+
* traducoes
|
|
5
|
+
*/
|
|
6
|
+
if (!lemonade && typeof (require) === 'function') {
|
|
7
|
+
var lemonade = require('lemonadejs');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!Modal && typeof (require) === 'function') {
|
|
11
|
+
var Modal = require('@lemonadejs/modal');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
; (function (global, factory) {
|
|
15
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
16
|
+
typeof define === 'function' && define.amd ? define(factory) :
|
|
17
|
+
global.Dropdown = factory();
|
|
18
|
+
}(this, (function () {
|
|
19
|
+
|
|
20
|
+
// Default row height
|
|
21
|
+
let defaultRowHeight = 24;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Compare two arrays to see if contains exact the same elements
|
|
25
|
+
* @param {number|number[]} a1
|
|
26
|
+
* @param {number|number[]} a2
|
|
27
|
+
*/
|
|
28
|
+
const compareValues = function (a1, a2) {
|
|
29
|
+
if (!a1 || !a2) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(a1) || !Array.isArray(a2)) {
|
|
33
|
+
if (a1 === a2) {
|
|
34
|
+
return true;
|
|
35
|
+
} else {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
let i = a1.length;
|
|
40
|
+
if (i !== a2.length) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
while (i--) {
|
|
44
|
+
if (a1[i] !== a2[i]) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const lazyLoading = function (self) {
|
|
53
|
+
/**
|
|
54
|
+
* Get the position from top of a row by its index
|
|
55
|
+
* @param item
|
|
56
|
+
* @returns {number}
|
|
57
|
+
*/
|
|
58
|
+
const getRowPosition = function (item) {
|
|
59
|
+
// Position from top
|
|
60
|
+
let top = 0;
|
|
61
|
+
if (item) {
|
|
62
|
+
let items = self.rows;
|
|
63
|
+
if (items && items.length) {
|
|
64
|
+
let index = self.rows.indexOf(item);
|
|
65
|
+
// Go through the items
|
|
66
|
+
for (let j = 0; j < index; j++) {
|
|
67
|
+
top += items[j].height || defaultRowHeight;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return top;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const updateScroll = function () {
|
|
75
|
+
let items = self.rows;
|
|
76
|
+
if (items) {
|
|
77
|
+
// Before control
|
|
78
|
+
let before = true;
|
|
79
|
+
// Total of items in the container
|
|
80
|
+
let numOfItems = items.length;
|
|
81
|
+
// Position from top
|
|
82
|
+
let height = 0;
|
|
83
|
+
// Size of the adjustment
|
|
84
|
+
let size = 0;
|
|
85
|
+
// Go through the items
|
|
86
|
+
for (let j = 0; j < numOfItems; j++) {
|
|
87
|
+
let h = items[j].height || defaultRowHeight;
|
|
88
|
+
// Height
|
|
89
|
+
height += h;
|
|
90
|
+
// Start tracking all items as before
|
|
91
|
+
if (items[j] === self.result[0]) {
|
|
92
|
+
before = false;
|
|
93
|
+
}
|
|
94
|
+
// Adjustment
|
|
95
|
+
if (before) {
|
|
96
|
+
size += h;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Update height
|
|
100
|
+
scroll.style.height = height + 'px';
|
|
101
|
+
// Adjust scroll position
|
|
102
|
+
return size;
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const getVisibleRows = function (reset) {
|
|
108
|
+
let items = self.rows;
|
|
109
|
+
if (items) {
|
|
110
|
+
let adjust;
|
|
111
|
+
// Total of items in the container
|
|
112
|
+
let numOfItems = items.length;
|
|
113
|
+
// Get the position from top
|
|
114
|
+
let y = el.scrollTop;
|
|
115
|
+
// Get the height
|
|
116
|
+
let h = null;
|
|
117
|
+
if (self.type === 'searchbar' || self.type === 'picker') {
|
|
118
|
+
// Priority should be the size used on the viewport
|
|
119
|
+
h = y + (el.offsetHeight || self.height);
|
|
120
|
+
} else {
|
|
121
|
+
// Priority is the height define during initialization
|
|
122
|
+
h = y + (self.height || el.offsetHeight);
|
|
123
|
+
}
|
|
124
|
+
// Go through the items
|
|
125
|
+
let rows = [];
|
|
126
|
+
// Height
|
|
127
|
+
let height = 0;
|
|
128
|
+
// Go through all items
|
|
129
|
+
for (let j = 0; j < numOfItems; j++) {
|
|
130
|
+
if (items[j].visible !== false) {
|
|
131
|
+
// Height
|
|
132
|
+
let rowHeight = items[j].height || defaultRowHeight;
|
|
133
|
+
// Return on partial width
|
|
134
|
+
if (height + rowHeight > y && height < h) {
|
|
135
|
+
rows.push(items[j]);
|
|
136
|
+
}
|
|
137
|
+
height += rowHeight;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Update visible rows
|
|
142
|
+
if (reset || !compareValues(rows, self.result)) {
|
|
143
|
+
// Render the items
|
|
144
|
+
self.result = rows;
|
|
145
|
+
// Adjust scroll height
|
|
146
|
+
let adjustScroll = reset;
|
|
147
|
+
// Adjust scrolling
|
|
148
|
+
for (let i = 0; i < rows.length; i++) {
|
|
149
|
+
// Item
|
|
150
|
+
let item = rows[i];
|
|
151
|
+
// Item height
|
|
152
|
+
let h = item.el.offsetHeight;
|
|
153
|
+
// Update row height
|
|
154
|
+
if (!item.height || h !== item.height) {
|
|
155
|
+
// Keep item height
|
|
156
|
+
item.height = h;
|
|
157
|
+
// Adjust total height
|
|
158
|
+
adjustScroll = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Update scroll if the height of one element has been changed
|
|
163
|
+
if (adjustScroll) {
|
|
164
|
+
// Adjust the scroll height
|
|
165
|
+
adjust = updateScroll();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Adjust position of the first element
|
|
170
|
+
let position = getRowPosition(self.result[0]);
|
|
171
|
+
let diff = position - el.scrollTop;
|
|
172
|
+
if (diff > 0) {
|
|
173
|
+
diff = 0;
|
|
174
|
+
}
|
|
175
|
+
self.container.style.top = diff + 'px';
|
|
176
|
+
|
|
177
|
+
return adjust;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Move the position to the top and re-render based on the scroll
|
|
183
|
+
* @param reset
|
|
184
|
+
*/
|
|
185
|
+
const render = function (reset) {
|
|
186
|
+
// Move scroll to the top
|
|
187
|
+
el.scrollTop = 0;
|
|
188
|
+
// Reset scroll
|
|
189
|
+
updateScroll();
|
|
190
|
+
// Append first batch
|
|
191
|
+
getVisibleRows(reset);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Will adjust the items based on the scroll position offset
|
|
196
|
+
*/
|
|
197
|
+
self.adjustPosition = function (item) {
|
|
198
|
+
if (item.el) {
|
|
199
|
+
let h = item.el.offsetHeight;
|
|
200
|
+
let calc = item.el.offsetTop + h;
|
|
201
|
+
if (calc > el.offsetHeight) {
|
|
202
|
+
let size = calc - el.offsetHeight;
|
|
203
|
+
if (size < h) {
|
|
204
|
+
size = h;
|
|
205
|
+
}
|
|
206
|
+
el.scrollTop -= -1 * size;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Controls
|
|
212
|
+
const scrollControls = function () {
|
|
213
|
+
getVisibleRows(false);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Element for scrolling
|
|
217
|
+
let el = self.container.parentNode;
|
|
218
|
+
el.classList.add('lm-lazy');
|
|
219
|
+
// Div to represent the height of the content
|
|
220
|
+
const scroll = document.createElement('div');
|
|
221
|
+
scroll.classList.add('lm-lazy-scroll');
|
|
222
|
+
// Force the height and add scrolling
|
|
223
|
+
el.appendChild(scroll);
|
|
224
|
+
el.addEventListener('scroll', scrollControls);
|
|
225
|
+
el.addEventListener('wheel', scrollControls);
|
|
226
|
+
self.container.classList.add('lm-lazy-items');
|
|
227
|
+
|
|
228
|
+
self.goto = function (item) {
|
|
229
|
+
el.scrollTop = getRowPosition(item);
|
|
230
|
+
let adjust = getVisibleRows(false);
|
|
231
|
+
if (adjust) {
|
|
232
|
+
el.scrollTop = adjust;
|
|
233
|
+
// Last adjust on the visible rows
|
|
234
|
+
getVisibleRows(false);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return (prop) => {
|
|
239
|
+
if (prop === 'rows') {
|
|
240
|
+
render(true);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const Dropdown = function () {
|
|
246
|
+
let self = this;
|
|
247
|
+
// Internal value controllers
|
|
248
|
+
let value = [];
|
|
249
|
+
// Cursor
|
|
250
|
+
let cursor = null;
|
|
251
|
+
// Control events
|
|
252
|
+
let ignoreEvents = false;
|
|
253
|
+
// Default widht
|
|
254
|
+
if (!self.width) {
|
|
255
|
+
self.width = 260;
|
|
256
|
+
}
|
|
257
|
+
// Lazy loading global instance
|
|
258
|
+
let lazyloading = null;
|
|
259
|
+
// Custom events defined by the user
|
|
260
|
+
let onload = self.onload;
|
|
261
|
+
let onchange = self.onchange;
|
|
262
|
+
|
|
263
|
+
// Cursor controllers
|
|
264
|
+
const setCursor = function (index, force) {
|
|
265
|
+
let item = self.rows[index];
|
|
266
|
+
|
|
267
|
+
if (typeof (item) !== 'undefined') {
|
|
268
|
+
// Set cursor number
|
|
269
|
+
cursor = index;
|
|
270
|
+
// Set visual indication
|
|
271
|
+
item.cursor = true;
|
|
272
|
+
// Go to the item on the scroll in case the item is not on the viewport
|
|
273
|
+
if (!(item.el && item.el.parentNode) || force === true) {
|
|
274
|
+
// Goto method
|
|
275
|
+
self.goto(item);
|
|
276
|
+
}
|
|
277
|
+
// Adjust cursor position
|
|
278
|
+
setTimeout(function () {
|
|
279
|
+
self.adjustPosition(item);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const removeCursor = function (reset) {
|
|
285
|
+
if (cursor !== null) {
|
|
286
|
+
if (typeof (self.rows[cursor]) !== 'undefined') {
|
|
287
|
+
self.rows[cursor].cursor = false;
|
|
288
|
+
}
|
|
289
|
+
if (reset) {
|
|
290
|
+
// Cursor is null
|
|
291
|
+
cursor = null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const moveCursor = function (direction, jump) {
|
|
297
|
+
// Remove cursor
|
|
298
|
+
removeCursor();
|
|
299
|
+
// Last item
|
|
300
|
+
let last = self.rows.length - 1;
|
|
301
|
+
if (jump) {
|
|
302
|
+
if (direction < 0) {
|
|
303
|
+
cursor = 0;
|
|
304
|
+
} else {
|
|
305
|
+
cursor = last;
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
// Position
|
|
309
|
+
if (cursor === null) {
|
|
310
|
+
cursor = 0;
|
|
311
|
+
} else {
|
|
312
|
+
// Move previous
|
|
313
|
+
cursor = cursor + direction;
|
|
314
|
+
}
|
|
315
|
+
// Reach the boundaries
|
|
316
|
+
if (direction < 0) {
|
|
317
|
+
// Back to the last one
|
|
318
|
+
if (cursor < 0) {
|
|
319
|
+
cursor = last;
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
// Back to the first one
|
|
323
|
+
if (cursor > last) {
|
|
324
|
+
cursor = 0;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Add cursor
|
|
329
|
+
setCursor(cursor);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const setData = function () {
|
|
333
|
+
// Estimate width
|
|
334
|
+
let width = self.width;
|
|
335
|
+
// Re-order to make sure groups are in sequence
|
|
336
|
+
if (self.data && self.data.length) {
|
|
337
|
+
self.data.sort((a, b) => {
|
|
338
|
+
// Compare groups
|
|
339
|
+
if (a.group && b.group) {
|
|
340
|
+
return a.group.localeCompare(b.group);
|
|
341
|
+
}
|
|
342
|
+
return 0;
|
|
343
|
+
});
|
|
344
|
+
let group = '';
|
|
345
|
+
// Define group headers
|
|
346
|
+
self.data.map((v) => {
|
|
347
|
+
// Compare groups
|
|
348
|
+
if (v && v.group && v.group !== group) {
|
|
349
|
+
v.header = true;
|
|
350
|
+
group = v.group;
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
// Width && values
|
|
354
|
+
self.data.map(function (s) {
|
|
355
|
+
// Estimated width of the element
|
|
356
|
+
if (s.text) {
|
|
357
|
+
width = Math.max(width, s.text.length * 8);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
// Adjust the width
|
|
362
|
+
let w = self.input.offsetWidth;
|
|
363
|
+
if (width < w) {
|
|
364
|
+
width = w;
|
|
365
|
+
}
|
|
366
|
+
// Estimated with based on the text
|
|
367
|
+
if (self.width < width) {
|
|
368
|
+
self.width = width;
|
|
369
|
+
}
|
|
370
|
+
self.el.style.width = self.width + 'px';
|
|
371
|
+
// Height
|
|
372
|
+
self.height = 400;
|
|
373
|
+
// Animation for mobile
|
|
374
|
+
if (document.documentElement.clientWidth < 800) {
|
|
375
|
+
self.animation = true;
|
|
376
|
+
}
|
|
377
|
+
// Data to be listed
|
|
378
|
+
self.rows = self.data;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const updateLabel = function () {
|
|
382
|
+
if (value && value.length) {
|
|
383
|
+
self.input.textContent = value.filter(v => v.selected).map(i => i.text).join('; ');
|
|
384
|
+
} else {
|
|
385
|
+
self.input.textContent = '';
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const setValue = function (v) {
|
|
390
|
+
// Values
|
|
391
|
+
let newValue;
|
|
392
|
+
if (!Array.isArray(v)) {
|
|
393
|
+
if (typeof (v) === 'string') {
|
|
394
|
+
newValue = v.split(';');
|
|
395
|
+
} else {
|
|
396
|
+
newValue = [v];
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
newValue = v;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Width && values
|
|
403
|
+
value = [];
|
|
404
|
+
|
|
405
|
+
if (Array.isArray(self.data)) {
|
|
406
|
+
self.data.map(function (s) {
|
|
407
|
+
// Select values
|
|
408
|
+
if (newValue.indexOf(s.value) !== -1) {
|
|
409
|
+
s.selected = true;
|
|
410
|
+
value.push(s);
|
|
411
|
+
} else {
|
|
412
|
+
s.selected = false;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Update label
|
|
418
|
+
updateLabel();
|
|
419
|
+
|
|
420
|
+
// Component onchange
|
|
421
|
+
if (typeof (onchange) === 'function') {
|
|
422
|
+
onchange.call(self, self, getValue());
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const getValue = function () {
|
|
427
|
+
if (self.multiple) {
|
|
428
|
+
if (value && value.length) {
|
|
429
|
+
return value.filter(v => v.selected).map(i => i.value);
|
|
430
|
+
}
|
|
431
|
+
return [];
|
|
432
|
+
} else {
|
|
433
|
+
if (value && value.length) {
|
|
434
|
+
return value[0].value;
|
|
435
|
+
} else {
|
|
436
|
+
return '';
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const onclose = function () {
|
|
442
|
+
// Cursor
|
|
443
|
+
removeCursor(true);
|
|
444
|
+
// Reset search
|
|
445
|
+
if (self.autocomplete) {
|
|
446
|
+
// Go to begin of the data
|
|
447
|
+
self.rows = self.data;
|
|
448
|
+
// Remove editable attribute
|
|
449
|
+
self.input.removeAttribute('contenteditable');
|
|
450
|
+
// Clear input
|
|
451
|
+
self.input.textContent = '';
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Current value
|
|
455
|
+
let newValue = getValue();
|
|
456
|
+
|
|
457
|
+
// If that is different from the component value
|
|
458
|
+
if (!compareValues(newValue, self.value)) {
|
|
459
|
+
self.value = newValue;
|
|
460
|
+
} else {
|
|
461
|
+
// Update label
|
|
462
|
+
updateLabel();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Identify the new state of the dropdown
|
|
466
|
+
self.state = false;
|
|
467
|
+
|
|
468
|
+
if (typeof (self.onclose) === 'function') {
|
|
469
|
+
self.onclose(self);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const onopen = function () {
|
|
474
|
+
self.state = true;
|
|
475
|
+
// Value
|
|
476
|
+
let v = value[value.length - 1];
|
|
477
|
+
// Make sure goes back to the top of the scroll
|
|
478
|
+
if (self.container.parentNode.scrollTop > 0) {
|
|
479
|
+
self.container.parentNode.scrollTop = 0;
|
|
480
|
+
}
|
|
481
|
+
// Move to the correct position
|
|
482
|
+
if (v) {
|
|
483
|
+
// Mark the position of the cursor to the same element
|
|
484
|
+
setCursor(self.rows.indexOf(v), true);
|
|
485
|
+
}
|
|
486
|
+
// Prepare search field
|
|
487
|
+
if (self.autocomplete) {
|
|
488
|
+
// Clear input
|
|
489
|
+
self.input.textContent = '';
|
|
490
|
+
// Editable
|
|
491
|
+
self.input.setAttribute('contenteditable', true);
|
|
492
|
+
// Focus on the item
|
|
493
|
+
self.input.focus();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (typeof (self.onopen) === 'function') {
|
|
497
|
+
self.onopen(self);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
self.add = async function (e) {
|
|
503
|
+
if (!self.input.textContent) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
e.preventDefault();
|
|
508
|
+
|
|
509
|
+
// New item
|
|
510
|
+
let s = {
|
|
511
|
+
text: self.input.textContent,
|
|
512
|
+
value: self.input.textContent,
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Event
|
|
516
|
+
if (typeof (self.onbeforeinsert) === 'function') {
|
|
517
|
+
let elClass = self.el.classList;
|
|
518
|
+
elClass.add('lm-dropdown-loading');
|
|
519
|
+
let ret = await self.onbeforeinsert(self, s);
|
|
520
|
+
elClass.remove('lm-dropdown-loading');
|
|
521
|
+
if (ret === false) {
|
|
522
|
+
return;
|
|
523
|
+
} else if (ret) {
|
|
524
|
+
s = ret;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Process the data
|
|
529
|
+
self.data.push(s);
|
|
530
|
+
// Select the new item
|
|
531
|
+
self.select(e, s);
|
|
532
|
+
// Close dropdown
|
|
533
|
+
self.close();
|
|
534
|
+
|
|
535
|
+
// Event
|
|
536
|
+
if (typeof (self.oninsert) === 'function') {
|
|
537
|
+
self.oninsert(self, s);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
self.search = function (e) {
|
|
542
|
+
if (self.state && self.autocomplete) {
|
|
543
|
+
// Filter options
|
|
544
|
+
let data;
|
|
545
|
+
if (!self.input.textContent) {
|
|
546
|
+
data = self.data;
|
|
547
|
+
} else {
|
|
548
|
+
data = self.data.filter(item => {
|
|
549
|
+
return item.selected === true ||
|
|
550
|
+
(item.text.toLowerCase().includes(self.input.textContent.toLowerCase())) ||
|
|
551
|
+
(item.group && item.group.toLowerCase().includes(self.input.textContent.toLowerCase()));
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
// Cursor
|
|
555
|
+
removeCursor(true);
|
|
556
|
+
// Update the data from the dropdown
|
|
557
|
+
self.rows = data;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
self.open = function () {
|
|
562
|
+
if (self.modal && self.modal.closed) {
|
|
563
|
+
// Open the modal
|
|
564
|
+
self.modal.closed = false;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
self.close = function () {
|
|
569
|
+
// Close the modal
|
|
570
|
+
if (self.modal) {
|
|
571
|
+
self.modal.closed = true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
self.toggle = function () {
|
|
576
|
+
if (self.modal) {
|
|
577
|
+
if (self.modal.closed) {
|
|
578
|
+
self.open();
|
|
579
|
+
} else {
|
|
580
|
+
self.close();
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
self.click = function (e) {
|
|
586
|
+
if (self.autocomplete) {
|
|
587
|
+
let x;
|
|
588
|
+
if (e.changedTouches && e.changedTouches[0]) {
|
|
589
|
+
x = e.changedTouches[0].clientX;
|
|
590
|
+
} else {
|
|
591
|
+
x = e.clientX;
|
|
592
|
+
}
|
|
593
|
+
if (e.target.offsetWidth - (x - e.target.offsetLeft) < 20) {
|
|
594
|
+
self.toggle();
|
|
595
|
+
} else {
|
|
596
|
+
self.open();
|
|
597
|
+
}
|
|
598
|
+
} else {
|
|
599
|
+
self.toggle();
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
self.select = function (e, s) {
|
|
604
|
+
if (s) {
|
|
605
|
+
if (self.multiple === true) {
|
|
606
|
+
let position = value.indexOf(s);
|
|
607
|
+
if (position === -1) {
|
|
608
|
+
value.push(s);
|
|
609
|
+
s.selected = true;
|
|
610
|
+
} else {
|
|
611
|
+
value.splice(position, 1);
|
|
612
|
+
s.selected = false;
|
|
613
|
+
}
|
|
614
|
+
} else {
|
|
615
|
+
if (value[0] === s) {
|
|
616
|
+
s.selected = !s.selected;
|
|
617
|
+
} else {
|
|
618
|
+
if (value[0]) {
|
|
619
|
+
value[0].selected = false;
|
|
620
|
+
}
|
|
621
|
+
s.selected = true;
|
|
622
|
+
}
|
|
623
|
+
if (s.selected) {
|
|
624
|
+
value = [s];
|
|
625
|
+
} else {
|
|
626
|
+
value = [];
|
|
627
|
+
}
|
|
628
|
+
// Close the modal
|
|
629
|
+
self.close();
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
self.getGroup = function () {
|
|
635
|
+
if (this.group && this.header) {
|
|
636
|
+
return this.group;
|
|
637
|
+
} else {
|
|
638
|
+
return '';
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
self.onload = function () {
|
|
643
|
+
if (self.type !== "inline") {
|
|
644
|
+
// Create modal instance
|
|
645
|
+
self.modal = {
|
|
646
|
+
closed: true,
|
|
647
|
+
focus: false,
|
|
648
|
+
width: self.width,
|
|
649
|
+
onopen: onopen,
|
|
650
|
+
onclose: onclose,
|
|
651
|
+
position: 'absolute',
|
|
652
|
+
'auto-adjust': true,
|
|
653
|
+
'auto-close': false,
|
|
654
|
+
};
|
|
655
|
+
// Generate modal
|
|
656
|
+
Modal(self.el.children[1], self.modal);
|
|
657
|
+
} else {
|
|
658
|
+
// For inline dropdown
|
|
659
|
+
self.el.setAttribute('tabindex', 0);
|
|
660
|
+
// Remove search
|
|
661
|
+
self.input.remove();
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (!Array.isArray(self.data)) {
|
|
665
|
+
self.data = [];
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
if (self.url && self.data.length === 0) {
|
|
669
|
+
const xhr = new XMLHttpRequest();
|
|
670
|
+
|
|
671
|
+
xhr.onreadystatechange = function () {
|
|
672
|
+
if (xhr.readyState === 4) {
|
|
673
|
+
if (xhr.status === 200) {
|
|
674
|
+
self.data = JSON.parse(xhr.responseText);
|
|
675
|
+
} else {
|
|
676
|
+
console.error('Failed to fetch data. Status code: ' + xhr.status);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
xhr.open('GET', self.url, true);
|
|
682
|
+
xhr.setRequestHeader('Content-Type', 'text/json')
|
|
683
|
+
xhr.send();
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Loading controls
|
|
687
|
+
lazyloading = lazyLoading(self);
|
|
688
|
+
// Process the data
|
|
689
|
+
setData();
|
|
690
|
+
// Set value
|
|
691
|
+
if (typeof (self.value) !== 'undefined') {
|
|
692
|
+
setValue(self.value);
|
|
693
|
+
}
|
|
694
|
+
// Focus out of the component
|
|
695
|
+
self.el.addEventListener('focusout', function (e) {
|
|
696
|
+
if (self.modal) {
|
|
697
|
+
if (!(e.relatedTarget && self.el.contains(e.relatedTarget)) && !self.el.contains(e.relatedTarget)) {
|
|
698
|
+
if (!self.modal.closed) {
|
|
699
|
+
self.modal.closed = true;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
})
|
|
704
|
+
// Key events
|
|
705
|
+
self.el.addEventListener('keydown', function (e) {
|
|
706
|
+
if (!self.modal.closed) {
|
|
707
|
+
let prevent = false;
|
|
708
|
+
if (e.key === 'ArrowUp') {
|
|
709
|
+
moveCursor(-1);
|
|
710
|
+
prevent = true;
|
|
711
|
+
} else if (e.key === 'ArrowDown') {
|
|
712
|
+
moveCursor(1);
|
|
713
|
+
prevent = true;
|
|
714
|
+
} else if (e.key === 'Home') {
|
|
715
|
+
moveCursor(-1, true);
|
|
716
|
+
if (!self.autocomplete) {
|
|
717
|
+
prevent = true;
|
|
718
|
+
}
|
|
719
|
+
} else if (e.key === 'End') {
|
|
720
|
+
moveCursor(1, true);
|
|
721
|
+
if (!self.autocomplete) {
|
|
722
|
+
prevent = true;
|
|
723
|
+
}
|
|
724
|
+
} else if (e.key === 'Enter') {
|
|
725
|
+
self.select(e, self.rows[cursor]);
|
|
726
|
+
prevent = true;
|
|
727
|
+
} else {
|
|
728
|
+
if (e.keyCode === 32 && !self.autocomplete) {
|
|
729
|
+
self.select(e, self.rows[cursor]);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (prevent) {
|
|
734
|
+
e.preventDefault();
|
|
735
|
+
e.stopImmediatePropagation();
|
|
736
|
+
}
|
|
737
|
+
} else {
|
|
738
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
739
|
+
self.modal.closed = false;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
// Custom event by the developer
|
|
744
|
+
if (typeof (onload) === 'function') {
|
|
745
|
+
onload(self);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
self.onchange = function (prop) {
|
|
750
|
+
if (prop === 'value') {
|
|
751
|
+
setValue(self.value);
|
|
752
|
+
} else if (prop === 'data') {
|
|
753
|
+
setData();
|
|
754
|
+
self.value = null;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if (typeof (lazyloading) === 'function') {
|
|
758
|
+
lazyloading(prop);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Sanitize any HTML from be paste on the search
|
|
764
|
+
* @param e
|
|
765
|
+
*/
|
|
766
|
+
self.onpaste = function (e) {
|
|
767
|
+
let text;
|
|
768
|
+
if (e.clipboardData || e.originalEvent.clipboardData) {
|
|
769
|
+
text = (e.originalEvent || e).clipboardData.getData('text/plain');
|
|
770
|
+
} else if (window.clipboardData) {
|
|
771
|
+
text = window.clipboardData.getData('Text');
|
|
772
|
+
}
|
|
773
|
+
text = text.replace(/(\r\n|\n|\r)/gm, "");
|
|
774
|
+
document.execCommand('insertText', false, text)
|
|
775
|
+
e.preventDefault();
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
return `<div class="lm-dropdown" data-insert="{{self.insert}}" data-type="{{self.type}}" data-state="{{self.state}}" :value="self.value" :data="self.data">
|
|
779
|
+
<div class="lm-dropdown-header">
|
|
780
|
+
<div class="lm-dropdown-input" onpaste="self.onpaste" oninput="self.search" onfocus="self.open" onmousedown="self.click" placeholder="{{self.placeholder}}" :ref="self.input" tabindex="0"></div>
|
|
781
|
+
<div class="lm-dropdown-add" onmousedown="self.add"></div>
|
|
782
|
+
<button onclick="self.close" class="lm-dropdown-done">Done</button>
|
|
783
|
+
</div>
|
|
784
|
+
<div class="lm-dropdown-content">
|
|
785
|
+
<div>
|
|
786
|
+
<div :loop="self.result" :ref="self.container" :rows="self.rows">
|
|
787
|
+
<div class="lm-dropdown-item" onclick="self.parent.select" data-cursor="{{self.cursor}}" data-selected="{{self.selected}}" data-group="{{self.parent.getGroup}}">
|
|
788
|
+
<div><img :src="self.image" /><span>{{self.text}}</span></div>
|
|
789
|
+
</div>
|
|
790
|
+
</div>
|
|
791
|
+
</div>
|
|
792
|
+
</div>
|
|
793
|
+
</div>`;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
lemonade.setComponents({ Dropdown: Dropdown });
|
|
797
|
+
|
|
798
|
+
return function (root, options) {
|
|
799
|
+
if (typeof (root) === 'object') {
|
|
800
|
+
lemonade.render(Dropdown, root, options)
|
|
801
|
+
return options;
|
|
802
|
+
} else {
|
|
803
|
+
return Dropdown.call(this, root)
|
|
804
|
+
}
|
|
805
|
+
}
|
|
779
806
|
})));
|