fomantic-ui-sass 2.8.8 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/app/assets/fonts/semantic-ui/brand-icons.eot +0 -0
  4. data/app/assets/fonts/semantic-ui/brand-icons.svg +41 -6
  5. data/app/assets/fonts/semantic-ui/brand-icons.ttf +0 -0
  6. data/app/assets/fonts/semantic-ui/brand-icons.woff +0 -0
  7. data/app/assets/fonts/semantic-ui/brand-icons.woff2 +0 -0
  8. data/app/assets/fonts/semantic-ui/icons.eot +0 -0
  9. data/app/assets/fonts/semantic-ui/icons.svg +245 -7
  10. data/app/assets/fonts/semantic-ui/icons.ttf +0 -0
  11. data/app/assets/fonts/semantic-ui/icons.woff +0 -0
  12. data/app/assets/fonts/semantic-ui/icons.woff2 +0 -0
  13. data/app/assets/fonts/semantic-ui/outline-icons.eot +0 -0
  14. data/app/assets/fonts/semantic-ui/outline-icons.svg +2 -2
  15. data/app/assets/fonts/semantic-ui/outline-icons.ttf +0 -0
  16. data/app/assets/fonts/semantic-ui/outline-icons.woff +0 -0
  17. data/app/assets/fonts/semantic-ui/outline-icons.woff2 +0 -0
  18. data/app/assets/javascripts/semantic-ui/accordion.js +9 -3
  19. data/app/assets/javascripts/semantic-ui/api.js +92 -33
  20. data/app/assets/javascripts/semantic-ui/calendar.js +200 -82
  21. data/app/assets/javascripts/semantic-ui/checkbox.js +20 -13
  22. data/app/assets/javascripts/semantic-ui/dimmer.js +24 -9
  23. data/app/assets/javascripts/semantic-ui/dropdown.js +250 -205
  24. data/app/assets/javascripts/semantic-ui/embed.js +13 -9
  25. data/app/assets/javascripts/semantic-ui/flyout.js +1530 -0
  26. data/app/assets/javascripts/semantic-ui/form.js +47 -41
  27. data/app/assets/javascripts/semantic-ui/modal.js +187 -83
  28. data/app/assets/javascripts/semantic-ui/nag.js +2 -2
  29. data/app/assets/javascripts/semantic-ui/popup.js +16 -22
  30. data/app/assets/javascripts/semantic-ui/progress.js +7 -4
  31. data/app/assets/javascripts/semantic-ui/rating.js +7 -3
  32. data/app/assets/javascripts/semantic-ui/search.js +47 -20
  33. data/app/assets/javascripts/semantic-ui/shape.js +3 -3
  34. data/app/assets/javascripts/semantic-ui/sidebar.js +140 -43
  35. data/app/assets/javascripts/semantic-ui/site.js +1 -1
  36. data/app/assets/javascripts/semantic-ui/slider.js +78 -63
  37. data/app/assets/javascripts/semantic-ui/state.js +2 -2
  38. data/app/assets/javascripts/semantic-ui/sticky.js +30 -19
  39. data/app/assets/javascripts/semantic-ui/tab.js +24 -6
  40. data/app/assets/javascripts/semantic-ui/toast.js +67 -33
  41. data/app/assets/javascripts/semantic-ui/transition.js +27 -22
  42. data/app/assets/javascripts/semantic-ui/visibility.js +5 -5
  43. data/app/assets/stylesheets/semantic-ui/collections/_breadcrumb.scss +1 -1
  44. data/app/assets/stylesheets/semantic-ui/collections/_form.scss +160 -83
  45. data/app/assets/stylesheets/semantic-ui/collections/_grid.scss +25 -21
  46. data/app/assets/stylesheets/semantic-ui/collections/_menu.scss +110 -78
  47. data/app/assets/stylesheets/semantic-ui/collections/_message.scss +43 -43
  48. data/app/assets/stylesheets/semantic-ui/collections/_table.scss +1684 -272
  49. data/app/assets/stylesheets/semantic-ui/elements/_button.scss +204 -157
  50. data/app/assets/stylesheets/semantic-ui/elements/_container.scss +98 -4
  51. data/app/assets/stylesheets/semantic-ui/elements/_divider.scss +31 -31
  52. data/app/assets/stylesheets/semantic-ui/elements/_emoji.scss +10799 -8841
  53. data/app/assets/stylesheets/semantic-ui/elements/_flag.scss +1021 -915
  54. data/app/assets/stylesheets/semantic-ui/elements/_header.scss +6 -4
  55. data/app/assets/stylesheets/semantic-ui/elements/_icon.scss +2110 -2061
  56. data/app/assets/stylesheets/semantic-ui/elements/_image.scss +1 -1
  57. data/app/assets/stylesheets/semantic-ui/elements/_input.scss +759 -22
  58. data/app/assets/stylesheets/semantic-ui/elements/_label.scss +72 -68
  59. data/app/assets/stylesheets/semantic-ui/elements/_list.scss +31 -31
  60. data/app/assets/stylesheets/semantic-ui/elements/_loader.scss +352 -352
  61. data/app/assets/stylesheets/semantic-ui/elements/_placeholder.scss +33 -33
  62. data/app/assets/stylesheets/semantic-ui/elements/_rail.scss +1 -1
  63. data/app/assets/stylesheets/semantic-ui/elements/_reveal.scss +1 -1
  64. data/app/assets/stylesheets/semantic-ui/elements/_segment.scss +118 -34
  65. data/app/assets/stylesheets/semantic-ui/elements/_step.scss +32 -32
  66. data/app/assets/stylesheets/semantic-ui/elements/_text.scss +1 -1
  67. data/app/assets/stylesheets/semantic-ui/globals/_reset.scss +5 -4
  68. data/app/assets/stylesheets/semantic-ui/globals/_site.scss +139 -42
  69. data/app/assets/stylesheets/semantic-ui/modules/_accordion.scss +177 -37
  70. data/app/assets/stylesheets/semantic-ui/modules/_calendar.scss +18 -1
  71. data/app/assets/stylesheets/semantic-ui/modules/_checkbox.scss +93 -92
  72. data/app/assets/stylesheets/semantic-ui/modules/_dimmer.scss +33 -18
  73. data/app/assets/stylesheets/semantic-ui/modules/_dropdown.scss +101 -51
  74. data/app/assets/stylesheets/semantic-ui/modules/_embed.scss +5 -5
  75. data/app/assets/stylesheets/semantic-ui/modules/_flyout.scss +592 -0
  76. data/app/assets/stylesheets/semantic-ui/modules/_modal.scss +37 -6
  77. data/app/assets/stylesheets/semantic-ui/modules/_nag.scss +1 -1
  78. data/app/assets/stylesheets/semantic-ui/modules/_popup.scss +103 -105
  79. data/app/assets/stylesheets/semantic-ui/modules/_progress.scss +1 -1
  80. data/app/assets/stylesheets/semantic-ui/modules/_rating.scss +7 -46
  81. data/app/assets/stylesheets/semantic-ui/modules/_search.scss +6 -6
  82. data/app/assets/stylesheets/semantic-ui/modules/_shape.scss +1 -1
  83. data/app/assets/stylesheets/semantic-ui/modules/_sidebar.scss +23 -9
  84. data/app/assets/stylesheets/semantic-ui/modules/_slider.scss +17 -17
  85. data/app/assets/stylesheets/semantic-ui/modules/_sticky.scss +1 -1
  86. data/app/assets/stylesheets/semantic-ui/modules/_tab.scss +5 -5
  87. data/app/assets/stylesheets/semantic-ui/modules/_toast.scss +49 -1
  88. data/app/assets/stylesheets/semantic-ui/modules/_transition.scss +1 -1
  89. data/app/assets/stylesheets/semantic-ui/views/_ad.scss +4 -4
  90. data/app/assets/stylesheets/semantic-ui/views/_card.scss +754 -117
  91. data/app/assets/stylesheets/semantic-ui/views/_comment.scss +12 -12
  92. data/app/assets/stylesheets/semantic-ui/views/_feed.scss +29 -29
  93. data/app/assets/stylesheets/semantic-ui/views/_item.scss +17 -17
  94. data/app/assets/stylesheets/semantic-ui/views/_statistic.scss +4 -4
  95. data/fomantic-ui-sass.gemspec +1 -1
  96. data/lib/fomantic/ui/sass/version.rb +2 -2
  97. metadata +9 -7
