less-rails-semantic_ui 2.1.8.2 → 2.2.1.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/.github/ISSUE_TEMPLATE.md +15 -0
  3. data/assets/fonts/semantic_ui/themes/default/assets/fonts/icons.eot +0 -0
  4. data/assets/fonts/semantic_ui/themes/default/assets/fonts/icons.svg +146 -26
  5. data/assets/fonts/semantic_ui/themes/default/assets/fonts/icons.ttf +0 -0
  6. data/assets/fonts/semantic_ui/themes/default/assets/fonts/icons.woff +0 -0
  7. data/assets/fonts/semantic_ui/themes/default/assets/fonts/icons.woff2 +0 -0
  8. data/assets/javascripts/semantic_ui/definitions/behaviors/api.js +41 -16
  9. data/assets/javascripts/semantic_ui/definitions/behaviors/colorize.js +233 -227
  10. data/assets/javascripts/semantic_ui/definitions/behaviors/form.js +58 -23
  11. data/assets/javascripts/semantic_ui/definitions/behaviors/state.js +20 -7
  12. data/assets/javascripts/semantic_ui/definitions/behaviors/visibility.js +89 -22
  13. data/assets/javascripts/semantic_ui/definitions/behaviors/visit.js +13 -5
  14. data/assets/javascripts/semantic_ui/definitions/globals/site.js +2 -2
  15. data/assets/javascripts/semantic_ui/definitions/modules/accordion.js +20 -6
  16. data/assets/javascripts/semantic_ui/definitions/modules/checkbox.js +31 -9
  17. data/assets/javascripts/semantic_ui/definitions/modules/dimmer.js +27 -9
  18. data/assets/javascripts/semantic_ui/definitions/modules/dropdown.js +482 -207
  19. data/assets/javascripts/semantic_ui/definitions/modules/embed.js +50 -13
  20. data/assets/javascripts/semantic_ui/definitions/modules/modal.js +28 -13
  21. data/assets/javascripts/semantic_ui/definitions/modules/nag.js +28 -7
  22. data/assets/javascripts/semantic_ui/definitions/modules/popup.js +136 -76
  23. data/assets/javascripts/semantic_ui/definitions/modules/progress.js +177 -62
  24. data/assets/javascripts/semantic_ui/definitions/modules/rating.js +41 -8
  25. data/assets/javascripts/semantic_ui/definitions/modules/search.js +109 -56
  26. data/assets/javascripts/semantic_ui/definitions/modules/shape.js +52 -19
  27. data/assets/javascripts/semantic_ui/definitions/modules/sidebar.js +21 -7
  28. data/assets/javascripts/semantic_ui/definitions/modules/sticky.js +48 -19
  29. data/assets/javascripts/semantic_ui/definitions/modules/tab.js +57 -27
  30. data/assets/javascripts/semantic_ui/definitions/modules/transition.js +24 -8
  31. data/assets/stylesheets/semantic_ui/definitions/collections/breadcrumb.less +1 -2
  32. data/assets/stylesheets/semantic_ui/definitions/collections/form.less +42 -36
  33. data/assets/stylesheets/semantic_ui/definitions/collections/grid.less +12 -5
  34. data/assets/stylesheets/semantic_ui/definitions/collections/menu.less +50 -6
  35. data/assets/stylesheets/semantic_ui/definitions/collections/message.less +20 -1
  36. data/assets/stylesheets/semantic_ui/definitions/collections/table.less +16 -3
  37. data/assets/stylesheets/semantic_ui/definitions/elements/button.less +184 -40
  38. data/assets/stylesheets/semantic_ui/definitions/elements/container.less +1 -2
  39. data/assets/stylesheets/semantic_ui/definitions/elements/divider.less +1 -3
  40. data/assets/stylesheets/semantic_ui/definitions/elements/flag.less +1 -2
  41. data/assets/stylesheets/semantic_ui/definitions/elements/header.less +2 -2
  42. data/assets/stylesheets/semantic_ui/definitions/elements/icon.less +1 -2
  43. data/assets/stylesheets/semantic_ui/definitions/elements/image.less +6 -1
  44. data/assets/stylesheets/semantic_ui/definitions/elements/input.less +14 -14
  45. data/assets/stylesheets/semantic_ui/definitions/elements/label.less +3 -3
  46. data/assets/stylesheets/semantic_ui/definitions/elements/list.less +29 -16
  47. data/assets/stylesheets/semantic_ui/definitions/elements/loader.less +72 -9
  48. data/assets/stylesheets/semantic_ui/definitions/elements/rail.less +21 -2
  49. data/assets/stylesheets/semantic_ui/definitions/elements/reveal.less +2 -3
  50. data/assets/stylesheets/semantic_ui/definitions/elements/segment.less +44 -3
  51. data/assets/stylesheets/semantic_ui/definitions/elements/step.less +28 -8
  52. data/assets/stylesheets/semantic_ui/definitions/globals/reset.less +1 -2
  53. data/assets/stylesheets/semantic_ui/definitions/globals/site.less +0 -1
  54. data/assets/stylesheets/semantic_ui/definitions/modules/accordion.less +0 -1
  55. data/assets/stylesheets/semantic_ui/definitions/modules/checkbox.less +9 -10
  56. data/assets/stylesheets/semantic_ui/definitions/modules/dimmer.less +1 -2
  57. data/assets/stylesheets/semantic_ui/definitions/modules/dropdown.less +39 -21
  58. data/assets/stylesheets/semantic_ui/definitions/modules/embed.less +0 -1
  59. data/assets/stylesheets/semantic_ui/definitions/modules/modal.less +0 -1
  60. data/assets/stylesheets/semantic_ui/definitions/modules/nag.less +1 -2
  61. data/assets/stylesheets/semantic_ui/definitions/modules/popup.less +344 -2
  62. data/assets/stylesheets/semantic_ui/definitions/modules/progress.less +0 -1
  63. data/assets/stylesheets/semantic_ui/definitions/modules/rating.less +0 -1
  64. data/assets/stylesheets/semantic_ui/definitions/modules/search.less +1 -1
  65. data/assets/stylesheets/semantic_ui/definitions/modules/shape.less +1 -2
  66. data/assets/stylesheets/semantic_ui/definitions/modules/sidebar.less +1 -2
  67. data/assets/stylesheets/semantic_ui/definitions/modules/sticky.less +1 -2
  68. data/assets/stylesheets/semantic_ui/definitions/modules/tab.less +1 -2
  69. data/assets/stylesheets/semantic_ui/definitions/modules/transition.less +1 -2
  70. data/assets/stylesheets/semantic_ui/definitions/views/card.less +20 -2
  71. data/assets/stylesheets/semantic_ui/definitions/views/comment.less +1 -2
  72. data/assets/stylesheets/semantic_ui/definitions/views/feed.less +0 -1
  73. data/assets/stylesheets/semantic_ui/definitions/views/item.less +1 -2
  74. data/assets/stylesheets/semantic_ui/definitions/views/statistic.less +18 -19
  75. data/assets/stylesheets/semantic_ui/themes/basic/globals/reset.overrides +1 -1
  76. data/assets/stylesheets/semantic_ui/themes/default/collections/form.variables +4 -5
  77. data/assets/stylesheets/semantic_ui/themes/default/collections/menu.variables +13 -0
  78. data/assets/stylesheets/semantic_ui/themes/default/collections/message.variables +47 -1
  79. data/assets/stylesheets/semantic_ui/themes/default/collections/table.variables +7 -2
  80. data/assets/stylesheets/semantic_ui/themes/default/elements/button.variables +14 -0
  81. data/assets/stylesheets/semantic_ui/themes/default/elements/icon.overrides +263 -76
  82. data/assets/stylesheets/semantic_ui/themes/default/elements/icon.variables +3 -1
  83. data/assets/stylesheets/semantic_ui/themes/default/elements/input.variables +2 -4
  84. data/assets/stylesheets/semantic_ui/themes/default/elements/list.variables +2 -1
  85. data/assets/stylesheets/semantic_ui/themes/default/elements/loader.variables +17 -5
  86. data/assets/stylesheets/semantic_ui/themes/default/elements/rail.variables +2 -2
  87. data/assets/stylesheets/semantic_ui/themes/default/elements/step.variables +1 -1
  88. data/assets/stylesheets/semantic_ui/themes/default/globals/reset.overrides +1 -6
  89. data/assets/stylesheets/semantic_ui/themes/default/globals/site.variables +170 -46
  90. data/assets/stylesheets/semantic_ui/themes/default/modules/dropdown.variables +15 -12
  91. data/assets/stylesheets/semantic_ui/themes/default/modules/popup.variables +41 -3
  92. data/assets/stylesheets/semantic_ui/themes/default/modules/rating.overrides +2 -2
  93. data/assets/stylesheets/semantic_ui/themes/default/modules/sticky.variables +1 -1
  94. data/assets/stylesheets/semantic_ui/themes/default/views/card.variables +11 -0
  95. data/assets/stylesheets/semantic_ui/themes/material/collections/menu.variables +1 -1
  96. data/lib/less/rails/semantic_ui/version.rb +1 -1
  97. metadata +4 -3
@@ -3,7 +3,6 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
@@ -13,6 +12,13 @@
13
12
 
14
13
  "use strict";
15
14
 
15
+ window = (typeof window != 'undefined' && window.Math == Math)
16
+ ? window
17
+ : (typeof self != 'undefined' && self.Math == Math)
18
+ ? self
19
+ : Function('return this')()
20
+ ;
21
+
16
22
  $.visit = $.fn.visit = function(parameters) {
17
23
  var
18
24
  $allModules = $.isFunction(this)
@@ -322,7 +328,7 @@ $.visit = $.fn.visit = function(parameters) {
322
328
  }
323
329
  },
