@lemonadejs/dropdown 3.1.2 → 3.1.5

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/dist/index.js CHANGED
@@ -20,17 +20,22 @@ if (!Modal && typeof (require) === 'function') {
20
20
  // Default row height
21
21
  let defaultRowHeight = 24;
22
22
 
23
- const lazyLoading = function(self) {
24
- /**
25
- * Compare two arrays to see if contains exact the same elements
26
- * @param {number[]} a1
27
- * @param {number[]} a2
28
- */
29
- const compareArray = function (a1, a2) {
30
- if (! a1 || ! a2) {
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 {
31
36
  return false;
32
37
  }
33
-
38
+ } else {
34
39
  let i = a1.length;
35
40
  if (i !== a2.length) {
36
41
  return false;
@@ -40,9 +45,11 @@ if (!Modal && typeof (require) === 'function') {
40
45
  return false;
41
46
  }
42
47
  }
43
- return true;
44
48
  }
49
+ return true;
50
+ }
45
51
 
52
+ const lazyLoading = function(self) {
46
53
  /**
47
54
  * Get the position from top of a row by its index
48
55
  * @param item
@@ -132,7 +139,7 @@ if (!Modal && typeof (require) === 'function') {
132
139
  }
133
140
 
134
141
  // Update visible rows
135
- if (reset || ! compareArray(rows, self.result)) {
142
+ if (reset || ! compareValues(rows, self.result)) {
136
143
  // Render the items
137
144
  self.result = rows;
138
145
  // Adjust scroll height
@@ -237,81 +244,33 @@ if (!Modal && typeof (require) === 'function') {
237
244
 
238
245
  const Dropdown = function () {
239
246
  let self = this;
247
+ // Internal value controllers
240
248
  let value = [];
249
+ // Cursor
241
250
  let cursor = null;
242
-
251
+ // Control events
252
+ let ignoreEvents = false;
253
+ // Default widht
243
254
  if (! self.width) {
244
255
  self.width = 260;
245
256
  }
246
-
247
257
  // Lazy loading global instance
248
258
  let lazyloading = null;
249
-
259
+ // Custom events defined by the user
250
260
  let onload = self.load;
251
261
  let onchange = self.onchange;
252
262
 
253
- const setData = function() {
254
- // Estimate width
255
- let width = self.width;
256
- // Re-order to make sure groups are in sequence
257
- if (self.data && self.data.length) {
258
- self.data.sort((a, b) => {
259
- // Compare groups
260
- if (a.group && b.group) {
261
- return a.group.localeCompare(b.group);
262
- }
263
- return 0;
264
- });
265
- let group = '';
266
- // Define group headers
267
- self.data.map((v) => {
268
- // Compare groups
269
- if (v && v.group && v.group !== group) {
270
- v.header = true;
271
- group = v.group;
272
- }
273
- });
274
- // Width && values
275
- self.data.map(function (s) {
276
- // Estimated width of the element
277
- if (s.text) {
278
- width = Math.max(width, s.text.length * 8);
279
- }
280
- });
281
- }
282
- // Adjust the width
283
- let w = self.input.offsetWidth;
284
- if (width < w) {
285
- width = w;
286
- }
287
- // Estimated with based on the text
288
- if (self.width < width) {
289
- self.width = width;
290
- }
291
- self.el.style.width = self.width + 'px';
292
- // Height
293
- self.height = 400;
294
- // Animation for mobile
295
- if (document.documentElement.clientWidth < 800) {
296
- self.animation = true;
297
- }
298
- // Data to be listed
299
- self.rows = self.data;
300
- // Set the initial value
301
- if (typeof(self.value) !== 'undefined') {
302
- setValue(self.value);
303
- }
304
- }
305
-
263
+ // Cursor controllers
306
264
  const setCursor = function(index) {
307
265
  let item = self.rows[index];
266
+
308
267
  if (typeof(item) !== 'undefined') {
309
268
  // Set cursor number
310
269
  cursor = index;
311
270
  // Set visual indication
312
271
  item.cursor = true;
313
272
  // Go to the item on the scroll in case the item is not on the viewport
314
- if (! item.el || ! item.el.parentNode) {
273
+ if (! (item.el && item.el.parentNode)) {
315
274
  // Goto method
316
275
  self.goto(item);
317
276
  }
@@ -370,6 +329,55 @@ if (!Modal && typeof (require) === 'function') {
370
329
  setCursor(cursor);
371
330
  }
372
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
+
373
381
  const updateLabel = function() {
374
382
  if (value && value.length) {
375
383
  self.input.textContent = value.filter(v => v.selected).map(i => i.text).join('; ');
@@ -394,22 +402,24 @@ if (!Modal && typeof (require) === 'function') {
394
402
  // Width && values
395
403
  value = [];
396
404
 
397
- self.data.map(function(s) {
398
- // Select values
399
- if (newValue.indexOf(s.value) !== -1) {
400
- s.selected = true;
401
- value.push(s);
402
- } else {
403
- s.selected = false;
404
- }
405
- });
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
+ }
406
416
 
407
417
  // Update label
408
418
  updateLabel();
409
419
 
410
420
  // Component onchange
411
421
  if (typeof(onchange) === 'function') {
412
- onchange(self, self.value);
422
+ onchange(self, value);
413
423
  }
414
424
  }
415
425
 
@@ -440,10 +450,18 @@ if (!Modal && typeof (require) === 'function') {
440
450
  // Clear input
441
451
  self.input.textContent = '';
442
452
  }
443
- // Update label
444
- updateLabel();
445
- // Update value
446
- self.value = getValue();
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
+
447
465
  // Identify the new state of the dropdown
448
466
  self.state = false;
449
467
 
@@ -456,15 +474,14 @@ if (!Modal && typeof (require) === 'function') {
456
474
  self.state = true;
457
475
  // Value
458
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
+ }
459
481
  // Move to the correct position
460
482
  if (v) {
461
- // Go to the last item in the array of values
462
- self.goto(v);
463
483
  // Mark the position of the cursor to the same element
464
484
  setCursor(self.rows.indexOf(v));
465
- } else {
466
- // Go to begin of the data
467
- self.rows = self.data;
468
485
  }
469
486
  // Prepare search field
470
487
  if (self.autocomplete) {
@@ -481,6 +498,46 @@ if (!Modal && typeof (require) === 'function') {
481
498
  }
482
499
  }
483
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
+
484
541
  self.search = function(e) {
485
542
  if (self.state && self.autocomplete) {
486
543
  // Filter options
@@ -501,14 +558,10 @@ if (!Modal && typeof (require) === 'function') {
501
558
  }
502
559
  }
503
560
 
504
- let timer = null;
505
-
506
561
  self.open = function () {
507
562
  if (self.modal && self.modal.closed) {
508
563
  // Open the modal
509
564
  self.modal.closed = false;
510
- // Timer
511
- timer = setTimeout(() => timer = null, 400);
512
565
  }
513
566
  }
514
567
 
@@ -519,11 +572,7 @@ if (!Modal && typeof (require) === 'function') {
519
572
  }
520
573
  }
521
574
 
522
- self.toggle = function(e) {
523
- if (timer) {
524
- return;
525
- }
526
-
575
+ self.toggle = function() {
527
576
  if (self.modal) {
528
577
  if (self.modal.closed) {
529
578
  self.open();
@@ -534,16 +583,20 @@ if (!Modal && typeof (require) === 'function') {
534
583
  }
535
584
 
536
585
  self.click = function(e) {
537
- let x;
538
- if (e.changedTouches && e.changedTouches[0]) {
539
- x = e.changedTouches[0].clientX;
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
+ }
540
598
  } else {
541
- x = e.clientX;
542
- }
543
- if (e.target.offsetWidth - (x - e.target.offsetLeft) < 20) {
544
599
  self.toggle();
545
- } else {
546
- self.open();
547
600
  }
548
601
  }
549
602
 
@@ -611,6 +664,10 @@ if (!Modal && typeof (require) === 'function') {
611
664
  lazyloading = lazyLoading(self);
612
665
  // Process the data
613
666
  setData();
667
+ // Se value
668
+ if (self.value) {
669
+ setValue(self.value);
670
+ }
614
671
  // Focus out of the component
615
672
  self.el.addEventListener('focusout', function(e) {
616
673
  if (self.modal) {
@@ -623,32 +680,38 @@ if (!Modal && typeof (require) === 'function') {
623
680
  })
624
681
  // Key events
625
682
  self.el.addEventListener('keydown', function(e) {
626
- let prevent = false;
627
- if (e.key === 'ArrowUp') {
628
- moveCursor(-1);
629
- prevent = true;
630
- } else if (e.key === 'ArrowDown') {
631
- moveCursor(1);
632
- prevent = true;
633
- } else if (e.key === 'Home') {
634
- moveCursor(-1, true);
635
- } else if (e.key === 'End') {
636
- moveCursor(1, true);
637
- } else if (e.key === 'Enter') {
638
- self.select(e, self.rows[cursor]);
639
- prevent = true;
640
- } else {
641
- if (e.keyCode === 32 && ! self.autocomplete) {
683
+ if (! self.modal.closed) {
684
+ let prevent = false;
685
+ if (e.key === 'ArrowUp') {
686
+ moveCursor(-1);
687
+ prevent = true;
688
+ } else if (e.key === 'ArrowDown') {
689
+ moveCursor(1);
690
+ prevent = true;
691
+ } else if (e.key === 'Home') {
692
+ moveCursor(-1, true);
693
+ } else if (e.key === 'End') {
694
+ moveCursor(1, true);
695
+ } else if (e.key === 'Enter') {
642
696
  self.select(e, self.rows[cursor]);
697
+ prevent = true;
698
+ } else {
699
+ if (e.keyCode === 32 && !self.autocomplete) {
700
+ self.select(e, self.rows[cursor]);
701
+ }
643
702
  }
644
- }
645
703
 
646
- if (prevent) {
647
- e.preventDefault();
648
- e.stopImmediatePropagation();
704
+ if (prevent) {
705
+ e.preventDefault();
706
+ e.stopImmediatePropagation();
707
+ }
708
+ } else {
709
+ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
710
+ self.modal.closed = false;
711
+ }
649
712
  }
650
713
  });
651
-
714
+ // Custom event by the developer
652
715
  if (typeof(onload) === 'function') {
653
716
  onload(self);
654
717
  }
@@ -659,6 +722,7 @@ if (!Modal && typeof (require) === 'function') {
659
722
  setValue(self.value);
660
723
  } else if (prop === 'data') {
661
724
  setData();
725
+ self.value = null;
662
726
  }
663
727
 
664
728
  if (typeof(lazyloading) === 'function') {
@@ -682,48 +746,9 @@ if (!Modal && typeof (require) === 'function') {
682
746
  e.preventDefault();
683
747
  }
684
748
 
685
- self.add = async function(e) {
686
- if (! self.input.textContent) {
687
- return false;
688
- }
689
-
690
- e.preventDefault();
691
-
692
- // New item
693
- let s = {
694
- text: self.input.textContent,
695
- value: self.input.textContent,
696
- }
697
-
698
- // Event
699
- if (typeof(self.onbeforeinsert) === 'function') {
700
- let elClass = self.el.classList;
701
- elClass.add('lm-dropdown-loading');
702
- let ret = await self.onbeforeinsert(self, s);
703
- elClass.remove('lm-dropdown-loading');
704
- if (ret === false) {
705
- return;
706
- } else if (ret) {
707
- s = ret;
708
- }
709
- }
710
-
711
- // Process the data
712
- self.data.push(s);
713
- // Select the new item
714
- self.select(e, s);
715
- // Close dropdown
716
- self.close();
717
-
718
- // Event
719
- if (typeof(self.oninsert) === 'function') {
720
- self.oninsert(self, s);
721
- }
722
- }
723
-
724
- return `<div class="lm-dropdown" data-insert="{{self.insert}}" data-type="{{self.type}}" data-state="{{self.state}}" :value="self.value">
749
+ return `<div class="lm-dropdown" data-insert="{{self.insert}}" data-type="{{self.type}}" data-state="{{self.state}}" :value="self.value" :data="self.data">
725
750
  <div class="lm-dropdown-header">
726
- <div class="lm-dropdown-input" onpaste="self.onpaste" oninput="self.search" onfocus="self.open" onclick="self.click" placeholder="{{self.placeholder}}" :ref="self.input" tabindex="0"></div>
751
+ <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>
727
752
  <div class="lm-dropdown-add" onmousedown="self.add"></div>
728
753
  <button onclick="self.close" class="lm-dropdown-done">Done</button>
729
754
  </div>
package/dist/style.css CHANGED
@@ -63,7 +63,7 @@
63
63
 
64
64
  .lm-dropdown-add {
65
65
  position: absolute;
66
- padding: 10px;
66
+ padding: 12px;
67
67
  right: 20px;
68
68
  display: none;
69
69
  }
package/package.json CHANGED
@@ -19,5 +19,5 @@
19
19
  },
20
20
  "main": "dist/index.js",
21
21
  "types": "dist/index.d.ts",
22
- "version": "3.1.2"
22
+ "version": "3.1.5"
23
23
  }