@@ -30,11 +30,6 @@ $.fn.dropdown = function(parameters) {
30
30
 
31
31
  moduleSelector = $allModules.selector || '',
32
32
 
33
- hasTouch = ('ontouchstart' in document.documentElement),
34
- clickEvent = hasTouch
35
- ? 'touchstart'
36
- : 'click',
37
-
38
33
  time = new Date().getTime(),
39
34
  performance = [],
40
35
 
@@ -66,7 +61,7 @@ $.fn.dropdown = function(parameters) {
66
61
  moduleNamespace = 'module-' + namespace,
67
62
 
68
63
  $module = $(this),
69
- $context = $(settings.context),
64
+ $context = [window,document].indexOf(settings.context) < 0 ? $document.find(settings.context) : $(settings.context),
70
65
  $text = $module.find(selector.text),
71
66
  $search = $module.find(selector.search),
72
67
  $sizer = $module.find(selector.sizer),
@@ -116,6 +111,7 @@ $.fn.dropdown = function(parameters) {
116
111
  module.error(error.noNormalize, element);
117
112
  }
118
113
 
114
+ module.create.id();
119
115
  module.setup.layout();
120
116
 
121
117
  if(settings.values) {
@@ -129,7 +125,6 @@ $.fn.dropdown = function(parameters) {
129
125
  module.save.defaults();
130
126
  module.restore.selected();
131
127
 
132
- module.create.id();
133
128
  module.bind.events();
134
129
 
135
130
  module.observeChanges();
@@ -200,6 +195,7 @@ $.fn.dropdown = function(parameters) {
200
195
  select: function() {
201
196
  if(module.has.input() && selectObserver) {
202
197
  selectObserver.observe($module[0], {
198
+ attributes: true,
203
199
  childList : true,
204
200
  subtree : true
205
201
  });
@@ -224,7 +220,7 @@ $.fn.dropdown = function(parameters) {
224
220
 
225
221
  create: {
226
222
  id: function() {
227
- id = (Math.random().toString(16) + '000000000').substr(2, 8);
223
+ id = (Math.random().toString(16) + '000000000').slice(2, 10);
228
224
  elementNamespace = '.' + id;
229
225
  module.verbose('Creating unique id for element', id);
230
226
  },
@@ -232,7 +228,6 @@ $.fn.dropdown = function(parameters) {
232
228
  var
233
229
  $userChoices,
234
230
  $userChoice,
235
- isUserValue,
236
231
  html
237
232
  ;
238
233
  values = values || module.get.userValues();
@@ -370,11 +365,20 @@ $.fn.dropdown = function(parameters) {
370
365
  }
371
366
  if( module.is.search() && !module.has.search() ) {
372
367
  module.verbose('Adding search input');
368
+ var
369
+ labelNode = $module.prev('label')
370
+ ;
373
371
  $search = $('<input />')
374
372
  .addClass(className.search)
375
373
  .prop('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
376
- .insertBefore($text)
377
374
  ;
375
+ if (labelNode.length) {
376
+ if (!labelNode.attr('id')) {
377
+ labelNode.attr('id', '_' + module.get.id() + '_formLabel');
378
+ }
379
+ $search.attr('aria-labelledby', labelNode.attr('id'));
380
+ }
381
+ $search.insertBefore($text);
378
382
  }
379
383
  if( module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
380
384
  module.create.sizer();
@@ -421,6 +425,9 @@ $.fn.dropdown = function(parameters) {
421
425
  module.debug('Disabling dropdown');
422
426
  $module.addClass(className.disabled);
423
427
  }
428
+ if($input.is('[required]')) {
429
+ settings.forceSelection = true;
430
+ }
424
431
  $input
425
432
  .removeAttr('required')
426
433
  .removeAttr('class')
@@ -440,7 +447,7 @@ $.fn.dropdown = function(parameters) {
440
447
  // replace module reference
441
448
  $module = $module.parent(selector.dropdown);
442
449
  instance = $module.data(moduleNamespace);
443
- element = $module.get(0);
450
+ element = $module[0];
444
451
  module.refresh();
445
452
  module.setup.returnedObject();
446
453
  },
@@ -536,10 +543,9 @@ $.fn.dropdown = function(parameters) {
536
543
  return true;
537
544
  }
538
545
  if(settings.onShow.call(element) !== false) {
546
+ module.remove.empty();
539
547
  module.animate.show(function() {
540
- if( module.can.click() ) {
541
- module.bind.intent();
542
- }
548
+ module.bind.intent();
543
549
  if(module.has.search() && !preventFocus) {
544
550
  module.focusSearch();
545
551
  }
@@ -560,14 +566,23 @@ $.fn.dropdown = function(parameters) {
560
566
  if(settings.onHide.call(element) !== false) {
561
567
  module.animate.hide(function() {
562
568
  module.remove.visible();
563
- // hidding search focus
569
+ // hiding search focus
564
570
  if ( module.is.focusedOnSearch() && preventBlur !== true ) {
565
571
  $search.blur();
566
572
  }
567
573
  callback.call(element);
568
574
  });
575
+ // Hide submenus explicitly. On some browsers (esp. mobile), they will not automatically receive a
576
+ // mouseleave event
577
+ var $subMenu = $module.find(selector.menu);
578
+ if($subMenu.length > 0) {
579
+ module.verbose('Hiding sub-menu', $subMenu);
580
+ $subMenu.each(function() {
581
+ module.animate.hide(false, $(this));
582
+ });
583
+ }
569
584
  }
570
- } else if( module.can.click() ) {
585
+ } else {
571
586
  module.unbind.intent();
572
587
  }
573
588
  iconClicked = false;
@@ -587,7 +602,7 @@ $.fn.dropdown = function(parameters) {
587
602
  module.verbose('Hiding menu instantaneously');
588
603
  module.remove.active();
589
604
  module.remove.visible();
590
- $menu.transition('hide');
605
+ $menu.transition('destroy').transition('hide');
591
606
  },
592
607
 
593
608
  hideSubMenus: function() {
@@ -625,13 +640,18 @@ $.fn.dropdown = function(parameters) {
625
640
  $module
626
641
  .on('change' + eventNamespace, selector.input, module.event.change)
627
642
  ;
643
+ if(module.is.multiple() && module.is.searchSelection()) {
644
+ $module
645
+ .on('paste' + eventNamespace, selector.search, module.event.paste)
646
+ ;
647
+ }
628
648
  },
629
649
  mouseEvents: function() {
630
650
  module.verbose('Binding mouse events');
631
651
  if(module.is.multiple()) {
632
652
  $module
633
- .on(clickEvent + eventNamespace, selector.label, module.event.label.click)
634
- .on(clickEvent + eventNamespace, selector.remove, module.event.remove.click)
653
+ .on('click' + eventNamespace, selector.label, module.event.label.click)
654
+ .on('click' + eventNamespace, selector.remove, module.event.remove.click)
635
655
  ;
636
656
  }
637
657
  if( module.is.searchSelection() ) {
@@ -640,31 +660,33 @@ $.fn.dropdown = function(parameters) {
640
660
  .on('mouseup' + eventNamespace, module.event.mouseup)
641
661
  .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
642
662
  .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
643
- .on(clickEvent + eventNamespace, selector.icon, module.event.icon.click)
644
- .on(clickEvent + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
663
+ .on('click' + eventNamespace, selector.icon, module.event.icon.click)
664
+ .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
645
665
  .on('focus' + eventNamespace, selector.search, module.event.search.focus)
646
- .on(clickEvent + eventNamespace, selector.search, module.event.search.focus)
666
+ .on('click' + eventNamespace, selector.search, module.event.search.focus)
647
667
  .on('blur' + eventNamespace, selector.search, module.event.search.blur)
648
- .on(clickEvent + eventNamespace, selector.text, module.event.text.focus)
668
+ .on('click' + eventNamespace, selector.text, module.event.text.focus)
649
669
  ;
650
670
  if(module.is.multiple()) {
651
671
  $module
652
- .on(clickEvent + eventNamespace, module.event.click)
653
- .on(clickEvent + eventNamespace, module.event.search.focus)
672
+ .on('click' + eventNamespace, module.event.click)
673
+ .on('click' + eventNamespace, module.event.search.focus)
654
674
  ;
655
675
  }
656
676
  }
657
677
  else {
658
678
  if(settings.on == 'click') {
659
679
  $module
660
- .on(clickEvent + eventNamespace, selector.icon, module.event.icon.click)
661
- .on(clickEvent + eventNamespace, module.event.test.toggle)
680
+ .on('click' + eventNamespace, selector.icon, module.event.icon.click)
681
+ .on('click' + eventNamespace, module.event.test.toggle)
662
682
  ;
663
683
  }
664
684
  else if(settings.on == 'hover') {
665
685
  $module
666
686
  .on('mouseenter' + eventNamespace, module.delay.show)
667
687
  .on('mouseleave' + eventNamespace, module.delay.hide)
688
+ .on('touchstart' + eventNamespace, module.event.test.toggle)
689
+ .on('touchstart' + eventNamespace, selector.icon, module.event.icon.click)
668
690
  ;
669
691
  }
670
692
  else {
@@ -676,7 +698,7 @@ $.fn.dropdown = function(parameters) {
676
698
  .on('mousedown' + eventNamespace, module.event.mousedown)
677
699
  .on('mouseup' + eventNamespace, module.event.mouseup)
678
700
  .on('focus' + eventNamespace, module.event.focus)
679
- .on(clickEvent + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
701
+ .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
680
702
  ;
681
703
  if(module.has.menuSearch() ) {
682
704
  $module
@@ -690,21 +712,16 @@ $.fn.dropdown = function(parameters) {
690
712
  }
691
713
  }
692
714
  $menu
693
- .on((hasTouch ? 'touchstart' : 'mouseenter') + eventNamespace, selector.item, module.event.item.mouseenter)
715
+ .on('mouseenter' + eventNamespace, selector.item, module.event.item.mouseenter)
716
+ .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
694
717
  .on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
695
718
  .on('click' + eventNamespace, selector.item, module.event.item.click)
696
719
  ;
697
720
  },
698
721
  intent: function() {
699
722
  module.verbose('Binding hide intent event to document');
700
- if(hasTouch) {
701
- $document
702
- .on('touchstart' + elementNamespace, module.event.test.touch)
703
- .on('touchmove' + elementNamespace, module.event.test.touch)
704
- ;
705
- }
706
723
  $document
707
- .on(clickEvent + elementNamespace, module.event.test.hide)
724
+ .on('click' + elementNamespace, module.event.test.hide)
708
725
  ;
709
726
  }
710
727
  },
@@ -712,14 +729,8 @@ $.fn.dropdown = function(parameters) {
712
729
  unbind: {
713
730
  intent: function() {
714
731
  module.verbose('Removing hide intent event from document');
715
- if(hasTouch) {
716
- $document
717
- .off('touchstart' + elementNamespace)
718
- .off('touchmove' + elementNamespace)
719
- ;
720
- }
721
732
  $document
722
- .off(clickEvent + elementNamespace)
733
+ .off('click' + elementNamespace)
723
734
  ;
724
735
  }
725
736
  },
@@ -752,6 +763,7 @@ $.fn.dropdown = function(parameters) {
752
763
  }
753
764
  else {
754
765
  module.verbose('All items filtered, hiding dropdown', searchTerm);
766
+ module.set.empty();
755
767
  module.hideMenu();
756
768
  }
757
769
  }
@@ -762,7 +774,7 @@ $.fn.dropdown = function(parameters) {
762
774
  if(settings.allowAdditions) {
763
775
  module.add.userSuggestion(module.escape.htmlEntities(query));
764
776
  }
765
- if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() ) {
777
+ if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() && !module.is.empty()) {
766
778
  module.show();
767
779
  }
768
780
  }
@@ -812,20 +824,28 @@ $.fn.dropdown = function(parameters) {
812
824
  throttle : settings.throttle,
813
825
  urlData : {
814
826
  query: query
815
- },
816
- onError: function() {
827
+ }
828
+ },
829
+ apiCallbacks = {
830
+ onError: function(errorMessage, $module, xhr) {
817
831
  module.add.message(message.serverError);
818
832
  iconClicked = false;
819
833
  focused = false;
820
834
  callback.apply(null, callbackParameters);
835
+ if(typeof settings.apiSettings.onError === 'function') {
836
+ settings.apiSettings.onError.call(this, errorMessage, $module, xhr);
837
+ }
821
838
  },
822
- onFailure: function() {
839
+ onFailure: function(response, $module, xhr) {
823
840
  module.add.message(message.serverError);
824
841
  iconClicked = false;
825
842
  focused = false;
826
843
  callback.apply(null, callbackParameters);
844
+ if(typeof settings.apiSettings.onFailure === 'function') {
845
+ settings.apiSettings.onFailure.call(this, response, $module, xhr);
846
+ }
827
847
  },
828
- onSuccess : function(response) {
848
+ onSuccess : function(response, $module, xhr) {
829
849
  var
830
850
  values = response[fields.remoteValues]
831
851
  ;
@@ -844,19 +864,22 @@ $.fn.dropdown = function(parameters) {
844
864
  var value = module.is.multiple() ? module.get.values() : module.get.value();
845
865
  if (value !== '') {
846
866
  module.verbose('Value(s) present after click icon, select value(s) in items');
847
- module.set.selected(value, null, null, true);
867
+ module.set.selected(value, null, true, true);
848
868
  }
849
869
  }
850
870
  iconClicked = false;
851
871
  focused = false;
852
872
  callback.apply(null, callbackParameters);
873
+ if(typeof settings.apiSettings.onSuccess === 'function') {
874
+ settings.apiSettings.onSuccess.call(this, response, $module, xhr);
875
+ }
853
876
  }
854
877
  }
855
878
  ;
856
879
  if( !$module.api('get request') ) {
857
880
  module.setup.api();
858
881
  }
859
- apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings);
882
+ apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings, apiCallbacks);
860
883
  $module
861
884
  .api('setting', apiSettings)
862
885
  .api('query')
@@ -892,30 +915,18 @@ $.fn.dropdown = function(parameters) {
892
915
  }
893
916
  if(settings.match === 'both' || settings.match === 'text') {
894
917
  text = module.remove.diacritics(String(module.get.choiceText($choice, false)));
895
- if(text.search(beginsWithRegExp) !== -1) {
896
- results.push(this);
897
- return true;
898
- }
899
- else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
900
- results.push(this);
901
- return true;
902
- }
903
- else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
918
+ if(text.search(beginsWithRegExp) !== -1 ||
919
+ (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) ||
920
+ (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text))) {
904
921
  results.push(this);
905
922
  return true;
906
923
  }
907
924
  }
908
925
  if(settings.match === 'both' || settings.match === 'value') {
909
926
  value = module.remove.diacritics(String(module.get.choiceValue($choice, text)));
910
- if(value.search(beginsWithRegExp) !== -1) {
911
- results.push(this);
912
- return true;
913
- }
914
- else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value)) {
915
- results.push(this);
916
- return true;
917
- }
918
- else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value)) {
927
+ if(value.search(beginsWithRegExp) !== -1 ||
928
+ (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value)) ||
929
+ (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value))) {
919
930
  results.push(this);
920
931
  return true;
921
932
  }
@@ -1044,7 +1055,7 @@ $.fn.dropdown = function(parameters) {
1044
1055
  menuConfig[fields.values] = values;
1045
1056
  module.setup.menu(menuConfig);
1046
1057
  $.each(values, function(index, item) {
1047
- if(item.selected == true) {
1058
+ if(item.selected === true) {
1048
1059
  module.debug('Setting initial selection to', item[fields.value]);
1049
1060
  module.set.selected(item[fields.value]);
1050
1061
  if(!module.is.multiple()) {
@@ -1065,7 +1076,7 @@ $.fn.dropdown = function(parameters) {
1065
1076
  settings.preserveHTML
1066
1077
  )
1067
1078
  ;
1068
- $input.append('<option value="' + value + '">' + name + '</option>');
1079
+ $input.append('<option value="' + value + '"' + (item.selected === true ? ' selected' : '') + '>' + name + '</option>');
1069
1080
  });
1070
1081
  module.observe.select();
1071
1082
  }
@@ -1073,6 +1084,15 @@ $.fn.dropdown = function(parameters) {
1073
1084
  },
1074
1085
 
1075
1086
  event: {
1087
+ paste: function(event) {
1088
+ var pasteValue = (event.originalEvent.clipboardData || window.clipboardData).getData('text'),
1089
+ tokens = pasteValue.split(settings.delimiter)
1090
+ ;
1091
+ tokens.forEach(function(value){
1092
+ module.set.selected(module.escape.htmlEntities(value.trim()), null, true, true);
1093
+ });
1094
+ event.preventDefault();
1095
+ },
1076
1096
  change: function() {
1077
1097
  if(!internalChange) {
1078
1098
  module.debug('Input changed, updating selection');
@@ -1093,7 +1113,7 @@ $.fn.dropdown = function(parameters) {
1093
1113
  }
1094
1114
  },
1095
1115
  mousedown: function() {
1096
- if(module.is.searchSelection()) {
1116
+ if(module.is.searchSelection(true)) {
1097
1117
  // prevent menu hiding on immediate re-focus
1098
1118
  willRefocus = true;
1099
1119
  }
@@ -1103,7 +1123,7 @@ $.fn.dropdown = function(parameters) {
1103
1123
  }
1104
1124
  },
1105
1125
  mouseup: function() {
1106
- if(module.is.searchSelection()) {
1126
+ if(module.is.searchSelection(true)) {
1107
1127
  // prevent menu hiding on immediate re-focus
1108
1128
  willRefocus = false;
1109
1129
  }
@@ -1131,14 +1151,14 @@ $.fn.dropdown = function(parameters) {
1131
1151
  if(module.is.multiple()) {
1132
1152
  module.remove.activeLabel();
1133
1153
  }
1134
- if(!focused && !module.is.active() && (settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin'))) {
1154
+ if(!focused && !module.is.active() && (settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin')) && event.type !== 'touchstart') {
1135
1155
  focused = true;
1136
1156
  module.search();
1137
1157
  }
1138
1158
  },
1139
1159
  blur: function(event) {
1140
1160
  pageLostFocus = (document.activeElement === this);
1141
- if(module.is.searchSelection() && !willRefocus) {
1161
+ if(module.is.searchSelection(true) && !willRefocus) {
1142
1162
  if(!itemActivated && !pageLostFocus) {
1143
1163
  if(settings.forceSelection) {
1144
1164
  module.forceSelection();
@@ -1249,23 +1269,12 @@ $.fn.dropdown = function(parameters) {
1249
1269
  if (!module.is.multiple() || (module.is.multiple() && !module.is.active())) {
1250
1270
  focused = true;
1251
1271
  }
1252
- if( module.determine.eventOnElement(event, toggleBehavior) ) {
1272
+ if( module.determine.eventOnElement(event, toggleBehavior) && event.type !== 'touchstart') {
1273
+ // do not preventDefault of touchstart; so emulated mouseenter is triggered on first touch and not later
1274
+ // (when selecting an item). The double-showing of the dropdown through both events does not hurt.
1253
1275
  event.preventDefault();
1254
1276
  }
1255
1277
  },
1256
- touch: function(event) {
1257
- module.determine.eventOnElement(event, function() {
1258
- if(event.type == 'touchstart') {
1259
- module.timer = setTimeout(function() {
1260
- module.hide();
1261
- }, settings.delay.touch);
1262
- }
1263
- else if(event.type == 'touchmove') {
1264
- clearTimeout(module.timer);
1265
- }
1266
- });
1267
- event.stopPropagation();
1268
- },
1269
1278
  hide: function(event) {
1270
1279
  if(module.determine.eventInModule(event, module.hide)){
1271
1280
  if(element.id && $(event.target).attr('for') === element.id){
@@ -1285,8 +1294,8 @@ $.fn.dropdown = function(parameters) {
1285
1294
  },
1286
1295
  select: {
1287
1296
  mutation: function(mutations) {
1288
- module.debug('<select> modified, recreating menu');
1289
1297
  if(module.is.selectMutation(mutations)) {
1298
+ module.debug('<select> modified, recreating menu');
1290
1299
  module.disconnect.selectObserver();
1291
1300
  module.refresh();
1292
1301
  module.setup.select();
@@ -1349,13 +1358,15 @@ $.fn.dropdown = function(parameters) {
1349
1358
  },
1350
1359
  mouseleave: function(event) {
1351
1360
  var
1352
- $subMenu = $(this).children(selector.menu)
1361
+ $subMenu = $(this).find(selector.menu)
1353
1362
  ;
1354
1363
  if($subMenu.length > 0) {
1355
1364
  clearTimeout(module.itemTimer);
1356
1365
  module.itemTimer = setTimeout(function() {
1357
1366
  module.verbose('Hiding sub-menu', $subMenu);
1358
- module.animate.hide(false, $subMenu);
1367
+ $subMenu.each(function() {
1368
+ module.animate.hide(false, $(this));
1369
+ });
1359
1370
  }, settings.delay.hide);
1360
1371
  }
1361
1372
  },
@@ -1380,8 +1391,12 @@ $.fn.dropdown = function(parameters) {
1380
1391
  if(settings.allowAdditions) {
1381
1392
  module.remove.userAddition();
1382
1393
  }
1394
+ module.remove.filteredItem();
1395
+ if(!module.is.visible()) {
1396
+ module.show();
1397
+ }
1383
1398
  module.remove.searchTerm();
1384
- if(!module.is.focusedOnSearch() && !(skipRefocus == true)) {
1399
+ if(!module.is.focusedOnSearch() && skipRefocus !== true) {
1385
1400
  module.focusSearch(true);
1386
1401
  }
1387
1402
  }
@@ -1416,8 +1431,7 @@ $.fn.dropdown = function(parameters) {
1416
1431
  isFocusedOnSearch = module.is.focusedOnSearch(),
1417
1432
  isFocused = module.is.focused(),
1418
1433
  caretAtStart = (isFocusedOnSearch && module.get.caretPosition(false) === 0),
1419
- isSelectedSearch = (caretAtStart && module.get.caretPosition(true) !== 0),
1420
- $nextLabel
1434
+ isSelectedSearch = (caretAtStart && module.get.caretPosition(true) !== 0)
1421
1435
  ;
1422
1436
  if(isSearch && !hasActiveLabel && !isFocusedOnSearch) {
1423
1437
  return;
@@ -1495,12 +1509,18 @@ $.fn.dropdown = function(parameters) {
1495
1509
  }
1496
1510
  $activeLabel.last().next(selector.siblingLabel).addClass(className.active);
1497
1511
  module.remove.activeLabels($activeLabel);
1512
+ if(!module.is.visible()){
1513
+ module.show();
1514
+ }
1498
1515
  event.preventDefault();
1499
1516
  }
1500
1517
  else if(caretAtStart && !isSelectedSearch && !hasActiveLabel && pressedKey == keys.backspace) {
1501
1518
  module.verbose('Removing last label on input backspace');
1502
1519
  $activeLabel = $label.last().addClass(className.active);
1503
1520
  module.remove.activeLabels($activeLabel);
1521
+ if(!module.is.visible()){
1522
+ module.show();
1523
+ }
1504
1524
  }
1505
1525
  }
1506
1526
  else {
@@ -1513,7 +1533,7 @@ $.fn.dropdown = function(parameters) {
1513
1533
  keydown: function(event) {
1514
1534
  var
1515
1535
  pressedKey = event.which,
1516
- isShortcutKey = module.is.inObject(pressedKey, keys)
1536
+ isShortcutKey = module.is.inObject(pressedKey, keys) || event.key === settings.delimiter
1517
1537
  ;
1518
1538
  if(isShortcutKey) {
1519
1539
  var
@@ -1531,16 +1551,17 @@ $.fn.dropdown = function(parameters) {
1531
1551
  hasSubMenu = ($subMenu.length> 0),
1532
1552
  hasSelectedItem = ($selectedItem.length > 0),
1533
1553
  selectedIsSelectable = ($selectedItem.not(selector.unselectable).length > 0),
1534
- delimiterPressed = (pressedKey == keys.delimiter && settings.allowAdditions && module.is.multiple()),
1535
- isAdditionWithoutMenu = (settings.allowAdditions && settings.hideAdditions && (pressedKey == keys.enter || delimiterPressed) && selectedIsSelectable),
1554
+ delimiterPressed = (event.key === settings.delimiter && module.is.multiple()),
1555
+ isAdditionWithoutMenu = settings.allowAdditions && (pressedKey == keys.enter || delimiterPressed),
1536
1556
  $nextItem,
1537
- isSubMenuItem,
1538
- newIndex
1557
+ isSubMenuItem
1539
1558
  ;
1540
1559
  // allow selection with menu closed
1541
1560
  if(isAdditionWithoutMenu) {
1542
- module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1543
- module.event.item.click.call($selectedItem, event);
1561
+ if (selectedIsSelectable && settings.hideAdditions) {
1562
+ module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1563
+ module.event.item.click.call($selectedItem, event);
1564
+ }
1544
1565
  if(module.is.searchSelection()) {
1545
1566
  module.remove.searchTerm();
1546
1567
  }
@@ -1629,7 +1650,7 @@ $.fn.dropdown = function(parameters) {
1629
1650
  .addClass(className.selected)
1630
1651
  ;
1631
1652
  module.set.scrollPosition($nextItem);
1632
- if(settings.selectOnKeydown && module.is.single()) {
1653
+ if(settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
1633
1654
  module.set.selectedItem($nextItem);
1634
1655
  }
1635
1656
  }
@@ -1639,7 +1660,7 @@ $.fn.dropdown = function(parameters) {
1639
1660
  // down arrow (traverse menu down)
1640
1661
  if(pressedKey == keys.downArrow) {
1641
1662
  $nextItem = (hasSelectedItem && inVisibleMenu)
1642
- ? $nextItem = $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
1663
+ ? $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
1643
1664
  : $item.eq(0)
1644
1665
  ;
1645
1666
  if($nextItem.length === 0) {
@@ -1656,7 +1677,7 @@ $.fn.dropdown = function(parameters) {
1656
1677
  .addClass(className.selected)
1657
1678
  ;
1658
1679
  module.set.scrollPosition($nextItem);
1659
- if(settings.selectOnKeydown && module.is.single()) {
1680
+ if(settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
1660
1681
  module.set.selectedItem($nextItem);
1661
1682
  }
1662
1683
  }
@@ -1677,12 +1698,13 @@ $.fn.dropdown = function(parameters) {
1677
1698
  if(pressedKey == keys.escape) {
1678
1699
  module.verbose('Escape key pressed, closing dropdown');
1679
1700
  module.hide();
1701
+ event.stopPropagation();
1680
1702
  }
1681
1703
 
1682
1704
  }
1683
1705
  else {
1684
1706
  // delimiter key
1685
- if(delimiterPressed) {
1707
+ if(pressedKey == keys.enter || delimiterPressed) {
1686
1708
  event.preventDefault();
1687
1709
  }
1688
1710
  // down arrow (open menu)
@@ -1787,7 +1809,7 @@ $.fn.dropdown = function(parameters) {
1787
1809
  ;
1788
1810
  if( module.can.activate( $(element) ) ) {
1789
1811
  module.set.selected(value, $(element));
1790
- if(!module.is.multiple()) {
1812
+ if(!module.is.multiple() && !(!settings.collapseOnActionable && $(element).hasClass(className.actionable))) {
1791
1813
  module.hideAndClear();
1792
1814
  }
1793
1815
  }
@@ -1800,7 +1822,7 @@ $.fn.dropdown = function(parameters) {
1800
1822
  ;
1801
1823
  if( module.can.activate( $(element) ) ) {
1802
1824
  module.set.value(value, text, $(element));
1803
- if(!module.is.multiple()) {
1825
+ if(!module.is.multiple() && !(!settings.collapseOnActionable && $(element).hasClass(className.actionable))) {
1804
1826
  module.hideAndClear();
1805
1827
  }
1806
1828
  }
@@ -1851,7 +1873,7 @@ $.fn.dropdown = function(parameters) {
1851
1873
  ;
1852
1874
  $sizer.text(value);
1853
1875
  // prevent rounding issues
1854
- return Math.ceil( $sizer.width() + 1);
1876
+ return Math.ceil( $sizer.width() + (module.is.edge() ? 3 : 1));
1855
1877
  },
1856
1878
  selectionCount: function() {
1857
1879
  var
@@ -1878,7 +1900,7 @@ $.fn.dropdown = function(parameters) {
1878
1900
  },
1879
1901
  userValues: function() {
1880
1902
  var
1881
- values = module.get.values()
1903
+ values = module.get.values(true)
1882
1904
  ;
1883
1905
  if(!values) {
1884
1906
  return false;
@@ -1898,7 +1920,7 @@ $.fn.dropdown = function(parameters) {
1898
1920
  },
1899
1921
  caretPosition: function(returnEndPos) {
1900
1922
  var
1901
- input = $search.get(0),
1923
+ input = $search[0],
1902
1924
  range,
1903
1925
  rangeLength
1904
1926
  ;
@@ -2320,7 +2342,7 @@ $.fn.dropdown = function(parameters) {
2320
2342
  module.error(error.noStorage);
2321
2343
  return;
2322
2344
  }
2323
- name = sessionStorage.getItem(value);
2345
+ name = sessionStorage.getItem(value + elementNamespace);
2324
2346
  return (name !== undefined)
2325
2347
  ? name
2326
2348
  : false
@@ -2364,7 +2386,7 @@ $.fn.dropdown = function(parameters) {
2364
2386
  return;
2365
2387
  }
2366
2388
  module.verbose('Saving remote data to session storage', value, name);
2367
- sessionStorage.setItem(value, name);
2389
+ sessionStorage.setItem(value + elementNamespace, name);
2368
2390
  }
2369
2391
  },
2370
2392
 
@@ -2393,7 +2415,6 @@ $.fn.dropdown = function(parameters) {
2393
2415
  currentScroll = $menu.scrollTop(),
2394
2416
  itemHeight = $item.eq(0).outerHeight(),
2395
2417
  itemsPerPage = Math.floor(menuHeight / itemHeight),
2396
- maxScroll = $menu.prop('scrollHeight'),
2397
2418
  newScroll = (direction == 'up')
2398
2419
  ? currentScroll - (itemHeight * itemsPerPage)
2399
2420
  : currentScroll + (itemHeight * itemsPerPage),
@@ -2424,7 +2445,7 @@ $.fn.dropdown = function(parameters) {
2424
2445
  $nextSelectedItem
2425
2446
  .addClass(className.selected)
2426
2447
  ;
2427
- if(settings.selectOnKeydown && module.is.single()) {
2448
+ if(settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
2428
2449
  module.set.selectedItem($nextSelectedItem);
2429
2450
  }
2430
2451
  $menu
@@ -2510,7 +2531,7 @@ $.fn.dropdown = function(parameters) {
2510
2531
  var
2511
2532
  length = module.get.query().length
2512
2533
  ;
2513
- $search.val( text.substr(0, length));
2534
+ $search.val( text.slice(0, length));
2514
2535
  },
2515
2536
  scrollPosition: function($item, forceScroll) {
2516
2537
  var
@@ -2518,7 +2539,6 @@ $.fn.dropdown = function(parameters) {
2518
2539
  $menu,
2519
2540
  hasActive,
2520
2541
  offset,
2521
- itemHeight,
2522
2542
  itemOffset,
2523
2543
  menuOffset,
2524
2544
  menuScroll,
@@ -2557,7 +2577,7 @@ $.fn.dropdown = function(parameters) {
2557
2577
  $menu.removeClass(className.loading);
2558
2578
  }
2559
2579
  },
2560
- text: function(text) {
2580
+ text: function(text, isNotPlaceholder) {
2561
2581
  if(settings.action === 'combo') {
2562
2582
  module.debug('Changing combo button text', text, $combo);
2563
2583
  if(settings.preserveHTML) {
@@ -2568,7 +2588,7 @@ $.fn.dropdown = function(parameters) {
2568
2588
  }
2569
2589
  }
2570
2590
  else if(settings.action === 'activate') {
2571
- if(text !== module.get.placeholderText()) {
2591
+ if(text !== module.get.placeholderText() || isNotPlaceholder) {
2572
2592
  $text.removeClass(className.placeholder);
2573
2593
  }
2574
2594
  module.debug('Changing text', text, $text);
@@ -2587,7 +2607,7 @@ $.fn.dropdown = function(parameters) {
2587
2607
  var
2588
2608
  value = module.get.choiceValue($item),
2589
2609
  searchText = module.get.choiceText($item, false),
2590
- text = module.get.choiceText($item, true)
2610
+ text = module.get.choiceText($item)
2591
2611
  ;
2592
2612
  module.debug('Setting user selection to item', $item);
2593
2613
  module.remove.activeItem();
@@ -2627,13 +2647,13 @@ $.fn.dropdown = function(parameters) {
2627
2647
  module.set.scrollPosition($nextValue);
2628
2648
  $selectedItem.removeClass(className.selected);
2629
2649
  $nextValue.addClass(className.selected);
2630
- if(settings.selectOnKeydown && module.is.single()) {
2650
+ if(settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
2631
2651
  module.set.selectedItem($nextValue);
2632
2652
  }
2633
2653
  }
2634
2654
  },
2635
2655
  direction: function($menu) {
2636
- if(settings.direction == 'auto') {
2656
+ if(settings.direction === 'auto') {
2637
2657
  // reset position, remove upward if it's base menu
2638
2658
  if (!$menu) {
2639
2659
  module.remove.upward();
@@ -2652,7 +2672,7 @@ $.fn.dropdown = function(parameters) {
2652
2672
  module.set.leftward($menu);
2653
2673
  }
2654
2674
  }
2655
- else if(settings.direction == 'upward') {
2675
+ else if(settings.direction === 'upward') {
2656
2676
  module.set.upward($menu);
2657
2677
  }
2658
2678
  },
@@ -2665,6 +2685,11 @@ $.fn.dropdown = function(parameters) {
2665
2685
  $element.addClass(className.leftward);
2666
2686
  },
2667
2687
  value: function(value, text, $selected, preventChangeTrigger) {
2688
+ if(typeof text === 'boolean') {
2689
+ preventChangeTrigger = text;
2690
+ $selected = undefined;
2691
+ text = undefined;
2692
+ }
2668
2693
  if(value !== undefined && value !== '' && !(Array.isArray(value) && value.length === 0)) {
2669
2694
  $input.removeClass(className.noselection);
2670
2695
  } else {
@@ -2676,8 +2701,7 @@ $.fn.dropdown = function(parameters) {
2676
2701
  currentValue = module.get.values(),
2677
2702
  stringValue = (value !== undefined)
2678
2703
  ? String(value)
2679
- : value,
2680
- newValue
2704
+ : value
2681
2705
  ;
2682
2706
  if(hasInput) {
2683
2707
  if(!settings.allowReselection && stringValue == currentValue) {
@@ -2728,12 +2752,21 @@ $.fn.dropdown = function(parameters) {
2728
2752
  visible: function() {
2729
2753
  $module.addClass(className.visible);
2730
2754
  },
2731
- exactly: function(value, $selectedItem) {
2755
+ exactly: function(value, $selectedItem, preventChangeTrigger) {
2756
+ if(typeof $selectedItem === 'boolean') {
2757
+ preventChangeTrigger = $selectedItem;
2758
+ $selectedItem = undefined;
2759
+ }
2732
2760
  module.debug('Setting selected to exact values');
2733
2761
  module.clear();
2734
- module.set.selected(value, $selectedItem);
2762
+ module.set.selected(value, $selectedItem, preventChangeTrigger);
2735
2763
  },
2736
2764
  selected: function(value, $selectedItem, preventChangeTrigger, keepSearchTerm) {
2765
+ if(typeof $selectedItem === 'boolean') {
2766
+ keepSearchTerm = preventChangeTrigger;
2767
+ preventChangeTrigger = $selectedItem;
2768
+ $selectedItem = undefined;
2769
+ }
2737
2770
  var
2738
2771
  isMultiple = module.is.multiple()
2739
2772
  ;
@@ -2765,23 +2798,30 @@ $.fn.dropdown = function(parameters) {
2765
2798
 
2766
2799
  isFiltered = $selected.hasClass(className.filtered),
2767
2800
  isActive = $selected.hasClass(className.active),
2801
+ isActionable = $selected.hasClass(className.actionable),
2768
2802
  isUserValue = $selected.hasClass(className.addition),
2769
- shouldAnimate = (isMultiple && $selectedItem.length == 1)
2803
+ shouldAnimate = (isMultiple && $selectedItem && $selectedItem.length === 1)
2770
2804
  ;
2771
- if(isMultiple) {
2805
+ if(isActionable){
2806
+ if((!isMultiple || (!isActive || isUserValue)) && settings.apiSettings && settings.saveRemoteData) {
2807
+ module.save.remoteData(selectedText, selectedValue);
2808
+ }
2809
+ settings.onActionable.call(element, selectedValue, selectedText, $selected);
2810
+ }
2811
+ else if(isMultiple) {
2772
2812
  if(!isActive || isUserValue) {
2773
2813
  if(settings.apiSettings && settings.saveRemoteData) {
2774
2814
  module.save.remoteData(selectedText, selectedValue);
2775
2815
  }
2776
2816
  if(settings.useLabels) {
2817
+ module.add.value(selectedValue, selectedText, $selected, preventChangeTrigger);
2777
2818
  module.add.label(selectedValue, selectedText, shouldAnimate);
2778
- module.add.value(selectedValue, selectedText, $selected);
2779
2819
  module.set.activeItem($selected);
2780
2820
  module.filterActive();
2781
2821
  module.select.nextAvailable($selectedItem);
2782
2822
  }
2783
2823
  else {
2784
- module.add.value(selectedValue, selectedText, $selected);
2824
+ module.add.value(selectedValue, selectedText, $selected, preventChangeTrigger);
2785
2825
  module.set.text(module.add.variables(message.count));
2786
2826
  module.set.activeItem($selected);
2787
2827
  }
@@ -2795,8 +2835,8 @@ $.fn.dropdown = function(parameters) {
2795
2835
  if(settings.apiSettings && settings.saveRemoteData) {
2796
2836
  module.save.remoteData(selectedText, selectedValue);
2797
2837
  }
2798
- if (!keepSearchTerm) {
2799
- module.set.text(selectedText);
2838
+ if (!keepSearchTerm && !$selected.hasClass(className.actionable)) {
2839
+ module.set.text(selectedText, true);
2800
2840
  }
2801
2841
  module.set.value(selectedValue, selectedText, $selected, preventChangeTrigger);
2802
2842
  $selected
@@ -2809,6 +2849,10 @@ $.fn.dropdown = function(parameters) {
2809
2849
  if (!keepSearchTerm) {
2810
2850
  module.remove.searchTerm();
2811
2851
  }
2852
+ if(module.is.allFiltered()) {
2853
+ module.set.empty();
2854
+ module.hideMenu();
2855
+ }
2812
2856
  }
2813
2857
  },
2814
2858
 
@@ -2847,6 +2891,7 @@ $.fn.dropdown = function(parameters) {
2847
2891
  animation : settings.label.transition,
2848
2892
  debug : settings.debug,
2849
2893
  verbose : settings.verbose,
2894
+ silent : settings.silent,
2850
2895
  duration : settings.label.duration
2851
2896
  })
2852
2897
  ;
@@ -2869,7 +2914,7 @@ $.fn.dropdown = function(parameters) {
2869
2914
  ;
2870
2915
  }
2871
2916
  else {
2872
- $message = $('<div/>')
2917
+ $('<div/>')
2873
2918
  .html(html)
2874
2919
  .addClass(className.message)
2875
2920
  .appendTo($menu)
@@ -2894,7 +2939,7 @@ $.fn.dropdown = function(parameters) {
2894
2939
  $('<option/>')
2895
2940
  .prop('value', escapedValue)
2896
2941
  .addClass(className.addition)
2897
- .html(value)
2942
+ .text(value)
2898
2943
  .appendTo($input)
2899
2944
  ;
2900
2945
  module.verbose('Adding user addition as an <option>', value);
@@ -2952,16 +2997,13 @@ $.fn.dropdown = function(parameters) {
2952
2997
  hasCount = (message.search('{count}') !== -1),
2953
2998
  hasMaxCount = (message.search('{maxCount}') !== -1),
2954
2999
  hasTerm = (message.search('{term}') !== -1),
2955
- count,
2956
3000
  query
2957
3001
  ;
2958
3002
  module.verbose('Adding templated variables to message', message);
2959
3003
  if(hasCount) {
2960
- count = module.get.selectionCount();
2961
- message = message.replace('{count}', count);
3004
+ message = message.replace('{count}', module.get.selectionCount());
2962
3005
  }
2963
3006
  if(hasMaxCount) {
2964
- count = module.get.selectionCount();
2965
3007
  message = message.replace('{maxCount}', settings.maxSelections);
2966
3008
  }
2967
3009
  if(hasTerm) {
@@ -2970,7 +3012,12 @@ $.fn.dropdown = function(parameters) {
2970
3012
  }
2971
3013
  return message;
2972
3014
  },
2973
- value: function(addedValue, addedText, $selectedItem) {
3015
+ value: function(addedValue, addedText, $selectedItem, preventChangeTrigger) {
3016
+ if(typeof addedText === 'boolean') {
3017
+ preventChangeTrigger = addedText;
3018
+ $selectedItem = undefined;
3019
+ addedText = undefined;
3020
+ }
2974
3021
  var
2975
3022
  currentValue = module.get.values(true),
2976
3023
  newValue
@@ -2985,7 +3032,7 @@ $.fn.dropdown = function(parameters) {
2985
3032
  }
2986
3033
  // extend current array
2987
3034
  if(Array.isArray(currentValue)) {
2988
- newValue = currentValue.concat([addedValue]);
3035
+ newValue = $selectedItem && $selectedItem.hasClass(className.actionable) ? currentValue : currentValue.concat([addedValue]);
2989
3036
  newValue = module.get.uniqueArray(newValue);
2990
3037
  }
2991
3038
  else {
@@ -3009,7 +3056,7 @@ $.fn.dropdown = function(parameters) {
3009
3056
  else {
3010
3057
  settings.onAdd.call(element, addedValue, addedText, $selectedItem);
3011
3058
  }
3012
- module.set.value(newValue, addedText, $selectedItem);
3059
+ module.set.value(newValue, addedText, $selectedItem, preventChangeTrigger);
3013
3060
  module.check.maxSelections();
3014
3061
  },
3015
3062
  },
@@ -3069,18 +3116,10 @@ $.fn.dropdown = function(parameters) {
3069
3116
  return;
3070
3117
  }
3071
3118
  // temporarily disconnect observer
3072
- if(selectObserver) {
3073
- selectObserver.disconnect();
3074
- module.verbose('Temporarily disconnecting mutation observer');
3075
- }
3119
+ module.disconnect.selectObserver();
3076
3120
  $option.remove();
3077
3121
  module.verbose('Removing user addition as an <option>', escapedValue);
3078
- if(selectObserver) {
3079
- selectObserver.observe($input[0], {
3080
- childList : true,
3081
- subtree : true
3082
- });
3083
- }
3122
+ module.observe.select();
3084
3123
  },
3085
3124
  message: function() {
3086
3125
  $menu.children(selector.message).remove();
@@ -3146,10 +3185,9 @@ $.fn.dropdown = function(parameters) {
3146
3185
  },
3147
3186
  value: function(removedValue, removedText, $removedItem, preventChangeTrigger) {
3148
3187
  var
3149
- values = module.get.values(),
3188
+ values = module.get.values(true),
3150
3189
  newValue
3151
3190
  ;
3152
- removedValue = module.escape.htmlEntities(removedValue);
3153
3191
  if( module.has.selectInput() ) {
3154
3192
  module.verbose('Input is <select> removing selected option', removedValue);
3155
3193
  newValue = module.remove.arrayValue(removedValue, values);
@@ -3379,8 +3417,14 @@ $.fn.dropdown = function(parameters) {
3379
3417
  bubbledIconClick: function(event) {
3380
3418
  return $(event.target).closest($icon).length > 0;
3381
3419
  },
3420
+ edge: function() {
3421
+ return !!window.chrome && !!window.StyleMedia;
3422
+ },
3423
+ empty: function() {
3424
+ return $module.hasClass(className.empty);
3425
+ },
3382
3426
  chrome: function() {
3383
- return !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
3427
+ return !!window.chrome && !window.StyleMedia;
3384
3428
  },
3385
3429
  alreadySetup: function() {
3386
3430
  return ($module.is('select') && $module.parent(selector.dropdown).data(moduleNamespace) !== undefined && $module.prev().length === 0);
@@ -3408,7 +3452,7 @@ $.fn.dropdown = function(parameters) {
3408
3452
  return (document.activeElement === $search[0]);
3409
3453
  },
3410
3454
  allFiltered: function() {
3411
- return( (module.is.multiple() || module.has.search()) && !(settings.hideAdditions == false && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered() );
3455
+ return( (module.is.multiple() || module.has.search()) && !(!settings.hideAdditions && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered() );
3412
3456
  },
3413
3457
  hidden: function($subMenu) {
3414
3458
  return !module.is.visible($subMenu);
@@ -3445,7 +3489,7 @@ $.fn.dropdown = function(parameters) {
3445
3489
  selectChanged = false
3446
3490
  ;
3447
3491
  $.each(mutations, function(index, mutation) {
3448
- if($(mutation.target).is('select') || $(mutation.addedNodes).is('select')) {
3492
+ if($(mutation.target).is('select, option, optgroup') || $(mutation.addedNodes).is('select')) {
3449
3493
  selectChanged = true;
3450
3494
  return false;
3451
3495
  }
@@ -3455,8 +3499,8 @@ $.fn.dropdown = function(parameters) {
3455
3499
  search: function() {
3456
3500
  return $module.hasClass(className.search);
3457
3501
  },
3458
- searchSelection: function() {
3459
- return ( module.has.search() && $search.parent(selector.dropdown).length === 1 );
3502
+ searchSelection: function(deep) {
3503
+ return ( module.has.search() && (deep ? $search.parents(selector.dropdown) : $search.parent(selector.dropdown)).length === 1 );
3460
3504
  },
3461
3505
  selection: function() {
3462
3506
  return $module.hasClass(className.selection);
@@ -3476,7 +3520,7 @@ $.fn.dropdown = function(parameters) {
3476
3520
  },
3477
3521
  verticallyScrollableContext: function() {
3478
3522
  var
3479
- overflowY = ($context.get(0) !== window)
3523
+ overflowY = ($context[0] !== window)
3480
3524
  ? $context.css('overflow-y')
3481
3525
  : false
3482
3526
  ;
@@ -3484,7 +3528,7 @@ $.fn.dropdown = function(parameters) {
3484
3528
  },
3485
3529
  horizontallyScrollableContext: function() {
3486
3530
  var
3487
- overflowX = ($context.get(0) !== window)
3531
+ overflowX = ($context[0] !== window)
3488
3532
  ? $context.css('overflow-X')
3489
3533
  : false
3490
3534
  ;
@@ -3494,22 +3538,17 @@ $.fn.dropdown = function(parameters) {
3494
3538
 
3495
3539
  can: {
3496
3540
  activate: function($item) {
3497
- if(settings.useLabels) {
3498
- return true;
3499
- }
3500
- if(!module.has.maxSelections()) {
3501
- return true;
3502
- }
3503
- if(module.has.maxSelections() && $item.hasClass(className.active)) {
3504
- return true;
3505
- }
3506
- return false;
3541
+ return (
3542
+ settings.useLabels ||
3543
+ !module.has.maxSelections() ||
3544
+ (module.has.maxSelections() && $item.hasClass(className.active))
3545
+ );
3507
3546
  },
3508
3547
  openDownward: function($subMenu) {
3509
3548
  var
3510
3549
  $currentMenu = $subMenu || $menu,
3511
- canOpenDownward = true,
3512
- onScreen = {},
3550
+ canOpenDownward,
3551
+ onScreen,
3513
3552
  calculations
3514
3553
  ;
3515
3554
  $currentMenu
@@ -3517,7 +3556,7 @@ $.fn.dropdown = function(parameters) {
3517
3556
  ;
3518
3557
  calculations = {
3519
3558
  context: {
3520
- offset : ($context.get(0) === window)
3559
+ offset : ($context[0] === window)
3521
3560
  ? { top: 0, left: 0}
3522
3561
  : $context.offset(),
3523
3562
  scrollTop : $context.scrollTop(),
@@ -3565,7 +3604,7 @@ $.fn.dropdown = function(parameters) {
3565
3604
  ;
3566
3605
  calculations = {
3567
3606
  context: {
3568
- offset : ($context.get(0) === window)
3607
+ offset : ($context[0] === window)
3569
3608
  ? { top: 0, left: 0}
3570
3609
  : $context.offset(),
3571
3610
  scrollLeft : $context.scrollLeft(),
@@ -3587,9 +3626,6 @@ $.fn.dropdown = function(parameters) {
3587
3626
  $currentMenu.removeClass(className.loading);
3588
3627
  return canOpenRightward;
3589
3628
  },
3590
- click: function() {
3591
- return (hasTouch || settings.on == 'click');
3592
- },
3593
3629
  extendSelect: function() {
3594
3630
  return settings.allowAdditions || settings.apiSettings;
3595
3631
  },
@@ -3638,6 +3674,7 @@ $.fn.dropdown = function(parameters) {
3638
3674
  animation : transition + ' in',
3639
3675
  debug : settings.debug,
3640
3676
  verbose : settings.verbose,
3677
+ silent : settings.silent,
3641
3678
  duration : settings.transition.showDuration || settings.duration,
3642
3679
  queue : true,
3643
3680
  onStart : start,
@@ -3659,9 +3696,7 @@ $.fn.dropdown = function(parameters) {
3659
3696
  start = ($subMenu)
3660
3697
  ? function() {}
3661
3698
  : function() {
3662
- if( module.can.click() ) {
3663
- module.unbind.intent();
3664
- }
3699
+ module.unbind.intent();
3665
3700
  module.remove.active();
3666
3701
  },
3667
3702
  transition = settings.transition.hideMethod || module.get.transition($subMenu)
@@ -3687,6 +3722,7 @@ $.fn.dropdown = function(parameters) {
3687
3722
  duration : settings.transition.hideDuration || settings.duration,
3688
3723
  debug : settings.debug,
3689
3724
  verbose : settings.verbose,
3725
+ silent : settings.silent,
3690
3726
  queue : false,
3691
3727
  onStart : start,
3692
3728
  displayType: module.get.displayType(),
@@ -3772,7 +3808,7 @@ $.fn.dropdown = function(parameters) {
3772
3808
  }
3773
3809
  ;
3774
3810
  if(shouldEscape.test(string)) {
3775
- string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
3811
+ string = string.replace(/&(?![a-z0-9#]{1,12};)/gi, "&amp;");
3776
3812
  return string.replace(badChars, escapedChar);
3777
3813
  }
3778
3814
  return string;
@@ -3894,7 +3930,7 @@ $.fn.dropdown = function(parameters) {
3894
3930
  response
3895
3931
  ;
3896
3932
  passedArguments = passedArguments || queryArguments;
3897
- context = element || context;
3933
+ context = context || element;
3898
3934
  if(typeof query == 'string' && object !== undefined) {
3899
3935
  query = query.split(/[\. ]/);
3900
3936
  maxDepth = query.length - 1;
@@ -3990,7 +4026,7 @@ $.fn.dropdown.settings = {
3990
4026
  keepOnScreen : true, // Whether dropdown should check whether it is on screen before showing
3991
4027
 
3992
4028
  match : 'both', // what to match against with search selection (both, text, or label)
3993
- fullTextSearch : false, // search anywhere in value (set to 'exact' to require exact matches)
4029
+ fullTextSearch : 'exact', // search anywhere in value (set to 'exact' to require exact matches)
3994
4030
  ignoreDiacritics : false, // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
3995
4031
  hideDividers : false, // Whether to hide any divider elements (specified in selector.divider) that are sibling to any items when searched (set to true will hide all dividers, set to 'empty' will hide them when they are not followed by a visible item)
3996
4032
 
@@ -3998,7 +4034,7 @@ $.fn.dropdown.settings = {
3998
4034
  preserveHTML : true, // preserve html when selecting value
3999
4035
  sortSelect : false, // sort selection on init
4000
4036
 
4001
- forceSelection : true, // force a choice on blur with search selection
4037
+ forceSelection : false, // force a choice on blur with search selection
4002
4038
 
4003
4039
  allowAdditions : false, // whether multiple select should allow user added values
4004
4040
  ignoreCase : false, // whether to consider case sensitivity when creating labels
@@ -4009,7 +4045,7 @@ $.fn.dropdown.settings = {
4009
4045
  useLabels : true, // whether multiple select should filter currently active selections from choices
4010
4046
  delimiter : ',', // when multiselect uses normal <input> the values will be delimited with this character
4011
4047
 
4012
- showOnFocus : true, // show menu on focus
4048
+ showOnFocus : false, // show menu on focus
4013
4049
  allowReselection : false, // whether current value should trigger callbacks when reselected
4014
4050
  allowTab : true, // add tabindex to element
4015
4051
  allowCategorySelection : false, // allow elements with sub-menus to be selected
@@ -4024,6 +4060,8 @@ $.fn.dropdown.settings = {
4024
4060
 
4025
4061
  headerDivider : true, // whether option headers should have an additional divider line underneath when converted from <select> <optgroup>
4026
4062
 
4063
+ collapseOnActionable : true, // whether the dropdown should collapse upon selection of an actionable item
4064
+
4027
4065
  // label settings on multi-select
4028
4066
  label: {
4029
4067
  transition : 'scale',
@@ -4036,13 +4074,13 @@ $.fn.dropdown.settings = {
4036
4074
  hide : 300,
4037
4075
  show : 200,
4038
4076
  search : 20,
4039
- touch : 50
4040
4077
  },
4041
4078
 
4042
4079
  /* Callbacks */
4043
4080
  onChange : function(value, text, $selected){},
4044
4081
  onAdd : function(value, text, $selected){},
4045
4082
  onRemove : function(value, text, $selected){},
4083
+ onActionable : function(value, text, $selected){},
4046
4084
  onSearch : function(searchTerm){},
4047
4085
 
4048
4086
  onLabelSelect : function($selectedLabels){},
@@ -4105,12 +4143,12 @@ $.fn.dropdown.settings = {
4105
4143
  icon : 'icon', // optional icon name
4106
4144
  iconClass : 'iconClass', // optional individual class for icon (for example to use flag instead)
4107
4145
  class : 'class', // optional individual class for item/header
4108
- divider : 'divider' // optional divider append for group headers
4146
+ divider : 'divider', // optional divider append for group headers
4147
+ actionable : 'actionable' // optional actionable item
4109
4148
  },
4110
4149
 
4111
4150
  keys : {
4112
4151
  backspace : 8,
4113
- delimiter : 188, // comma
4114
4152
  deleteKey : 46,
4115
4153
  enter : 13,
4116
4154
  escape : 27,
@@ -4177,7 +4215,8 @@ $.fn.dropdown.settings = {
4177
4215
  header : 'header',
4178
4216
  divider : 'divider',
4179
4217
  groupIcon : '',
4180
- unfilterable : 'unfilterable'
4218
+ unfilterable : 'unfilterable',
4219
+ actionable : 'actionable'
4181
4220
  }
4182
4221
 
4183
4222
  };
@@ -4206,7 +4245,7 @@ $.fn.dropdown.settings.templates = {
4206
4245
  }
4207
4246
  ;
4208
4247
  if(shouldEscape.test(string)) {
4209
- string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
4248
+ string = string.replace(/&(?![a-z0-9#]{1,12};)/gi, "&amp;");
4210
4249
  return string.replace(badChars, escapedChar);
4211
4250
  }
4212
4251
  return string;
@@ -4216,7 +4255,8 @@ $.fn.dropdown.settings.templates = {
4216
4255
  var
4217
4256
  placeholder = select.placeholder || false,
4218
4257
  html = '',
4219
- escape = $.fn.dropdown.settings.templates.escape
4258
+ escape = $.fn.dropdown.settings.templates.escape,
4259
+ deQuote = $.fn.dropdown.settings.templates.deQuote
4220
4260
  ;
4221
4261
  html += '<i class="dropdown icon"></i>';
4222
4262
  if(placeholder) {
@@ -4225,7 +4265,7 @@ $.fn.dropdown.settings.templates = {
4225
4265
  else {
4226
4266
  html += '<div class="text"></div>';
4227
4267
  }
4228
- html += '<div class="'+className.menu+'">';
4268
+ html += '<div class="'+deQuote(className.menu)+'">';
4229
4269
  html += $.fn.dropdown.settings.templates.menu(select, fields, preserveHTML,className);
4230
4270
  html += '</div>';
4231
4271
  return html;
@@ -4252,6 +4292,9 @@ $.fn.dropdown.settings.templates = {
4252
4292
  maybeText = (option[fields.text])
4253
4293
  ? ' data-text="' + deQuote(option[fields.text],true) + '"'
4254
4294
  : '',
4295
+ maybeActionable = (option[fields.actionable])
4296
+ ? className.actionable+' '
4297
+ : '',
4255
4298
  maybeDisabled = (option[fields.disabled])
4256
4299
  ? className.disabled+' '
4257
4300
  : '',
@@ -4260,27 +4303,27 @@ $.fn.dropdown.settings.templates = {
4260
4303
  : '',
4261
4304
  hasDescription = (escape(option[fields.description] || '', preserveHTML) != '')
4262
4305
  ;
4263
- html += '<div class="'+ maybeDisabled + maybeDescriptionVertical + (option[fields.class] ? deQuote(option[fields.class]) : className.item)+'" data-value="' + deQuote(option[fields.value],true) + '"' + maybeText + '>';
4306
+ html += '<div class="'+ deQuote(maybeActionable + maybeDisabled + maybeDescriptionVertical + (option[fields.class] ? option[fields.class] : className.item))+'" data-value="' + deQuote(option[fields.value],true) + '"' + maybeText + '>';
4264
4307
  if (isMenu) {
4265
4308
  html += '<i class="'+ (itemType.indexOf('left') !== -1 ? 'left' : '') + ' dropdown icon"></i>';
4266
4309
  }
4267
4310
  if(option[fields.image]) {
4268
- html += '<img class="'+(option[fields.imageClass] ? deQuote(option[fields.imageClass]) : className.image)+'" src="' + deQuote(option[fields.image]) + '">';
4311
+ html += '<img class="'+deQuote(option[fields.imageClass] ? option[fields.imageClass] : className.image)+'" src="' + deQuote(option[fields.image]) + '">';
4269
4312
  }
4270
4313
  if(option[fields.icon]) {
4271
- html += '<i class="'+deQuote(option[fields.icon])+' '+(option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon)+'"></i>';
4314
+ html += '<i class="'+deQuote(option[fields.icon]+' '+(option[fields.iconClass] ? option[fields.iconClass] : className.icon))+'"></i>';
4272
4315
  }
4273
4316
  if(hasDescription){
4274
- html += '<span class="'+ className.description +'">'+ escape(option[fields.description] || '', preserveHTML) + '</span>';
4275
- html += (!isMenu) ? '<span class="'+ className.text + '">' : '';
4317
+ html += '<span class="'+ deQuote(className.description) +'">'+ escape(option[fields.description] || '', preserveHTML) + '</span>';
4318
+ html += (!isMenu) ? '<span class="'+ deQuote(className.text) + '">' : '';
4276
4319
  }
4277
4320
  if (isMenu) {
4278
- html += '<span class="' + className.text + '">';
4321
+ html += '<span class="' + deQuote(className.text) + '">';
4279
4322
  }
4280
4323
  html += escape(option[fields.name] || '', preserveHTML);
4281
4324
  if (isMenu) {
4282
4325
  html += '</span>';
4283
- html += '<div class="' + itemType + '">';
4326
+ html += '<div class="' + deQuote(itemType) + '">';
4284
4327
  html += $.fn.dropdown.settings.templates.menu(option, fields, preserveHTML, className);
4285
4328
  html += '</div>';
4286
4329
  } else if(hasDescription){
@@ -4289,18 +4332,18 @@ $.fn.dropdown.settings.templates = {
4289
4332
  html += '</div>';
4290
4333
  } else if (itemType === 'header') {
4291
4334
  var groupName = escape(option[fields.name] || '', preserveHTML),
4292
- groupIcon = option[fields.icon] ? deQuote(option[fields.icon]) : className.groupIcon
4335
+ groupIcon = deQuote(option[fields.icon] ? option[fields.icon] : className.groupIcon)
4293
4336
  ;
4294
4337
  if(groupName !== '' || groupIcon !== '') {
4295
- html += '<div class="' + (option[fields.class] ? deQuote(option[fields.class]) : className.header) + '">';
4338
+ html += '<div class="' + deQuote(option[fields.class] ? option[fields.class] : className.header) + '">';
4296
4339
  if (groupIcon !== '') {
4297
- html += '<i class="' + groupIcon + ' ' + (option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon) + '"></i>';
4340
+ html += '<i class="' + deQuote(groupIcon + ' ' + (option[fields.iconClass] ? option[fields.iconClass] : className.icon)) + '"></i>';
4298
4341
  }
4299
4342
  html += groupName;
4300
4343
  html += '</div>';
4301
4344
  }
4302
4345
  if(option[fields.divider]){
4303
- html += '<div class="'+className.divider+'"></div>';
4346
+ html += '<div class="'+deQuote(className.divider)+'"></div>';
4304
4347
  }
4305
4348
  }
4306
4349
  });
@@ -4310,8 +4353,10 @@ $.fn.dropdown.settings.templates = {
4310
4353
  // generates label for multiselect
4311
4354
  label: function(value, text, preserveHTML, className) {
4312
4355
  var
4313
- escape = $.fn.dropdown.settings.templates.escape;
4314
- return escape(text,preserveHTML) + '<i class="'+className.delete+' icon"></i>';
4356
+ escape = $.fn.dropdown.settings.templates.escape,
4357
+ deQuote = $.fn.dropdown.settings.templates.deQuote
4358
+ ;
4359
+ return escape(text,preserveHTML) + '<i class="'+deQuote(className.delete)+' icon"></i>';
4315
4360
  },
4316
4361
 
4317
4362