324
330
  debug: function() {
325
- if(settings.debug) {
331
+ if(!settings.silent && settings.debug) {
326
332
  if(settings.performance) {
327
333
  module.performance.log(arguments);
328
334
  }
@@ -333,7 +339,7 @@ $.visit = $.fn.visit = function(parameters) {
333
339
  }
334
340
  },
335
341
  verbose: function() {
336
- if(settings.verbose && settings.debug) {
342
+ if(!settings.silent && settings.verbose && settings.debug) {
337
343
  if(settings.performance) {
338
344
  module.performance.log(arguments);
339
345
  }
@@ -344,8 +350,10 @@ $.visit = $.fn.visit = function(parameters) {
344
350
  }
345
351
  },
346
352
  error: function() {
347
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
348
- module.error.apply(console, arguments);
353
+ if(!settings.silent) {
354
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
355
+ module.error.apply(console, arguments);
356
+ }
349
357
  },
350
358
  performance: {
351
359
  log: function(message) {
@@ -3,12 +3,12 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
10
9
  */
11
- ;(function ( $, window, document, undefined ) {
10
+
11
+ ;(function ($, window, document, undefined) {
12
12
 
13
13
  $.site = $.fn.site = function(parameters) {
14
14
  var
@@ -3,7 +3,6 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
@@ -13,6 +12,13 @@
13
12
 
14
13
  "use strict";
15
14
 
15
+ window = (typeof window != 'undefined' && window.Math == Math)
16
+ ? window
17
+ : (typeof self != 'undefined' && self.Math == Math)
18
+ ? self
19
+ : Function('return this')()
20
+ ;
21
+
16
22
  $.fn.accordion = function(parameters) {
17
23
  var
18
24
  $allModules = $(this),
@@ -367,7 +373,12 @@ $.fn.accordion = function(parameters) {
367
373
  $.extend(true, settings, name);
368
374
  }
369
375
  else if(value !== undefined) {
370
- settings[name] = value;
376
+ if($.isPlainObject(settings[name])) {
377
+ $.extend(true, settings[name], value);
378
+ }
379
+ else {
380
+ settings[name] = value;
381
+ }
371
382
  }
372
383
  else {
373
384
  return settings[name];
@@ -388,7 +399,7 @@ $.fn.accordion = function(parameters) {
388
399
  }
389
400
  },
390
401
  debug: function() {
391
- if(settings.debug) {
402
+ if(!settings.silent && settings.debug) {
392
403
  if(settings.performance) {
393
404
  module.performance.log(arguments);
394
405
  }
@@ -399,7 +410,7 @@ $.fn.accordion = function(parameters) {
399
410
  }
400
411
  },
401
412
  verbose: function() {
402
- if(settings.verbose && settings.debug) {
413
+ if(!settings.silent && settings.verbose && settings.debug) {
403
414
  if(settings.performance) {
404
415
  module.performance.log(arguments);
405
416
  }
@@ -410,8 +421,10 @@ $.fn.accordion = function(parameters) {
410
421
  }
411
422
  },
412
423
  error: function() {
413
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
414
- module.error.apply(console, arguments);
424
+ if(!settings.silent) {
425
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
426
+ module.error.apply(console, arguments);
427
+ }
415
428
  },
416
429
  performance: {
417
430
  log: function(message) {
@@ -544,6 +557,7 @@ $.fn.accordion.settings = {
544
557
  name : 'Accordion',
545
558
  namespace : 'accordion',
546
559
 
560
+ silent : false,
547
561
  debug : false,
548
562
  verbose : false,
549
563
  performance : true,
@@ -3,16 +3,22 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
10
9
  */
11
10
 
12
- ;(function ( $, window, document, undefined ) {
11
+ ;(function ($, window, document, undefined) {
13
12
 
14
13
  "use strict";
15
14
 
15
+ window = (typeof window != 'undefined' && window.Math == Math)
16
+ ? window
17
+ : (typeof self != 'undefined' && self.Math == Math)
18
+ ? self
19
+ : Function('return this')()
20
+ ;
21
+
16
22
  $.fn.checkbox = function(parameters) {
17
23
  var
18
24
  $allModules = $(this),
@@ -120,13 +126,13 @@ $.fn.checkbox = function(parameters) {
120
126
 
121
127
  hide: {
122
128
  input: function() {
123
- module.verbose('Modfying <input> z-index to be unselectable');
129
+ module.verbose('Modifying <input> z-index to be unselectable');
124
130
  $input.addClass(className.hidden);
125
131
  }
126
132
  },
127
133
  show: {
128
134
  input: function() {
129
- module.verbose('Modfying <input> z-index to be selectable');
135
+ module.verbose('Modifying <input> z-index to be selectable');
130
136
  $input.removeClass(className.hidden);
131
137
  }
132
138
  },
@@ -268,6 +274,8 @@ $.fn.checkbox = function(parameters) {
268
274
  }
269
275
  module.debug('Enabling checkbox');
270
276
  module.set.enabled();
277
+ settings.onEnable.call(input);
278
+ // preserve legacy callbacks
271
279
  settings.onEnabled.call(input);
272
280
  },
273
281
 
@@ -278,6 +286,8 @@ $.fn.checkbox = function(parameters) {
278
286
  }
279
287
  module.debug('Disabling checkbox');
280
288
  module.set.disabled();
289
+ settings.onDisable.call(input);
290
+ // preserve legacy callbacks
281
291
  settings.onDisabled.call(input);
282
292
  },
283
293
 
@@ -584,7 +594,12 @@ $.fn.checkbox = function(parameters) {
584
594
  $.extend(true, settings, name);
585
595
  }
586
596
  else if(value !== undefined) {
587
- settings[name] = value;
597
+ if($.isPlainObject(settings[name])) {
598
+ $.extend(true, settings[name], value);
599
+ }
600
+ else {
601
+ settings[name] = value;
602
+ }
588
603
  }
589
604
  else {
590
605
  return settings[name];
@@ -602,7 +617,7 @@ $.fn.checkbox = function(parameters) {
602
617
  }
603
618
  },
604
619
  debug: function() {
605
- if(settings.debug) {
620
+ if(!settings.silent && settings.debug) {
606
621
  if(settings.performance) {
607
622
  module.performance.log(arguments);
608
623
  }
@@ -613,7 +628,7 @@ $.fn.checkbox = function(parameters) {
613
628
  }
614
629
  },
615
630
  verbose: function() {
616
- if(settings.verbose && settings.debug) {
631
+ if(!settings.silent && settings.verbose && settings.debug) {
617
632
  if(settings.performance) {
618
633
  module.performance.log(arguments);
619
634
  }
@@ -624,8 +639,10 @@ $.fn.checkbox = function(parameters) {
624
639
  }
625
640
  },
626
641
  error: function() {
627
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
628
- module.error.apply(console, arguments);
642
+ if(!settings.silent) {
643
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
644
+ module.error.apply(console, arguments);
645
+ }
629
646
  },
630
647
  performance: {
631
648
  log: function(message) {
@@ -760,6 +777,7 @@ $.fn.checkbox.settings = {
760
777
  name : 'Checkbox',
761
778
  namespace : 'checkbox',
762
779
 
780
+ silent : false,
763
781
  debug : false,
764
782
  verbose : true,
765
783
  performance : true,
@@ -784,6 +802,10 @@ $.fn.checkbox.settings = {
784
802
  onEnable : function(){},
785
803
  onDisable : function(){},
786
804
 
805
+ // preserve misspelled callbacks (will be removed in 3.0)
806
+ onEnabled : function(){},
807
+ onDisabled : function(){},
808
+
787
809
  className : {
788
810
  checked : 'checked',
789
811
  indeterminate : 'indeterminate',
@@ -3,16 +3,22 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
10
9
  */
11
10
 
12
- ;(function ( $, window, document, undefined ) {
11
+ ;(function ($, window, document, undefined) {
13
12
 
14
13
  "use strict";
15
14
 
15
+ window = (typeof window != 'undefined' && window.Math == Math)
16
+ ? window
17
+ : (typeof self != 'undefined' && self.Math == Math)
18
+ ? self
19
+ : Function('return this')()
20
+ ;
21
+
16
22
  $.fn.dimmer = function(parameters) {
17
23
  var
18
24
  $allModules = $(this),
@@ -137,6 +143,9 @@ $.fn.dimmer = function(parameters) {
137
143
  $module
138
144
  .removeData(moduleNamespace)
139
145
  ;
146
+ $dimmable
147
+ .off(eventNamespace)
148
+ ;
140
149
  }
141
150
  },
142
151
 
@@ -383,10 +392,11 @@ $.fn.dimmer = function(parameters) {
383
392
  var
384
393
  color = $dimmer.css('background-color'),
385
394
  colorArray = color.split(','),
395
+ isRGB = (colorArray && colorArray.length == 3),
386
396
  isRGBA = (colorArray && colorArray.length == 4)
387
397
  ;
388
398
  opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity;
389
- if(isRGBA) {
399
+ if(isRGB || isRGBA) {
390
400
  colorArray[3] = opacity + ')';
391
401
  color = colorArray.join(',');
392
402
  }
@@ -445,7 +455,12 @@ $.fn.dimmer = function(parameters) {
445
455
  $.extend(true, settings, name);
446
456
  }
447
457
  else if(value !== undefined) {
448
- settings[name] = value;
458
+ if($.isPlainObject(settings[name])) {
459
+ $.extend(true, settings[name], value);
460
+ }
461
+ else {
462
+ settings[name] = value;
463
+ }
449
464
  }
450
465
  else {
451
466
  return settings[name];
@@ -463,7 +478,7 @@ $.fn.dimmer = function(parameters) {
463
478
  }
464
479
  },
465
480
  debug: function() {
466
- if(settings.debug) {
481
+ if(!settings.silent && settings.debug) {
467
482
  if(settings.performance) {
468
483
  module.performance.log(arguments);
469
484
  }
@@ -474,7 +489,7 @@ $.fn.dimmer = function(parameters) {
474
489
  }
475
490
  },
476
491
  verbose: function() {
477
- if(settings.verbose && settings.debug) {
492
+ if(!settings.silent && settings.verbose && settings.debug) {
478
493
  if(settings.performance) {
479
494
  module.performance.log(arguments);
480
495
  }
@@ -485,8 +500,10 @@ $.fn.dimmer = function(parameters) {
485
500
  }
486
501
  },
487
502
  error: function() {
488
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
489
- module.error.apply(console, arguments);
503
+ if(!settings.silent) {
504
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
505
+ module.error.apply(console, arguments);
506
+ }
490
507
  },
491
508
  performance: {
492
509
  log: function(message) {
@@ -626,6 +643,7 @@ $.fn.dimmer.settings = {
626
643
  name : 'Dimmer',
627
644
  namespace : 'dimmer',
628
645
 
646
+ silent : false,
629
647
  debug : false,
630
648
  verbose : false,
631
649
  performance : true,
@@ -690,4 +708,4 @@ $.fn.dimmer.settings = {
690
708
 
691
709
  };
692
710
 
693
- })( jQuery, window, document );
711
+ })( jQuery, window, document );
@@ -3,16 +3,22 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
10
9
  */
11
10
 
12
- ;(function ( $, window, document, undefined ) {
11
+ ;(function ($, window, document, undefined) {
13
12
 
14
13
  "use strict";
15
14
 
15
+ window = (typeof window != 'undefined' && window.Math == Math)
16
+ ? window
17
+ : (typeof self != 'undefined' && self.Math == Math)
18
+ ? self
19
+ : Function('return this')()
20
+ ;
21
+
16
22
  $.fn.dropdown = function(parameters) {
17
23
  var
18
24
  $allModules = $(this),
@@ -55,6 +61,7 @@ $.fn.dropdown = function(parameters) {
55
61
  $context = $(settings.context),
56
62
  $text = $module.find(selector.text),
57
63
  $search = $module.find(selector.search),
64
+ $sizer = $module.find(selector.sizer),
58
65
  $input = $module.find(selector.input),
59
66
  $icon = $module.find(selector.icon),
60
67
 
@@ -73,6 +80,7 @@ $.fn.dropdown = function(parameters) {
73
80
 
74
81
  initialLoad,
75
82
  pageLostFocus,
83
+ willRefocus,
76
84
  elementNamespace,
77
85
  id,
78
86
  selectObserver,
@@ -125,37 +133,48 @@ $.fn.dropdown = function(parameters) {
125
133
  $document
126
134
  .off(elementNamespace)
127
135
  ;
128
- if(selectObserver) {
129
- selectObserver.disconnect();
130
- }
131
- if(menuObserver) {
132
- menuObserver.disconnect();
133
- }
136
+ module.disconnect.menuObserver();
137
+ module.disconnect.selectObserver();
134
138
  },
135
139
 
136
140
  observeChanges: function() {
137
141
  if('MutationObserver' in window) {
138
- selectObserver = new MutationObserver(function(mutations) {
139
- module.debug('<select> modified, recreating menu');
140
- module.setup.select();
141
- });
142
- menuObserver = new MutationObserver(function(mutations) {
143
- module.debug('Menu modified, updating selector cache');
144
- module.refresh();
145
- });
142
+ selectObserver = new MutationObserver(module.event.select.mutation);
143
+ menuObserver = new MutationObserver(module.event.menu.mutation);
144
+ module.debug('Setting up mutation observer', selectObserver, menuObserver);
145
+ module.observe.select();
146
+ module.observe.menu();
147
+ }
148
+ },
149
+
150
+ disconnect: {
151
+ menuObserver: function() {
152
+ if(menuObserver) {
153
+ menuObserver.disconnect();
154
+ }
155
+ },
156
+ selectObserver: function() {
157
+ if(menuObserver) {
158
+ menuObserver.disconnect();
159
+ }
160
+ }
161
+ },
162
+ observe: {
163
+ select: function() {
146
164
  if(module.has.input()) {
147
165
  selectObserver.observe($input[0], {
148
166
  childList : true,
149
167
  subtree : true
150
168
  });
151
169
  }
170
+ },
171
+ menu: function() {
152
172
  if(module.has.menu()) {
153
173
  menuObserver.observe($menu[0], {
154
174
  childList : true,
155
175
  subtree : true
156
176
  });
157
177
  }
158
- module.debug('Setting up mutation observer', selectObserver, menuObserver);
159
178
  }
160
179
  },
161
180
 
@@ -190,6 +209,9 @@ $.fn.dropdown = function(parameters) {
190
209
  .addClass(className.addition)
191
210
  .addClass(className.item)
192
211
  ;
212
+ if(settings.hideAdditions) {
213
+ $userChoice.addClass(className.hidden);
214
+ }
193
215
  $userChoices = ($userChoices === undefined)
194
216
  ? $userChoice
195
217
  : $userChoices.add($userChoice)
@@ -216,6 +238,12 @@ $.fn.dropdown = function(parameters) {
216
238
  .addClass(className.menu)
217
239
  .appendTo($module)
218
240
  ;
241
+ },
242
+ sizer: function() {
243
+ $sizer = $('<span />')
244
+ .addClass(className.sizer)
245
+ .insertAfter($search)
246
+ ;
219
247
  }
220
248
  },
221
249
 
@@ -225,7 +253,12 @@ $.fn.dropdown = function(parameters) {
225
253
  : module.get.query()
226
254
  ;
227
255
  module.verbose('Searching for query', query);
228
- module.filter(query);
256
+ if(module.has.minCharacters(query)) {
257
+ module.filter(query);
258
+ }
259
+ else {
260
+ module.hide();
261
+ }
229
262
  },
230
263
 
231
264
  select: {
@@ -234,6 +267,7 @@ $.fn.dropdown = function(parameters) {
234
267
  module.remove.selectedItem();
235
268
  $item
236
269
  .not(selector.unselectable)
270
+ .not(selector.addition + selector.hidden)
237
271
  .eq(0)
238
272
  .addClass(className.selected)
239
273
  ;
@@ -260,7 +294,11 @@ $.fn.dropdown = function(parameters) {
260
294
  api: function() {
261
295
  var
262
296
  apiSettings = {
263
- debug : settings.debug,
297
+ debug : settings.debug,
298
+ urlData : {
299
+ value : module.get.value(),
300
+ query : module.get.query()
301
+ },
264
302
  on : false
265
303
  }
266
304
  ;
@@ -285,6 +323,9 @@ $.fn.dropdown = function(parameters) {
285
323
  .insertBefore($text)
286
324
  ;
287
325
  }
326
+ if( module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
327
+ module.create.sizer();
328
+ }
288
329
  if(settings.allowTab) {
289
330
  module.set.tabbable();
290
331
  }
@@ -324,8 +365,8 @@ $.fn.dropdown = function(parameters) {
324
365
  module.set.multiple();
325
366
  }
326
367
  if ($input.prop('disabled')) {
327
- module.debug('Disabling dropdown')
328
- $module.addClass(className.disabled)
368
+ module.debug('Disabling dropdown');
369
+ $module.addClass(className.disabled);
329
370
  }
330
371
  $input
331
372
  .removeAttr('class')
@@ -366,6 +407,10 @@ $.fn.dropdown = function(parameters) {
366
407
  module.refreshData();
367
408
  },
368
409
 
410
+ refreshItems: function() {
411
+ $item = $menu.find(selector.item);
412
+ },
413
+
369
414
  refreshSelectors: function() {
370
415
  module.verbose('Refreshing selector cache');
371
416
  $text = $module.find(selector.text);
@@ -386,6 +431,14 @@ $.fn.dropdown = function(parameters) {
386
431
  .removeData(metadata.text)
387
432
  .removeData(metadata.value)
388
433
  ;
434
+ },
435
+
436
+ clearData: function() {
437
+ module.verbose('Clearing metadata');
438
+ $item
439
+ .removeData(metadata.text)
440
+ .removeData(metadata.value)
441
+ ;
389
442
  $module
390
443
  .removeData(metadata.defaultText)
391
444
  .removeData(metadata.defaultValue)
@@ -410,17 +463,20 @@ $.fn.dropdown = function(parameters) {
410
463
  ;
411
464
  if( module.can.show() && !module.is.active() ) {
412
465
  module.debug('Showing dropdown');
413
- if(module.is.multiple() && !module.has.search() && module.is.allFiltered()) {
414
- return true;
415
- }
416
466
  if(module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered()) ) {
417
467
  module.remove.message();
418
468
  }
469
+ if(module.is.allFiltered()) {
470
+ return true;
471
+ }
419
472
  if(settings.onShow.call(element) !== false) {
420
473
  module.animate.show(function() {
421
474
  if( module.can.click() ) {
422
475
  module.bind.intent();
423
476
  }
477
+ if(module.has.menuSearch()) {
478
+ module.focusSearch();
479
+ }
424
480
  module.set.visible();
425
481
  callback.call(element);
426
482
  });
@@ -523,11 +579,13 @@ $.fn.dropdown = function(parameters) {
523
579
  }
524
580
  if( module.is.searchSelection() ) {
525
581
  $module
582
+ .on('mousedown' + eventNamespace, module.event.mousedown)
583
+ .on('mouseup' + eventNamespace, module.event.mouseup)
526
584
  .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
527
585
  .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
528
586
  .on('click' + eventNamespace, selector.icon, module.event.icon.click)
529
- .on('click' + eventNamespace, selector.search, module.show)
530
587
  .on('focus' + eventNamespace, selector.search, module.event.search.focus)
588
+ .on('click' + eventNamespace, selector.search, module.event.search.focus)
531
589
  .on('blur' + eventNamespace, selector.search, module.event.search.blur)
532
590
  .on('click' + eventNamespace, selector.text, module.event.text.focus)
533
591
  ;
@@ -609,7 +667,14 @@ $.fn.dropdown = function(parameters) {
609
667
  module.select.firstUnfiltered();
610
668
  if( module.has.allResultsFiltered() ) {
611
669
  if( settings.onNoResults.call(element, searchTerm) ) {
612
- if(!settings.allowAdditions) {
670
+ if(settings.allowAdditions) {
671
+ if(settings.hideAdditions) {
672
+ module.verbose('User addition with no menu, setting empty style');
673
+ module.set.empty();
674
+ module.hideMenu();
675
+ }
676
+ }
677
+ else {
613
678
  module.verbose('All items filtered, showing message', searchTerm);
614
679
  module.add.message(message.noResults);
615
680
  }
@@ -620,6 +685,7 @@ $.fn.dropdown = function(parameters) {
620
685
  }
621
686
  }
622
687
  else {
688
+ module.remove.empty();
623
689
  module.remove.message();
624
690
  }
625
691
  if(settings.allowAdditions) {
@@ -652,9 +718,10 @@ $.fn.dropdown = function(parameters) {
652
718
  queryRemote: function(query, callback) {
653
719
  var
654
720
  apiSettings = {
655
- errorDuration : false,
656
- throttle : settings.throttle,
657
- urlData : {
721
+ errorDuration : false,
722
+ cache : 'local',
723
+ throttle : settings.throttle,
724
+ urlData : {
658
725
  query: query
659
726
  },
660
727
  onError: function() {
@@ -711,7 +778,11 @@ $.fn.dropdown = function(parameters) {
711
778
  results.push(this);
712
779
  return true;
713
780
  }
714
- else if(settings.fullTextSearch && module.fuzzySearch(searchTerm, text)) {
781
+ else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
782
+ results.push(this);
783
+ return true;
784
+ }
785
+ else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
715
786
  results.push(this);
716
787
  return true;
717
788
  }
@@ -767,7 +838,14 @@ $.fn.dropdown = function(parameters) {
767
838
  }
768
839
  return true;
769
840
  },
770
-
841
+ exactSearch: function (query, term) {
842
+ query = query.toLowerCase();
843
+ term = term.toLowerCase();
844
+ if(term.indexOf(query) > -1) {
845
+ return true;
846
+ }
847
+ return false;
848
+ },
771
849
  filterActive: function() {
772
850
  if(settings.useLabels) {
773
851
  $item.filter('.' + className.active)
@@ -776,9 +854,16 @@ $.fn.dropdown = function(parameters) {
776
854
  }
777
855
  },
778
856
 
779
- focusSearch: function() {
780
- if( module.is.search() && !module.is.focusedOnSearch() ) {
781
- $search[0].focus();
857
+ focusSearch: function(skipHandler) {
858
+ if( module.has.search() && !module.is.focusedOnSearch() ) {
859
+ if(skipHandler) {
860
+ $module.off('focus' + eventNamespace, selector.search);
861
+ $search.focus();
862
+ $module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
863
+ }
864
+ else {
865
+ $search.focus();
866
+ }
782
867
  }
783
868
  },
784
869
 
@@ -789,19 +874,22 @@ $.fn.dropdown = function(parameters) {
789
874
  $selectedItem = ($currentlySelected.length > 0)
790
875
  ? $currentlySelected
791
876
  : $activeItem,
792
- hasSelected = ($selectedItem.size() > 0)
877
+ hasSelected = ($selectedItem.length > 0)
793
878
  ;
794
- if( module.has.query() ) {
795
- if(hasSelected) {
796
- module.debug('Forcing partial selection to selected item', $selectedItem);
797
- module.event.item.click.call($selectedItem);
798
- return;
879
+ if(hasSelected) {
880
+ module.debug('Forcing partial selection to selected item', $selectedItem);
881
+ module.event.item.click.call($selectedItem, {}, true);
882
+ return;
883
+ }
884
+ else {
885
+ if(settings.allowAdditions) {
886
+ module.set.selected(module.get.query());
887
+ module.remove.searchTerm();
799
888
  }
800
889
  else {
801
890
  module.remove.searchTerm();
802
891
  }
803
892
  }
804
- module.hide();
805
893
  },
806
894
 
807
895
  event: {
@@ -816,15 +904,6 @@ $.fn.dropdown = function(parameters) {
816
904
  module.show();
817
905
  }
818
906
  },
819
- click: function(event) {
820
- var
821
- $target = $(event.target)
822
- ;
823
- // focus search
824
- if($target.is($module) && !module.is.focusedOnSearch()) {
825
- module.focusSearch();
826
- }
827
- },
828
907
  blur: function(event) {
829
908
  pageLostFocus = (document.activeElement === this);
830
909
  if(!activated && !pageLostFocus) {
@@ -832,12 +911,38 @@ $.fn.dropdown = function(parameters) {
832
911
  module.hide();
833
912
  }
834
913
  },
835
- // prevents focus callback from occurring on mousedown
836
914
  mousedown: function() {
837
- activated = true;
915
+ if(module.is.searchSelection()) {
916
+ // prevent menu hiding on immediate re-focus
917
+ willRefocus = true;
918
+ }
919
+ else {
920
+ // prevents focus callback from occurring on mousedown
921
+ activated = true;
922
+ }
838
923
  },
839
924
  mouseup: function() {
840
- activated = false;
925
+ if(module.is.searchSelection()) {
926
+ // prevent menu hiding on immediate re-focus
927
+ willRefocus = false;
928
+ }
929
+ else {
930
+ activated = false;
931
+ }
932
+ },
933
+ click: function(event) {
934
+ var
935
+ $target = $(event.target)
936
+ ;
937
+ // focus search
938
+ if($target.is($module)) {
939
+ if(!module.is.focusedOnSearch()) {
940
+ module.focusSearch();
941
+ }
942
+ else {
943
+ module.show();
944
+ }
945
+ }
841
946
  },
842
947
  search: {
843
948
  focus: function() {
@@ -847,28 +952,19 @@ $.fn.dropdown = function(parameters) {
847
952
  }
848
953
  if(settings.showOnFocus) {
849
954
  module.search();
850
- module.show();
851
955
  }
852
956
  },
853
957
  blur: function(event) {
854
958
  pageLostFocus = (document.activeElement === this);
855
- if(!itemActivated && !pageLostFocus) {
856
- if(module.is.multiple()) {
857
- module.remove.activeLabel();
858
- module.hide();
859
- }
860
- else if(settings.forceSelection) {
861
- module.forceSelection();
862
- }
863
- else {
959
+ if(!willRefocus) {
960
+ if(!itemActivated && !pageLostFocus) {
961
+ if(settings.forceSelection && module.has.query()) {
962
+ module.forceSelection();
963
+ }
864
964
  module.hide();
865
965
  }
866
966
  }
867
- else if(pageLostFocus) {
868
- if(settings.forceSelection) {
869
- module.forceSelection();
870
- }
871
- }
967
+ willRefocus = false;
872
968
  }
873
969
  },
874
970
  icon: {
@@ -938,6 +1034,9 @@ $.fn.dropdown = function(parameters) {
938
1034
  ? module.show
939
1035
  : module.toggle
940
1036
  ;
1037
+ if(module.is.bubbledLabelClick(event)) {
1038
+ return;
1039
+ }
941
1040
  if( module.determine.eventOnElement(event, toggleBehavior) ) {
942
1041
  event.preventDefault();
943
1042
  }
@@ -959,7 +1058,35 @@ $.fn.dropdown = function(parameters) {
959
1058
  module.determine.eventInModule(event, module.hide);
960
1059
  }
961
1060
  },
1061
+ select: {
1062
+ mutation: function(mutations) {
1063
+ module.debug('<select> modified, recreating menu');
1064
+ module.setup.select();
1065
+ }
1066
+ },
962
1067
  menu: {
1068
+ mutation: function(mutations) {
1069
+ var
1070
+ mutation = mutations[0],
1071
+ $addedNode = mutation.addedNodes
1072
+ ? $(mutation.addedNodes[0])
1073
+ : $(false),
1074
+ $removedNode = mutation.removedNodes
1075
+ ? $(mutation.removedNodes[0])
1076
+ : $(false),
1077
+ $changedNodes = $addedNode.add($removedNode),
1078
+ isUserAddition = $changedNodes.is(selector.addition) || $changedNodes.closest(selector.addition).length > 0,
1079
+ isMessage = $changedNodes.is(selector.message) || $changedNodes.closest(selector.message).length > 0
1080
+ ;
1081
+ if(isUserAddition || isMessage) {
1082
+ module.debug('Updating item selector cache');
1083
+ module.refreshItems();
1084
+ }
1085
+ else {
1086
+ module.debug('Menu modified, updating selector cache');
1087
+ module.refresh();
1088
+ }
1089
+ },
963
1090
  mousedown: function() {
964
1091
  itemActivated = true;
965
1092
  },
@@ -970,17 +1097,21 @@ $.fn.dropdown = function(parameters) {
970
1097
  item: {
971
1098
  mouseenter: function(event) {
972
1099
  var
973
- $subMenu = $(this).children(selector.menu),
974
- $otherMenus = $(this).siblings(selector.item).children(selector.menu)
1100
+ $target = $(event.target),
1101
+ $item = $(this),
1102
+ $subMenu = $item.children(selector.menu),
1103
+ $otherMenus = $item.siblings(selector.item).children(selector.menu),
1104
+ hasSubMenu = ($subMenu.length > 0),
1105
+ isBubbledEvent = ($subMenu.find($target).length > 0)
975
1106
  ;
976
- if( $subMenu.length > 0 ) {
1107
+ if( !isBubbledEvent && hasSubMenu ) {
977
1108
  clearTimeout(module.itemTimer);
978
1109
  module.itemTimer = setTimeout(function() {
979
1110
  module.verbose('Showing sub-menu', $subMenu);
980
1111
  $.each($otherMenus, function() {
981
1112
  module.animate.hide(false, $(this));
982
1113
  });
983
- module.animate.show(false, $subMenu);
1114
+ module.animate.show(false, $subMenu);
984
1115
  }, settings.delay.show);
985
1116
  event.preventDefault();
986
1117
  }
@@ -993,13 +1124,11 @@ $.fn.dropdown = function(parameters) {
993
1124
  clearTimeout(module.itemTimer);
994
1125
  module.itemTimer = setTimeout(function() {
995
1126
  module.verbose('Hiding sub-menu', $subMenu);
996
- module.animate.hide(false, $subMenu);
1127
+ module.animate.hide(false, $subMenu);
997
1128
  }, settings.delay.hide);
998
1129
  }
999
1130
  },
1000
- touchend: function() {
1001
- },
1002
- click: function (event) {
1131
+ click: function (event, skipRefocus) {
1003
1132
  var
1004
1133
  $choice = $(this),
1005
1134
  $target = (event)
@@ -1012,9 +1141,17 @@ $.fn.dropdown = function(parameters) {
1012
1141
  isBubbledEvent = ($subMenu.find($target).length > 0)
1013
1142
  ;
1014
1143
  if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
1144
+ if(module.is.searchSelection()) {
1145
+ if(settings.allowAdditions) {
1146
+ module.remove.userAddition();
1147
+ }
1148
+ module.remove.searchTerm();
1149
+ if(!module.is.focusedOnSearch() && !(skipRefocus == true)) {
1150
+ module.focusSearch(true);
1151
+ }
1152
+ }
1015
1153
  if(!settings.useLabels) {
1016
1154
  module.remove.filteredItem();
1017
- module.remove.searchTerm();
1018
1155
  module.set.scrollPosition($choice);
1019
1156
  }
1020
1157
  module.determine.selectAction.call(this, text, value);
@@ -1150,19 +1287,29 @@ $.fn.dropdown = function(parameters) {
1150
1287
  ? $currentlySelected
1151
1288
  : $activeItem,
1152
1289
  $visibleItems = ($selectedItem.length > 0)
1153
- ? $selectedItem.siblings(':not(.' + className.filtered +')').andSelf()
1290
+ ? $selectedItem.siblings(':not(.' + className.filtered +')').addBack()
1154
1291
  : $menu.children(':not(.' + className.filtered +')'),
1155
- $subMenu = $selectedItem.children(selector.menu),
1156
- $parentMenu = $selectedItem.closest(selector.menu),
1157
- inVisibleMenu = ($parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0),
1158
- hasSubMenu = ($subMenu.length> 0),
1159
- hasSelectedItem = ($selectedItem.length > 0),
1160
- selectedIsSelectable = ($selectedItem.not(selector.unselectable).length > 0),
1161
- delimiterPressed = (pressedKey == keys.delimiter && settings.allowAdditions && module.is.multiple()),
1292
+ $subMenu = $selectedItem.children(selector.menu),
1293
+ $parentMenu = $selectedItem.closest(selector.menu),
1294
+ inVisibleMenu = ($parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0),
1295
+ hasSubMenu = ($subMenu.length> 0),
1296
+ hasSelectedItem = ($selectedItem.length > 0),
1297
+ selectedIsSelectable = ($selectedItem.not(selector.unselectable).length > 0),
1298
+ delimiterPressed = (pressedKey == keys.delimiter && settings.allowAdditions && module.is.multiple()),
1299
+ isAdditionWithoutMenu = (settings.allowAdditions && settings.hideAdditions && (pressedKey == keys.enter || delimiterPressed) && selectedIsSelectable),
1162
1300
  $nextItem,
1163
1301
  isSubMenuItem,
1164
1302
  newIndex
1165
1303
  ;
1304
+ // allow selection with menu closed
1305
+ if(isAdditionWithoutMenu) {
1306
+ module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1307
+ module.event.item.click.call($selectedItem, event);
1308
+ if(module.is.searchSelection()) {
1309
+ module.remove.searchTerm();
1310
+ }
1311
+ }
1312
+
1166
1313
  // visible menu keyboard shortcuts
1167
1314
  if( module.is.visible() ) {
1168
1315
 
@@ -1182,38 +1329,41 @@ $.fn.dropdown = function(parameters) {
1182
1329
  event.preventDefault();
1183
1330
  }
1184
1331
 
1185
- // left arrow (hide sub-menu)
1186
- if(pressedKey == keys.leftArrow) {
1332
+ // sub-menu actions
1333
+ if(hasSelectedItem) {
1187
1334
 
1188
- isSubMenuItem = ($parentMenu[0] !== $menu[0]);
1335
+ if(pressedKey == keys.leftArrow) {
1189
1336
 
1190
- if(isSubMenuItem) {
1191
- module.verbose('Left key pressed, closing sub-menu');
1192
- module.animate.hide(false, $parentMenu);
1193
- $selectedItem
1194
- .removeClass(className.selected)
1195
- ;
1196
- $parentMenu
1197
- .closest(selector.item)
1198
- .addClass(className.selected)
1199
- ;
1200
- event.preventDefault();
1337
+ isSubMenuItem = ($parentMenu[0] !== $menu[0]);
1338
+
1339
+ if(isSubMenuItem) {
1340
+ module.verbose('Left key pressed, closing sub-menu');
1341
+ module.animate.hide(false, $parentMenu);
1342
+ $selectedItem
1343
+ .removeClass(className.selected)
1344
+ ;
1345
+ $parentMenu
1346
+ .closest(selector.item)
1347
+ .addClass(className.selected)
1348
+ ;
1349
+ event.preventDefault();
1350
+ }
1201
1351
  }
1202
- }
1203
1352
 
1204
- // right arrow (show sub-menu)
1205
- if(pressedKey == keys.rightArrow) {
1206
- if(hasSubMenu) {
1207
- module.verbose('Right key pressed, opening sub-menu');
1208
- module.animate.show(false, $subMenu);
1209
- $selectedItem
1210
- .removeClass(className.selected)
1211
- ;
1212
- $subMenu
1213
- .find(selector.item).eq(0)
1214
- .addClass(className.selected)
1215
- ;
1216
- event.preventDefault();
1353
+ // right arrow (show sub-menu)
1354
+ if(pressedKey == keys.rightArrow) {
1355
+ if(hasSubMenu) {
1356
+ module.verbose('Right key pressed, opening sub-menu');
1357
+ module.animate.show(false, $subMenu);
1358
+ $selectedItem
1359
+ .removeClass(className.selected)
1360
+ ;
1361
+ $subMenu
1362
+ .find(selector.item).eq(0)
1363
+ .addClass(className.selected)
1364
+ ;
1365
+ event.preventDefault();
1366
+ }
1217
1367
  }
1218
1368
  }
1219
1369
 
@@ -1237,6 +1387,9 @@ $.fn.dropdown = function(parameters) {
1237
1387
  .addClass(className.selected)
1238
1388
  ;
1239
1389
  module.set.scrollPosition($nextItem);
1390
+ if(settings.selectOnKeydown && module.is.single()) {
1391
+ module.set.selectedItem($nextItem);
1392
+ }
1240
1393
  }
1241
1394
  event.preventDefault();
1242
1395
  }
@@ -1261,6 +1414,10 @@ $.fn.dropdown = function(parameters) {
1261
1414
  .addClass(className.selected)
1262
1415
  ;
1263
1416
  module.set.scrollPosition($nextItem);
1417
+ if(settings.selectOnKeydown && module.is.single()) {
1418
+ module.set.activeItem($nextItem);
1419
+ module.set.selected(module.get.choiceValue($nextItem), $nextItem);
1420
+ }
1264
1421
  }
1265
1422
  event.preventDefault();
1266
1423
  }
@@ -1288,15 +1445,16 @@ $.fn.dropdown = function(parameters) {
1288
1445
  event.preventDefault();
1289
1446
  }
1290
1447
  // down arrow (open menu)
1291
- if(pressedKey == keys.downArrow) {
1448
+ if(pressedKey == keys.downArrow && !module.is.visible()) {
1292
1449
  module.verbose('Down key pressed, showing dropdown');
1450
+ module.select.firstUnfiltered();
1293
1451
  module.show();
1294
1452
  event.preventDefault();
1295
1453
  }
1296
1454
  }
1297
1455
  }
1298
1456
  else {
1299
- if( module.is.selection() && !module.is.search() ) {
1457
+ if( !module.has.search() ) {
1300
1458
  module.set.selectedLetter( String.fromCharCode(pressedKey) );
1301
1459
  }
1302
1460
  }
@@ -1322,11 +1480,11 @@ $.fn.dropdown = function(parameters) {
1322
1480
  module.verbose('Determining action', settings.action);
1323
1481
  if( $.isFunction( module.action[settings.action] ) ) {
1324
1482
  module.verbose('Triggering preset action', settings.action, text, value);
1325
- module.action[ settings.action ].call(this, text, value);
1483
+ module.action[ settings.action ].call(element, text, value, this);
1326
1484
  }
1327
1485
  else if( $.isFunction(settings.action) ) {
1328
1486
  module.verbose('Triggering user action', settings.action, text, value);
1329
- settings.action.call(this, text, value);
1487
+ settings.action.call(element, text, value, this);
1330
1488
  }
1331
1489
  else {
1332
1490
  module.error(error.action, settings.action);
@@ -1354,16 +1512,17 @@ $.fn.dropdown = function(parameters) {
1354
1512
  },
1355
1513
  eventOnElement: function(event, callback) {
1356
1514
  var
1357
- $target = $(event.target),
1358
- $label = $target.closest(selector.siblingLabel),
1359
- notOnLabel = ($module.find($label).length === 0),
1360
- notInMenu = ($target.closest($menu).length === 0)
1515
+ $target = $(event.target),
1516
+ $label = $target.closest(selector.siblingLabel),
1517
+ inVisibleDOM = document.body.contains(event.target),
1518
+ notOnLabel = ($module.find($label).length === 0),
1519
+ notInMenu = ($target.closest($menu).length === 0)
1361
1520
  ;
1362
1521
  callback = $.isFunction(callback)
1363
1522
  ? callback
1364
1523
  : function(){}
1365
1524
  ;
1366
- if(notOnLabel && notInMenu) {
1525
+ if(inVisibleDOM && notOnLabel && notInMenu) {
1367
1526
  module.verbose('Triggering event', callback);
1368
1527
  callback();
1369
1528
  return true;
@@ -1379,13 +1538,13 @@ $.fn.dropdown = function(parameters) {
1379
1538
 
1380
1539
  nothing: function() {},
1381
1540
 
1382
- activate: function(text, value) {
1541
+ activate: function(text, value, element) {
1383
1542
  value = (value !== undefined)
1384
1543
  ? value
1385
1544
  : text
1386
1545
  ;
1387
- if( module.can.activate( $(this) ) ) {
1388
- module.set.selected(value, $(this));
1546
+ if( module.can.activate( $(element) ) ) {
1547
+ module.set.selected(value, $(element));
1389
1548
  if(module.is.multiple() && !module.is.allFiltered()) {
1390
1549
  return;
1391
1550
  }
@@ -1395,22 +1554,22 @@ $.fn.dropdown = function(parameters) {
1395
1554
  }
1396
1555
  },
1397
1556
 
1398
- select: function(text, value) {
1557
+ select: function(text, value, element) {
1399
1558
  // mimics action.activate but does not select text
1400
- module.action.activate.call(this);
1559
+ module.action.activate.call(element);
1401
1560
  },
1402
1561
 
1403
- combo: function(text, value) {
1562
+ combo: function(text, value, element) {
1404
1563
  value = (value !== undefined)
1405
1564
  ? value
1406
1565
  : text
1407
1566
  ;
1408
- module.set.selected(value, $(this));
1567
+ module.set.selected(value, $(element));
1409
1568
  module.hideAndClear();
1410
1569
  },
1411
1570
 
1412
- hide: function(text, value) {
1413
- module.set.value(value);
1571
+ hide: function(text, value, element) {
1572
+ module.set.value(value, text);
1414
1573
  module.hideAndClear();
1415
1574
  }
1416
1575
 
@@ -1435,8 +1594,14 @@ $.fn.dropdown = function(parameters) {
1435
1594
  query: function() {
1436
1595
  return $.trim($search.val());
1437
1596
  },
1438
- searchWidth: function(characterCount) {
1439
- return (characterCount * settings.glyphWidth) + 'em';
1597
+ searchWidth: function(value) {
1598
+ value = (value !== undefined)
1599
+ ? value
1600
+ : $search.val()
1601
+ ;
1602
+ $sizer.text(value);
1603
+ // prevent rounding issues
1604
+ return Math.ceil( $sizer.width() + 1);
1440
1605
  },
1441
1606
  selectionCount: function() {
1442
1607
  var
@@ -1502,13 +1667,14 @@ $.fn.dropdown = function(parameters) {
1502
1667
  var
1503
1668
  value = ($input.length > 0)
1504
1669
  ? $input.val()
1505
- : $module.data(metadata.value)
1670
+ : $module.data(metadata.value),
1671
+ isEmptyMultiselect = ($.isArray(value) && value.length === 1 && value[0] === '')
1506
1672
  ;
1507
1673
  // prevents placeholder element from being selected when multiple
1508
- if($.isArray(value) && value.length === 1 && value[0] === '') {
1509
- return '';
1510
- }
1511
- return value;
1674
+ return (value === undefined || isEmptyMultiselect)
1675
+ ? ''
1676
+ : value
1677
+ ;
1512
1678
  },
1513
1679
  values: function() {
1514
1680
  var
@@ -1533,16 +1699,17 @@ $.fn.dropdown = function(parameters) {
1533
1699
  if(typeof values == 'string') {
1534
1700
  values = [values];
1535
1701
  }
1536
- remoteValues = {};
1537
1702
  $.each(values, function(index, value) {
1538
1703
  var
1539
1704
  name = module.read.remoteData(value)
1540
1705
  ;
1541
1706
  module.verbose('Restoring value from session data', name, value);
1542
- remoteValues[value] = (name)
1543
- ? name
1544
- : value
1545
- ;
1707
+ if(name) {
1708
+ if(!remoteValues) {
1709
+ remoteValues = {};
1710
+ }
1711
+ remoteValues[value] = name;
1712
+ }
1546
1713
  });
1547
1714
  }
1548
1715
  return remoteValues;
@@ -1554,7 +1721,7 @@ $.fn.dropdown = function(parameters) {
1554
1721
  ;
1555
1722
  if($choice) {
1556
1723
  if($choice.find(selector.menu).length > 0) {
1557
- module.verbose('Retreiving text of element with sub-menu');
1724
+ module.verbose('Retrieving text of element with sub-menu');
1558
1725
  $choice = $choice.clone();
1559
1726
  $choice.find(selector.menu).remove();
1560
1727
  $choice.find(selector.menuIcon).remove();
@@ -1635,7 +1802,7 @@ $.fn.dropdown = function(parameters) {
1635
1802
  module.debug('Retrieved and sorted values from select', select);
1636
1803
  }
1637
1804
  else {
1638
- module.debug('Retreived values from select', select);
1805
+ module.debug('Retrieved values from select', select);
1639
1806
  }
1640
1807
  return select;
1641
1808
  },
@@ -1776,6 +1943,9 @@ $.fn.dropdown = function(parameters) {
1776
1943
  module.set.text(defaultText);
1777
1944
  }
1778
1945
  },
1946
+ placeholderText: function() {
1947
+ module.set.placeholderText();
1948
+ },
1779
1949
  defaultValue: function() {
1780
1950
  var
1781
1951
  defaultValue = module.get.defaultValue()
@@ -1814,15 +1984,10 @@ $.fn.dropdown = function(parameters) {
1814
1984
  }
1815
1985
  },
1816
1986
  values: function() {
1817
- // prevents callbacks from occuring on initial load
1987
+ // prevents callbacks from occurring on initial load
1818
1988
  module.set.initialLoad();
1819
- if(settings.apiSettings) {
1820
- if(settings.saveRemoteData) {
1821
- module.restore.remoteValues();
1822
- }
1823
- else {
1824
- module.clearValue();
1825
- }
1989
+ if(settings.apiSettings && settings.saveRemoteData && module.get.remoteValues()) {
1990
+ module.restore.remoteValues();
1826
1991
  }
1827
1992
  else {
1828
1993
  module.set.selected();
@@ -1961,6 +2126,9 @@ $.fn.dropdown = function(parameters) {
1961
2126
  $nextSelectedItem
1962
2127
  .addClass(className.selected)
1963
2128
  ;
2129
+ if(settings.selectOnKeydown && module.is.single()) {
2130
+ module.set.selectedItem($nextSelectedItem);
2131
+ }
1964
2132
  $menu
1965
2133
  .scrollTop(newScroll)
1966
2134
  ;
@@ -1977,7 +2145,7 @@ $.fn.dropdown = function(parameters) {
1977
2145
  ? module.get.query()
1978
2146
  : '',
1979
2147
  hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0),
1980
- searchWidth = module.get.searchWidth(searchValue.length),
2148
+ searchWidth = module.get.searchWidth(),
1981
2149
  valueIsSet = searchValue !== ''
1982
2150
  ;
1983
2151
  if(isMultiple && hasSearchValue) {
@@ -1993,6 +2161,9 @@ $.fn.dropdown = function(parameters) {
1993
2161
  $text.removeClass(className.filtered);
1994
2162
  }
1995
2163
  },
2164
+ empty: function() {
2165
+ $module.addClass(className.empty);
2166
+ },
1996
2167
  loading: function() {
1997
2168
  $module.addClass(className.loading);
1998
2169
  },
@@ -2107,6 +2278,12 @@ $.fn.dropdown = function(parameters) {
2107
2278
  }
2108
2279
  }
2109
2280
  },
2281
+ selectedItem: function($item) {
2282
+ module.debug('Setting user selection to item', $item);
2283
+ module.remove.activeItem();
2284
+ module.set.activeItem($item);
2285
+ module.set.selected(module.get.choiceValue($item), $item);
2286
+ },
2110
2287
  selectedLetter: function(letter) {
2111
2288
  var
2112
2289
  $selectedItem = $item.filter('.' + className.selected),
@@ -2138,6 +2315,9 @@ $.fn.dropdown = function(parameters) {
2138
2315
  module.set.scrollPosition($nextValue);
2139
2316
  $selectedItem.removeClass(className.selected);
2140
2317
  $nextValue.addClass(className.selected);
2318
+ if(settings.selectOnKeydown && module.is.single()) {
2319
+ module.set.selectedItem($nextValue);
2320
+ }
2141
2321
  }
2142
2322
  },
2143
2323
  direction: function($menu) {
@@ -2159,6 +2339,7 @@ $.fn.dropdown = function(parameters) {
2159
2339
  },
2160
2340
  value: function(value, text, $selected) {
2161
2341
  var
2342
+ escapedValue = module.escape.value(value),
2162
2343
  hasInput = ($input.length > 0),
2163
2344
  isAddition = !module.has.value(value),
2164
2345
  currentValue = module.get.values(),
@@ -2168,7 +2349,7 @@ $.fn.dropdown = function(parameters) {
2168
2349
  newValue
2169
2350
  ;
2170
2351
  if(hasInput) {
2171
- if(stringValue == currentValue) {
2352
+ if(!settings.allowReselection && stringValue == currentValue) {
2172
2353
  module.verbose('Skipping value update already same value', value, currentValue);
2173
2354
  if(!module.is.initialLoad()) {
2174
2355
  return;
@@ -2179,10 +2360,10 @@ $.fn.dropdown = function(parameters) {
2179
2360
  module.debug('Adding user option', value);
2180
2361
  module.add.optionValue(value);
2181
2362
  }
2182
- module.debug('Updating input value', value, currentValue);
2363
+ module.debug('Updating input value', escapedValue, currentValue);
2183
2364
  internalChange = true;
2184
2365
  $input
2185
- .val(value)
2366
+ .val(escapedValue)
2186
2367
  ;
2187
2368
  if(settings.fireOnInit === false && module.is.initialLoad()) {
2188
2369
  module.debug('Input native change event ignored on initial load');
@@ -2193,8 +2374,8 @@ $.fn.dropdown = function(parameters) {
2193
2374
  internalChange = false;
2194
2375
  }
2195
2376
  else {
2196
- module.verbose('Storing value in metadata', value, $input);
2197
- if(value !== currentValue) {
2377
+ module.verbose('Storing value in metadata', escapedValue, $input);
2378
+ if(escapedValue !== currentValue) {
2198
2379
  $module.data(metadata.value, stringValue);
2199
2380
  }
2200
2381
  }
@@ -2234,6 +2415,9 @@ $.fn.dropdown = function(parameters) {
2234
2415
  return;
2235
2416
  }
2236
2417
  module.debug('Setting selected menu item to', $selectedItem);
2418
+ if(module.is.multiple()) {
2419
+ module.remove.searchWidth();
2420
+ }
2237
2421
  if(module.is.single()) {
2238
2422
  module.remove.activeItem();
2239
2423
  module.remove.selectedItem();
@@ -2299,17 +2483,18 @@ $.fn.dropdown = function(parameters) {
2299
2483
  $next = module.is.searchSelection()
2300
2484
  ? $search
2301
2485
  : $text,
2486
+ escapedValue = module.escape.value(value),
2302
2487
  $label
2303
2488
  ;
2304
2489
  $label = $('<a />')
2305
2490
  .addClass(className.label)
2306
- .attr('data-value', value)
2307
- .html(templates.label(value, text))
2491
+ .attr('data-value', escapedValue)
2492
+ .html(templates.label(escapedValue, text))
2308
2493
  ;
2309
- $label = settings.onLabelCreate.call($label, value, text);
2494
+ $label = settings.onLabelCreate.call($label, escapedValue, text);
2310
2495
 
2311
2496
  if(module.has.label(value)) {
2312
- module.debug('Label already exists, skipping', value);
2497
+ module.debug('Label already exists, skipping', escapedValue);
2313
2498
  return;
2314
2499
  }
2315
2500
  if(settings.label.variation) {
@@ -2350,34 +2535,27 @@ $.fn.dropdown = function(parameters) {
2350
2535
  },
2351
2536
  optionValue: function(value) {
2352
2537
  var
2353
- $option = $input.find('option[value="' + value + '"]'),
2354
- hasOption = ($option.length > 0)
2538
+ escapedValue = module.escape.value(value),
2539
+ $option = $input.find('option[value="' + escapedValue + '"]'),
2540
+ hasOption = ($option.length > 0)
2355
2541
  ;
2356
2542
  if(hasOption) {
2357
2543
  return;
2358
2544
  }
2359
2545
  // temporarily disconnect observer
2360
- if(selectObserver) {
2361
- selectObserver.disconnect();
2362
- module.verbose('Temporarily disconnecting mutation observer', value);
2363
- }
2546
+ module.disconnect.selectObserver();
2364
2547
  if( module.is.single() ) {
2365
2548
  module.verbose('Removing previous user addition');
2366
2549
  $input.find('option.' + className.addition).remove();
2367
2550
  }
2368
2551
  $('<option/>')
2369
- .prop('value', value)
2552
+ .prop('value', escapedValue)
2370
2553
  .addClass(className.addition)
2371
2554
  .html(value)
2372
2555
  .appendTo($input)
2373
2556
  ;
2374
2557
  module.verbose('Adding user addition as an <option>', value);
2375
- if(selectObserver) {
2376
- selectObserver.observe($input[0], {
2377
- childList : true,
2378
- subtree : true
2379
- });
2380
- }
2558
+ module.observe.select();
2381
2559
  },
2382
2560
  userSuggestion: function(value) {
2383
2561
  var
@@ -2394,28 +2572,37 @@ $.fn.dropdown = function(parameters) {
2394
2572
  $addition.remove();
2395
2573
  return;
2396
2574
  }
2397
- $item
2398
- .removeClass(className.selected)
2399
- ;
2400
2575
  if(hasUserSuggestion) {
2401
- html = settings.templates.addition( module.add.variables(message.addResult, value) );
2402
2576
  $addition
2403
- .html(html)
2577
+ .data(metadata.value, value)
2578
+ .data(metadata.text, value)
2404
2579
  .attr('data-' + metadata.value, value)
2405
2580
  .attr('data-' + metadata.text, value)
2406
2581
  .removeClass(className.filtered)
2407
- .addClass(className.selected)
2408
2582
  ;
2583
+ if(!settings.hideAdditions) {
2584
+ html = settings.templates.addition( module.add.variables(message.addResult, value) );
2585
+ $addition
2586
+ .html(html)
2587
+ ;
2588
+ }
2409
2589
  module.verbose('Replacing user suggestion with new value', $addition);
2410
2590
  }
2411
2591
  else {
2412
2592
  $addition = module.create.userChoice(value);
2413
2593
  $addition
2414
2594
  .prependTo($menu)
2415
- .addClass(className.selected)
2416
2595
  ;
2417
2596
  module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
2418
2597
  }
2598
+ if(!settings.hideAdditions || module.is.allFiltered()) {
2599
+ $addition
2600
+ .addClass(className.selected)
2601
+ .siblings()
2602
+ .removeClass(className.selected)
2603
+ ;
2604
+ }
2605
+ module.refreshItems();
2419
2606
  },
2420
2607
  variables: function(message, term) {
2421
2608
  var
@@ -2488,6 +2675,9 @@ $.fn.dropdown = function(parameters) {
2488
2675
  activeLabel: function() {
2489
2676
  $module.find(selector.label).removeClass(className.active);
2490
2677
  },
2678
+ empty: function() {
2679
+ $module.removeClass(className.empty);
2680
+ },
2491
2681
  loading: function() {
2492
2682
  $module.removeClass(className.loading);
2493
2683
  },
@@ -2514,11 +2704,13 @@ $.fn.dropdown = function(parameters) {
2514
2704
  else {
2515
2705
  $item.removeClass(className.filtered);
2516
2706
  }
2707
+ module.remove.empty();
2517
2708
  },
2518
2709
  optionValue: function(value) {
2519
2710
  var
2520
- $option = $input.find('option[value="' + value + '"]'),
2521
- hasOption = ($option.length > 0)
2711
+ escapedValue = module.escape.value(value),
2712
+ $option = $input.find('option[value="' + escapedValue + '"]'),
2713
+ hasOption = ($option.length > 0)
2522
2714
  ;
2523
2715
  if(!hasOption || !$option.hasClass(className.addition)) {
2524
2716
  return;
@@ -2526,10 +2718,10 @@ $.fn.dropdown = function(parameters) {
2526
2718
  // temporarily disconnect observer
2527
2719
  if(selectObserver) {
2528
2720
  selectObserver.disconnect();
2529
- module.verbose('Temporarily disconnecting mutation observer', value);
2721
+ module.verbose('Temporarily disconnecting mutation observer');
2530
2722
  }
2531
2723
  $option.remove();
2532
- module.verbose('Removing user addition as an <option>', value);
2724
+ module.verbose('Removing user addition as an <option>', escapedValue);
2533
2725
  if(selectObserver) {
2534
2726
  selectObserver.observe($input[0], {
2535
2727
  childList : true,
@@ -2540,11 +2732,17 @@ $.fn.dropdown = function(parameters) {
2540
2732
  message: function() {
2541
2733
  $menu.children(selector.message).remove();
2542
2734
  },
2735
+ searchWidth: function() {
2736
+ $search.css('width', '');
2737
+ },
2543
2738
  searchTerm: function() {
2544
2739
  module.verbose('Cleared search term');
2545
2740
  $search.val('');
2546
2741
  module.set.filtered();
2547
2742
  },
2743
+ userAddition: function() {
2744
+ $item.filter(selector.addition).remove();
2745
+ },
2548
2746
  selected: function(value, $selectedItem) {
2549
2747
  $selectedItem = (settings.allowAdditions)
2550
2748
  ? $selectedItem || module.get.itemWithAdditions(value)
@@ -2657,6 +2855,7 @@ $.fn.dropdown = function(parameters) {
2657
2855
  module.debug('Label remove callback cancelled removal');
2658
2856
  return;
2659
2857
  }
2858
+ module.remove.message();
2660
2859
  if(isUserValue) {
2661
2860
  module.remove.value(stringValue);
2662
2861
  module.remove.label(stringValue);
@@ -2691,12 +2890,28 @@ $.fn.dropdown = function(parameters) {
2691
2890
  },
2692
2891
 
2693
2892
  has: {
2893
+ menuSearch: function() {
2894
+ return (module.has.search() && $search.closest($menu).length > 0);
2895
+ },
2694
2896
  search: function() {
2695
2897
  return ($search.length > 0);
2696
2898
  },
2899
+ sizer: function() {
2900
+ return ($sizer.length > 0);
2901
+ },
2697
2902
  selectInput: function() {
2698
2903
  return ( $input.is('select') );
2699
2904
  },
2905
+ minCharacters: function(searchTerm) {
2906
+ if(settings.minCharacters) {
2907
+ searchTerm = (searchTerm !== undefined)
2908
+ ? String(searchTerm)
2909
+ : String(module.get.query())
2910
+ ;
2911
+ return (searchTerm.length >= settings.minCharacters);
2912
+ }
2913
+ return true;
2914
+ },
2700
2915
  firstLetter: function($item, letter) {
2701
2916
  var
2702
2917
  text,
@@ -2724,15 +2939,22 @@ $.fn.dropdown = function(parameters) {
2724
2939
  },
2725
2940
  label: function(value) {
2726
2941
  var
2727
- $labels = $module.find(selector.label)
2942
+ escapedValue = module.escape.value(value),
2943
+ $labels = $module.find(selector.label)
2728
2944
  ;
2729
- return ($labels.filter('[data-value="' + value +'"]').length > 0);
2945
+ return ($labels.filter('[data-value="' + escapedValue +'"]').length > 0);
2730
2946
  },
2731
2947
  maxSelections: function() {
2732
2948
  return (settings.maxSelections && module.get.selectionCount() >= settings.maxSelections);
2733
2949
  },
2734
2950
  allResultsFiltered: function() {
2735
- return ($item.filter(selector.unselectable).length === $item.length);
2951
+ var
2952
+ $normalResults = $item.not(selector.addition)
2953
+ ;
2954
+ return ($normalResults.filter(selector.unselectable).length === $normalResults.length);
2955
+ },
2956
+ userSuggestion: function() {
2957
+ return ($menu.children(selector.addition).length > 0);
2736
2958
  },
2737
2959
  query: function() {
2738
2960
  return (module.get.query() !== '');
@@ -2755,6 +2977,9 @@ $.fn.dropdown = function(parameters) {
2755
2977
  active: function() {
2756
2978
  return $module.hasClass(className.active);
2757
2979
  },
2980
+ bubbledLabelClick: function(event) {
2981
+ return $(event.target).is('select, input') && $module.closest('label').length > 0;
2982
+ },
2758
2983
  alreadySetup: function() {
2759
2984
  return ($module.is('select') && $module.parent(selector.dropdown).length > 0 && $module.prev().length === 0);
2760
2985
  },
@@ -2774,7 +2999,7 @@ $.fn.dropdown = function(parameters) {
2774
2999
  return (document.activeElement === $search[0]);
2775
3000
  },
2776
3001
  allFiltered: function() {
2777
- return( (module.is.multiple() || module.has.search()) && !module.has.message() && module.has.allResultsFiltered() );
3002
+ return( (module.is.multiple() || module.has.search()) && !(settings.hideAdditions == false && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered() );
2778
3003
  },
2779
3004
  hidden: function($subMenu) {
2780
3005
  return !module.is.visible($subMenu);
@@ -3031,6 +3256,26 @@ $.fn.dropdown = function(parameters) {
3031
3256
  },
3032
3257
 
3033
3258
  escape: {
3259
+ value: function(value) {
3260
+ var
3261
+ multipleValues = $.isArray(value),
3262
+ stringValue = (typeof value === 'string'),
3263
+ isUnparsable = (!stringValue && !multipleValues),
3264
+ hasQuotes = (stringValue && value.search(regExp.quote) !== -1),
3265
+ values = []
3266
+ ;
3267
+ if(!module.has.selectInput() || isUnparsable || !hasQuotes) {
3268
+ return value;
3269
+ }
3270
+ module.debug('Encoding quote values for use in select', value);
3271
+ if(multipleValues) {
3272
+ $.each(value, function(index, value){
3273
+ values.push(value.replace(regExp.quote, '&quot;'));
3274
+ });
3275
+ return values;
3276
+ }
3277
+ return value.replace(regExp.quote, '&quot;');
3278
+ },
3034
3279
  regExp: function(text) {
3035
3280
  text = String(text);
3036
3281
  return text.replace(regExp.escape, '\\$&');
@@ -3043,7 +3288,12 @@ $.fn.dropdown = function(parameters) {
3043
3288
  $.extend(true, settings, name);
3044
3289
  }
3045
3290
  else if(value !== undefined) {
3046
- settings[name] = value;
3291
+ if($.isPlainObject(settings[name])) {
3292
+ $.extend(true, settings[name], value);
3293
+ }
3294
+ else {
3295
+ settings[name] = value;
3296
+ }
3047
3297
  }
3048
3298
  else {
3049
3299
  return settings[name];
@@ -3061,7 +3311,7 @@ $.fn.dropdown = function(parameters) {
3061
3311
  }
3062
3312
  },
3063
3313
  debug: function() {
3064
- if(settings.debug) {
3314
+ if(!settings.silent && settings.debug) {
3065
3315
  if(settings.performance) {
3066
3316
  module.performance.log(arguments);
3067
3317
  }
@@ -3072,7 +3322,7 @@ $.fn.dropdown = function(parameters) {
3072
3322
  }
3073
3323
  },
3074
3324
  verbose: function() {
3075
- if(settings.verbose && settings.debug) {
3325
+ if(!settings.silent && settings.verbose && settings.debug) {
3076
3326
  if(settings.performance) {
3077
3327
  module.performance.log(arguments);
3078
3328
  }
@@ -3083,8 +3333,10 @@ $.fn.dropdown = function(parameters) {
3083
3333
  }
3084
3334
  },
3085
3335
  error: function() {
3086
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
3087
- module.error.apply(console, arguments);
3336
+ if(!settings.silent) {
3337
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
3338
+ module.error.apply(console, arguments);
3339
+ }
3088
3340
  },
3089
3341
  performance: {
3090
3342
  log: function(message) {
@@ -3215,6 +3467,7 @@ $.fn.dropdown = function(parameters) {
3215
3467
 
3216
3468
  $.fn.dropdown.settings = {
3217
3469
 
3470
+ silent : false,
3218
3471
  debug : false,
3219
3472
  verbose : false,
3220
3473
  performance : true,
@@ -3224,28 +3477,33 @@ $.fn.dropdown.settings = {
3224
3477
 
3225
3478
 
3226
3479
  apiSettings : false,
3227
- saveRemoteData : true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
3228
- throttle : 200, // How long to wait after last user input to search remotely
3480
+ selectOnKeydown : true, // Whether selection should occur automatically when keyboard shortcuts used
3481
+ minCharacters : 0, // Minimum characters required to trigger API call
3482
+ saveRemoteData : true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
3483
+ throttle : 200, // How long to wait after last user input to search remotely
3229
3484
 
3230
- context : window, // Context to use when determining if on screen
3485
+ context : window, // Context to use when determining if on screen
3231
3486
  direction : 'auto', // Whether dropdown should always open in one direction
3232
3487
  keepOnScreen : true, // Whether dropdown should check whether it is on screen before showing
3233
3488
 
3234
3489
  match : 'both', // what to match against with search selection (both, text, or label)
3235
- fullTextSearch : false, // search anywhere in value
3490
+ fullTextSearch : false, // search anywhere in value (set to 'exact' to require exact matches)
3236
3491
 
3237
3492
  placeholder : 'auto', // whether to convert blank <select> values to placeholder text
3238
3493
  preserveHTML : true, // preserve html when selecting value
3239
3494
  sortSelect : false, // sort selection on init
3240
3495
 
3241
3496
  forceSelection : true, // force a choice on blur with search selection
3497
+
3242
3498
  allowAdditions : false, // whether multiple select should allow user added values
3499
+ hideAdditions : true, // whether or not to hide special message prompting a user they can enter a value
3243
3500
 
3244
3501
  maxSelections : false, // When set to a number limits the number of selections to this count
3245
3502
  useLabels : true, // whether multiple select should filter currently active selections from choices
3246
3503
  delimiter : ',', // when multiselect uses normal <input> the values will be delimited with this character
3247
3504
 
3248
3505
  showOnFocus : true, // show menu on focus
3506
+ allowReselection : false, // whether current value should trigger callbacks when reselected
3249
3507
  allowTab : true, // add tabindex to element
3250
3508
  allowCategorySelection : false, // allow elements with sub-menus to be selected
3251
3509
 
@@ -3254,7 +3512,7 @@ $.fn.dropdown.settings = {
3254
3512
  transition : 'auto', // auto transition will slide down or up based on direction
3255
3513
  duration : 200, // duration of transition
3256
3514
 
3257
- glyphWidth : 1.0714, // widest glyph width in em (W is 1.0714 em) used to calculate multiselect input width
3515
+ glyphWidth : 1.037, // widest glyph width in em (W is 1.037 em) used to calculate multiselect input width
3258
3516
 
3259
3517
  // label settings on multi-select
3260
3518
  label: {
@@ -3308,6 +3566,7 @@ $.fn.dropdown.settings = {
3308
3566
 
3309
3567
  regExp : {
3310
3568
  escape : /[-[\]{}()*+?.,\\^$|#\s]/g,
3569
+ quote : /"/g
3311
3570
  },
3312
3571
 
3313
3572
  metadata : {
@@ -3320,10 +3579,12 @@ $.fn.dropdown.settings = {
3320
3579
 
3321
3580
  // property names for remote query
3322
3581
  fields: {
3323
- remoteValues : 'results', // grouping for api results
3324
- values : 'values', // grouping for all dropdown values
3325
- name : 'name', // displayed dropdown text
3326
- value : 'value' // actual dropdown value
3582
+ remoteValues : 'results', // grouping for api results
3583
+ values : 'values', // grouping for all dropdown values
3584
+ disabled : 'disabled', // whether value should be disabled
3585
+ name : 'name', // displayed dropdown text
3586
+ value : 'value', // actual dropdown value
3587
+ text : 'text' // displayed text when selected
3327
3588
  },
3328
3589
 
3329
3590
  keys : {
@@ -3343,6 +3604,7 @@ $.fn.dropdown.settings = {
3343
3604
  selector : {
3344
3605
  addition : '.addition',
3345
3606
  dropdown : '.ui.dropdown',
3607
+ hidden : '.hidden',
3346
3608
  icon : '> .dropdown.icon',
3347
3609
  input : '> input[type="hidden"], > select',
3348
3610
  item : '.item',
@@ -3352,7 +3614,8 @@ $.fn.dropdown.settings = {
3352
3614
  menu : '.menu',
3353
3615
  message : '.message',
3354
3616
  menuIcon : '.dropdown.icon',
3355
- search : 'input.search, .menu > .search > input',
3617
+ search : 'input.search, .menu > .search > input, .menu input.search',
3618
+ sizer : '> input.sizer',
3356
3619
  text : '> .text:not(.icon)',
3357
3620
  unselectable : '.disabled, .filtered'
3358
3621
  },
@@ -3362,6 +3625,7 @@ $.fn.dropdown.settings = {
3362
3625
  addition : 'addition',
3363
3626
  animating : 'animating',
3364
3627
  disabled : 'disabled',
3628
+ empty : 'empty',
3365
3629
  dropdown : 'ui dropdown',
3366
3630
  filtered : 'filtered',
3367
3631
  hidden : 'hidden transition',
@@ -3372,6 +3636,7 @@ $.fn.dropdown.settings = {
3372
3636
  message : 'message',
3373
3637
  multiple : 'multiple',
3374
3638
  placeholder : 'default',
3639
+ sizer : 'sizer',
3375
3640
  search : 'search',
3376
3641
  selected : 'selected',
3377
3642
  selection : 'selection',
@@ -3416,7 +3681,17 @@ $.fn.dropdown.settings.templates = {
3416
3681
  html = ''
3417
3682
  ;
3418
3683
  $.each(values, function(index, option) {
3419
- html += '<div class="item" data-value="' + option[fields.value] + '">' + option[fields.name] + '</div>';
3684
+ var
3685
+ maybeText = (option[fields.text])
3686
+ ? 'data-text="' + option[fields.text] + '"'
3687
+ : '',
3688
+ maybeDisabled = (option[fields.disabled])
3689
+ ? 'disabled '
3690
+ : ''
3691
+ ;
3692
+ html += '<div class="'+ maybeDisabled +'item" data-value="' + option[fields.value] + '"' + maybeText + '>'
3693
+ html += option[fields.name];
3694
+ html += '</div>';
3420
3695
  });
3421
3696
  return html;
3422
3697
  },