rails-active-ui 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/app/javascript/ui/controllers/turbo_modal_controller.js +36 -0
  3. data/config/importmap.rb +1 -0
  4. data/formantic-ui/components/accordion.css +369 -0
  5. data/formantic-ui/components/accordion.js +595 -0
  6. data/formantic-ui/components/accordion.min.css +9 -0
  7. data/formantic-ui/components/accordion.min.js +11 -0
  8. data/formantic-ui/components/ad.css +264 -0
  9. data/formantic-ui/components/ad.min.css +10 -0
  10. data/formantic-ui/components/api.js +1225 -0
  11. data/formantic-ui/components/api.min.js +11 -0
  12. data/formantic-ui/components/breadcrumb.css +135 -0
  13. data/formantic-ui/components/breadcrumb.min.css +9 -0
  14. data/formantic-ui/components/button.css +4058 -0
  15. data/formantic-ui/components/button.min.css +9 -0
  16. data/formantic-ui/components/calendar.css +327 -0
  17. data/formantic-ui/components/calendar.js +2045 -0
  18. data/formantic-ui/components/calendar.min.css +9 -0
  19. data/formantic-ui/components/calendar.min.js +11 -0
  20. data/formantic-ui/components/card.css +1881 -0
  21. data/formantic-ui/components/card.min.css +9 -0
  22. data/formantic-ui/components/checkbox.css +785 -0
  23. data/formantic-ui/components/checkbox.js +888 -0
  24. data/formantic-ui/components/checkbox.min.css +9 -0
  25. data/formantic-ui/components/checkbox.min.js +11 -0
  26. data/formantic-ui/components/comment.css +283 -0
  27. data/formantic-ui/components/comment.min.css +9 -0
  28. data/formantic-ui/components/container.css +300 -0
  29. data/formantic-ui/components/container.min.css +9 -0
  30. data/formantic-ui/components/dimmer.css +367 -0
  31. data/formantic-ui/components/dimmer.js +732 -0
  32. data/formantic-ui/components/dimmer.min.css +9 -0
  33. data/formantic-ui/components/dimmer.min.js +11 -0
  34. data/formantic-ui/components/divider.css +287 -0
  35. data/formantic-ui/components/divider.min.css +9 -0
  36. data/formantic-ui/components/dropdown.css +2087 -0
  37. data/formantic-ui/components/dropdown.js +4432 -0
  38. data/formantic-ui/components/dropdown.min.css +9 -0
  39. data/formantic-ui/components/dropdown.min.js +11 -0
  40. data/formantic-ui/components/embed.css +155 -0
  41. data/formantic-ui/components/embed.js +688 -0
  42. data/formantic-ui/components/embed.min.css +9 -0
  43. data/formantic-ui/components/embed.min.js +11 -0
  44. data/formantic-ui/components/emoji.css +15311 -0
  45. data/formantic-ui/components/emoji.min.css +9 -0
  46. data/formantic-ui/components/feed.css +799 -0
  47. data/formantic-ui/components/feed.min.css +9 -0
  48. data/formantic-ui/components/flag.css +1149 -0
  49. data/formantic-ui/components/flag.min.css +9 -0
  50. data/formantic-ui/components/flyout.css +546 -0
  51. data/formantic-ui/components/flyout.js +1551 -0
  52. data/formantic-ui/components/flyout.min.css +9 -0
  53. data/formantic-ui/components/flyout.min.js +11 -0
  54. data/formantic-ui/components/form.css +1885 -0
  55. data/formantic-ui/components/form.js +2199 -0
  56. data/formantic-ui/components/form.min.css +9 -0
  57. data/formantic-ui/components/form.min.js +11 -0
  58. data/formantic-ui/components/grid.css +1952 -0
  59. data/formantic-ui/components/grid.min.css +9 -0
  60. data/formantic-ui/components/header.css +778 -0
  61. data/formantic-ui/components/header.min.css +9 -0
  62. data/formantic-ui/components/icon.css +7066 -0
  63. data/formantic-ui/components/icon.min.css +9 -0
  64. data/formantic-ui/components/image.css +315 -0
  65. data/formantic-ui/components/image.min.css +9 -0
  66. data/formantic-ui/components/input.css +1566 -0
  67. data/formantic-ui/components/input.min.css +9 -0
  68. data/formantic-ui/components/item.css +534 -0
  69. data/formantic-ui/components/item.min.css +9 -0
  70. data/formantic-ui/components/label.css +2114 -0
  71. data/formantic-ui/components/label.min.css +9 -0
  72. data/formantic-ui/components/list.css +955 -0
  73. data/formantic-ui/components/list.min.css +9 -0
  74. data/formantic-ui/components/loader.css +787 -0
  75. data/formantic-ui/components/loader.min.css +9 -0
  76. data/formantic-ui/components/menu.css +2131 -0
  77. data/formantic-ui/components/menu.min.css +9 -0
  78. data/formantic-ui/components/message.css +619 -0
  79. data/formantic-ui/components/message.min.css +9 -0
  80. data/formantic-ui/components/modal.css +779 -0
  81. data/formantic-ui/components/modal.js +1637 -0
  82. data/formantic-ui/components/modal.min.css +9 -0
  83. data/formantic-ui/components/modal.min.js +11 -0
  84. data/formantic-ui/components/nag.css +290 -0
  85. data/formantic-ui/components/nag.js +566 -0
  86. data/formantic-ui/components/nag.min.css +9 -0
  87. data/formantic-ui/components/nag.min.js +11 -0
  88. data/formantic-ui/components/placeholder.css +228 -0
  89. data/formantic-ui/components/placeholder.min.css +9 -0
  90. data/formantic-ui/components/popup.css +1184 -0
  91. data/formantic-ui/components/popup.js +1561 -0
  92. data/formantic-ui/components/popup.min.css +9 -0
  93. data/formantic-ui/components/popup.min.js +11 -0
  94. data/formantic-ui/components/progress.css +761 -0
  95. data/formantic-ui/components/progress.js +979 -0
  96. data/formantic-ui/components/progress.min.css +9 -0
  97. data/formantic-ui/components/progress.min.js +11 -0
  98. data/formantic-ui/components/rail.css +147 -0
  99. data/formantic-ui/components/rail.min.css +9 -0
  100. data/formantic-ui/components/rating.css +414 -0
  101. data/formantic-ui/components/rating.js +540 -0
  102. data/formantic-ui/components/rating.min.css +9 -0
  103. data/formantic-ui/components/rating.min.js +11 -0
  104. data/formantic-ui/components/reset.css +386 -0
  105. data/formantic-ui/components/reset.min.css +9 -0
  106. data/formantic-ui/components/reveal.css +277 -0
  107. data/formantic-ui/components/reveal.min.css +9 -0
  108. data/formantic-ui/components/search.css +541 -0
  109. data/formantic-ui/components/search.js +1641 -0
  110. data/formantic-ui/components/search.min.css +9 -0
  111. data/formantic-ui/components/search.min.js +11 -0
  112. data/formantic-ui/components/segment.css +1053 -0
  113. data/formantic-ui/components/segment.min.css +9 -0
  114. data/formantic-ui/components/shape.css +144 -0
  115. data/formantic-ui/components/shape.js +797 -0
  116. data/formantic-ui/components/shape.min.css +9 -0
  117. data/formantic-ui/components/shape.min.js +11 -0
  118. data/formantic-ui/components/sidebar.css +539 -0
  119. data/formantic-ui/components/sidebar.js +1054 -0
  120. data/formantic-ui/components/sidebar.min.css +9 -0
  121. data/formantic-ui/components/sidebar.min.js +11 -0
  122. data/formantic-ui/components/site.css +286 -0
  123. data/formantic-ui/components/site.js +455 -0
  124. data/formantic-ui/components/site.min.css +9 -0
  125. data/formantic-ui/components/site.min.js +11 -0
  126. data/formantic-ui/components/slider.css +926 -0
  127. data/formantic-ui/components/slider.js +1546 -0
  128. data/formantic-ui/components/slider.min.css +9 -0
  129. data/formantic-ui/components/slider.min.js +11 -0
  130. data/formantic-ui/components/state.js +697 -0
  131. data/formantic-ui/components/state.min.js +11 -0
  132. data/formantic-ui/components/statistic.css +586 -0
  133. data/formantic-ui/components/statistic.min.css +9 -0
  134. data/formantic-ui/components/step.css +1538 -0
  135. data/formantic-ui/components/step.min.css +9 -0
  136. data/formantic-ui/components/sticky.css +73 -0
  137. data/formantic-ui/components/sticky.js +917 -0
  138. data/formantic-ui/components/sticky.min.css +9 -0
  139. data/formantic-ui/components/sticky.min.js +11 -0
  140. data/formantic-ui/components/tab.css +84 -0
  141. data/formantic-ui/components/tab.js +967 -0
  142. data/formantic-ui/components/tab.min.css +9 -0
  143. data/formantic-ui/components/tab.min.js +11 -0
  144. data/formantic-ui/components/table.css +3473 -0
  145. data/formantic-ui/components/table.min.css +9 -0
  146. data/formantic-ui/components/text.css +155 -0
  147. data/formantic-ui/components/text.min.css +9 -0
  148. data/formantic-ui/components/toast.css +751 -0
  149. data/formantic-ui/components/toast.js +964 -0
  150. data/formantic-ui/components/toast.min.css +9 -0
  151. data/formantic-ui/components/toast.min.js +11 -0
  152. data/formantic-ui/components/transition.css +1148 -0
  153. data/formantic-ui/components/transition.js +1034 -0
  154. data/formantic-ui/components/transition.min.css +9 -0
  155. data/formantic-ui/components/transition.min.js +11 -0
  156. data/formantic-ui/components/visibility.js +1292 -0
  157. data/formantic-ui/components/visibility.min.js +11 -0
  158. data/formantic-ui/semantic.css +78485 -0
  159. data/formantic-ui/semantic.js +31036 -0
  160. data/formantic-ui/semantic.min.css +11 -0
  161. data/formantic-ui/semantic.min.js +11 -0
  162. data/formantic-ui/themes/basic/assets/fonts/LICENSE.txt +91 -0
  163. data/formantic-ui/themes/basic/assets/fonts/icons.woff +0 -0
  164. data/formantic-ui/themes/basic/assets/fonts/icons.woff2 +0 -0
  165. data/formantic-ui/themes/default/assets/fonts/LICENSE_Lato.txt +94 -0
  166. data/formantic-ui/themes/default/assets/fonts/LICENSE_icons.txt +165 -0
  167. data/formantic-ui/themes/default/assets/fonts/Lato-Bold.woff +0 -0
  168. data/formantic-ui/themes/default/assets/fonts/Lato-Bold.woff2 +0 -0
  169. data/formantic-ui/themes/default/assets/fonts/Lato-BoldItalic.woff +0 -0
  170. data/formantic-ui/themes/default/assets/fonts/Lato-BoldItalic.woff2 +0 -0
  171. data/formantic-ui/themes/default/assets/fonts/Lato-Italic.woff +0 -0
  172. data/formantic-ui/themes/default/assets/fonts/Lato-Italic.woff2 +0 -0
  173. data/formantic-ui/themes/default/assets/fonts/Lato-Regular.woff +0 -0
  174. data/formantic-ui/themes/default/assets/fonts/Lato-Regular.woff2 +0 -0
  175. data/formantic-ui/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  176. data/formantic-ui/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  177. data/formantic-ui/themes/default/assets/fonts/LatoLatin-BoldItalic.woff +0 -0
  178. data/formantic-ui/themes/default/assets/fonts/LatoLatin-BoldItalic.woff2 +0 -0
  179. data/formantic-ui/themes/default/assets/fonts/LatoLatin-Italic.woff +0 -0
  180. data/formantic-ui/themes/default/assets/fonts/LatoLatin-Italic.woff2 +0 -0
  181. data/formantic-ui/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  182. data/formantic-ui/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  183. data/formantic-ui/themes/default/assets/fonts/brand-icons.woff +0 -0
  184. data/formantic-ui/themes/default/assets/fonts/brand-icons.woff2 +0 -0
  185. data/formantic-ui/themes/default/assets/fonts/icons.woff +0 -0
  186. data/formantic-ui/themes/default/assets/fonts/icons.woff2 +0 -0
  187. data/formantic-ui/themes/default/assets/fonts/outline-icons.woff +0 -0
  188. data/formantic-ui/themes/default/assets/fonts/outline-icons.woff2 +0 -0
  189. data/formantic-ui/themes/famfamfam/assets/images/flags.png +0 -0
  190. data/formantic-ui/themes/github/assets/fonts/LICENSE.txt +94 -0
  191. data/formantic-ui/themes/github/assets/fonts/octicons.woff +0 -0
  192. data/formantic-ui/themes/github/assets/fonts/octicons.woff2 +0 -0
  193. data/formantic-ui/themes/material/assets/fonts/LICENSE.txt +202 -0
  194. data/formantic-ui/themes/material/assets/fonts/icons.woff +0 -0
  195. data/formantic-ui/themes/material/assets/fonts/icons.woff2 +0 -0
  196. data/lib/ui/version.rb +1 -1
  197. metadata +194 -1
@@ -0,0 +1,4432 @@
1
+ /*!
2
+ * # Fomantic-UI 2.9.4 - Dropdown
3
+ * https://github.com/fomantic/Fomantic-UI/
4
+ *
5
+ *
6
+ * Released under the MIT license
7
+ * https://opensource.org/licenses/MIT
8
+ *
9
+ */
10
+
11
+ (function ($, window, document) {
12
+ 'use strict';
13
+
14
+ function isFunction(obj) {
15
+ return typeof obj === 'function' && typeof obj.nodeType !== 'number';
16
+ }
17
+
18
+ window = window !== undefined && window.Math === Math
19
+ ? window
20
+ : globalThis;
21
+
22
+ $.fn.dropdown = function (parameters) {
23
+ var
24
+ $allModules = $(this),
25
+ $document = $(document),
26
+
27
+ time = Date.now(),
28
+ performance = [],
29
+
30
+ query = arguments[0],
31
+ methodInvoked = typeof query === 'string',
32
+ queryArguments = [].slice.call(arguments, 1),
33
+ contextCheck = function (context, win) {
34
+ var $context;
35
+ if ([window, document].indexOf(context) >= 0) {
36
+ $context = $(context);
37
+ } else {
38
+ $context = $(win.document).find(context);
39
+ if ($context.length === 0) {
40
+ $context = win.frameElement ? contextCheck(context, win.parent) : window;
41
+ }
42
+ }
43
+
44
+ return $context;
45
+ },
46
+ returnedValue
47
+ ;
48
+
49
+ $allModules.each(function (elementIndex) {
50
+ var
51
+ settings = $.isPlainObject(parameters)
52
+ ? $.extend(true, {}, $.fn.dropdown.settings, parameters)
53
+ : $.extend({}, $.fn.dropdown.settings),
54
+
55
+ className = settings.className,
56
+ message = settings.message,
57
+ fields = settings.fields,
58
+ keys = settings.keys,
59
+ metadata = settings.metadata,
60
+ namespace = settings.namespace,
61
+ regExp = settings.regExp,
62
+ selector = settings.selector,
63
+ error = settings.error,
64
+ templates = settings.templates,
65
+
66
+ eventNamespace = '.' + namespace,
67
+ moduleNamespace = 'module-' + namespace,
68
+
69
+ $module = $(this),
70
+ $context = contextCheck(settings.context, window),
71
+ $text = $module.find(selector.text),
72
+ $search = $module.find(selector.search),
73
+ $sizer = $module.find(selector.sizer),
74
+ $input = $module.find(selector.input),
75
+ $icon = $module.find(selector.icon),
76
+ $clear = $module.find(selector.clearIcon),
77
+
78
+ $combo = $module.prev().find(selector.text).length > 0
79
+ ? $module.prev().find(selector.text)
80
+ : $module.prev(),
81
+
82
+ $menu = $module.children(selector.menu),
83
+ $item = $menu.find(selector.item),
84
+ $divider = settings.hideDividers
85
+ ? $item.parent().children(selector.divider)
86
+ : $(),
87
+
88
+ activated = false,
89
+ itemActivated = false,
90
+ internalChange = false,
91
+ iconClicked = false,
92
+ element = this,
93
+ focused = false,
94
+ instance = $module.data(moduleNamespace),
95
+
96
+ selectActionActive,
97
+ initialLoad,
98
+ pageLostFocus,
99
+ willRefocus,
100
+ elementNamespace,
101
+ id,
102
+ selectObserver,
103
+ menuObserver,
104
+ classObserver,
105
+ module,
106
+ tempDisableApiCache = false
107
+ ;
108
+
109
+ module = {
110
+
111
+ initialize: function () {
112
+ module.debug('Initializing dropdown', settings);
113
+
114
+ if (module.is.alreadySetup()) {
115
+ module.setup.reference();
116
+ } else {
117
+ if (settings.ignoreDiacritics && !String.prototype.normalize) {
118
+ settings.ignoreDiacritics = false;
119
+ module.error(error.noNormalize, element);
120
+ }
121
+
122
+ module.create.id();
123
+ module.setup.layout();
124
+
125
+ if (settings.values) {
126
+ module.set.initialLoad();
127
+ module.change.values(settings.values);
128
+ module.remove.initialLoad();
129
+ }
130
+ if (module.get.placeholderText() !== '') {
131
+ module.set.placeholderText();
132
+ }
133
+
134
+ module.refreshData();
135
+
136
+ module.save.defaults();
137
+ module.restore.selected();
138
+
139
+ module.bind.events();
140
+
141
+ module.observeChanges();
142
+ module.instantiate();
143
+ }
144
+ },
145
+
146
+ instantiate: function () {
147
+ module.verbose('Storing instance of dropdown', module);
148
+ instance = module;
149
+ $module
150
+ .data(moduleNamespace, module)
151
+ ;
152
+ },
153
+
154
+ destroy: function () {
155
+ module.verbose('Destroying previous dropdown', $module);
156
+ module.remove.tabbable();
157
+ module.remove.active();
158
+ $menu.transition('stop all');
159
+ $menu.removeClass(className.visible).addClass(className.hidden);
160
+ $module
161
+ .off(eventNamespace)
162
+ .removeData(moduleNamespace)
163
+ ;
164
+ $menu
165
+ .off(eventNamespace)
166
+ ;
167
+ $document
168
+ .off(elementNamespace)
169
+ ;
170
+ module.disconnect.menuObserver();
171
+ module.disconnect.selectObserver();
172
+ module.disconnect.classObserver();
173
+ },
174
+
175
+ observeChanges: function () {
176
+ if ('MutationObserver' in window) {
177
+ selectObserver = new MutationObserver(module.event.select.mutation);
178
+ menuObserver = new MutationObserver(module.event.menu.mutation);
179
+ classObserver = new MutationObserver(module.event.class.mutation);
180
+ module.debug('Setting up mutation observer', selectObserver, menuObserver, classObserver);
181
+ module.observe.select();
182
+ module.observe.menu();
183
+ module.observe.class();
184
+ }
185
+ },
186
+
187
+ disconnect: {
188
+ menuObserver: function () {
189
+ if (menuObserver) {
190
+ menuObserver.disconnect();
191
+ }
192
+ },
193
+ selectObserver: function () {
194
+ if (selectObserver) {
195
+ selectObserver.disconnect();
196
+ }
197
+ },
198
+ classObserver: function () {
199
+ if (classObserver) {
200
+ classObserver.disconnect();
201
+ }
202
+ },
203
+ },
204
+ observe: {
205
+ select: function () {
206
+ if (module.has.input() && selectObserver) {
207
+ selectObserver.observe($module[0], {
208
+ attributes: true,
209
+ childList: true,
210
+ subtree: true,
211
+ });
212
+ }
213
+ },
214
+ menu: function () {
215
+ if (module.has.menu() && menuObserver) {
216
+ menuObserver.observe($menu[0], {
217
+ childList: true,
218
+ subtree: true,
219
+ });
220
+ }
221
+ },
222
+ class: function () {
223
+ if (module.has.search() && classObserver) {
224
+ classObserver.observe($module[0], {
225
+ attributes: true,
226
+ });
227
+ }
228
+ },
229
+ },
230
+
231
+ create: {
232
+ id: function () {
233
+ id = (Math.random().toString(16) + '000000000').slice(2, 10);
234
+ elementNamespace = '.' + id;
235
+ module.verbose('Creating unique id for element', id);
236
+ },
237
+ userChoice: function (values) {
238
+ var
239
+ $userChoices,
240
+ $userChoice,
241
+ html
242
+ ;
243
+ values = values || module.get.userValues();
244
+ if (!values) {
245
+ return false;
246
+ }
247
+ values = Array.isArray(values)
248
+ ? values
249
+ : [values];
250
+ $.each(values, function (index, value) {
251
+ if (module.get.item(value) === false) {
252
+ html = settings.templates.addition(module.add.variables(message.addResult, value));
253
+ $userChoice = $('<div />')
254
+ .html(html)
255
+ .attr('data-' + metadata.value, value)
256
+ .attr('data-' + metadata.text, value)
257
+ .addClass(className.addition)
258
+ .addClass(className.item)
259
+ ;
260
+ if (settings.hideAdditions) {
261
+ $userChoice.addClass(className.hidden);
262
+ }
263
+ $userChoices = $userChoices === undefined
264
+ ? $userChoice
265
+ : $userChoices.add($userChoice);
266
+ module.verbose('Creating user choices for value', value, $userChoice);
267
+ }
268
+ });
269
+
270
+ return $userChoices;
271
+ },
272
+ userLabels: function (value) {
273
+ var
274
+ userValues = module.get.userValues()
275
+ ;
276
+ if (userValues) {
277
+ module.debug('Adding user labels', userValues);
278
+ $.each(userValues, function (index, value) {
279
+ module.verbose('Adding custom user value');
280
+ module.add.label(value, value);
281
+ });
282
+ }
283
+ },
284
+ menu: function () {
285
+ $menu = $('<div />')
286
+ .addClass(className.menu)
287
+ .appendTo($module)
288
+ ;
289
+ },
290
+ sizer: function () {
291
+ $sizer = $('<span />')
292
+ .addClass(className.sizer)
293
+ .insertAfter($search)
294
+ ;
295
+ },
296
+ },
297
+
298
+ search: function (query) {
299
+ query = query !== undefined
300
+ ? query
301
+ : module.get.query();
302
+ module.verbose('Searching for query', query);
303
+ if (settings.fireOnInit === false && module.is.initialLoad()) {
304
+ module.verbose('Skipping callback on initial load', settings.onSearch);
305
+ } else if (module.has.minCharacters(query) && settings.onSearch.call(element, query) !== false) {
306
+ module.filter(query);
307
+ } else {
308
+ module.hide(null, true);
309
+ }
310
+ },
311
+
312
+ select: {
313
+ firstUnfiltered: function () {
314
+ module.verbose('Selecting first non-filtered element');
315
+ module.remove.selectedItem();
316
+ $item
317
+ .not(selector.unselectable)
318
+ .not(selector.addition + selector.hidden)
319
+ .eq(0)
320
+ .addClass(className.selected)
321
+ ;
322
+ },
323
+ nextAvailable: function ($selected) {
324
+ $selected = $selected.eq(0);
325
+ var
326
+ $nextAvailable = $selected.nextAll(selector.item).not(selector.unselectable).eq(0),
327
+ $prevAvailable = $selected.prevAll(selector.item).not(selector.unselectable).eq(0),
328
+ hasNext = $nextAvailable.length > 0
329
+ ;
330
+ if (hasNext) {
331
+ module.verbose('Moving selection to', $nextAvailable);
332
+ $nextAvailable.addClass(className.selected);
333
+ } else {
334
+ module.verbose('Moving selection to', $prevAvailable);
335
+ $prevAvailable.addClass(className.selected);
336
+ }
337
+ },
338
+ },
339
+
340
+ setup: {
341
+ api: function () {
342
+ var
343
+ apiSettings = {
344
+ debug: settings.debug,
345
+ urlData: {
346
+ value: module.get.value(),
347
+ query: module.get.query(),
348
+ },
349
+ on: false,
350
+ }
351
+ ;
352
+ module.verbose('First request, initializing API');
353
+ $module
354
+ .api(apiSettings)
355
+ ;
356
+ },
357
+ layout: function () {
358
+ if ($module.is('select')) {
359
+ module.setup.select();
360
+ module.setup.returnedObject();
361
+ }
362
+ if (!module.has.menu()) {
363
+ module.create.menu();
364
+ }
365
+ if (module.is.clearable() && !module.has.clearItem()) {
366
+ module.verbose('Adding clear icon');
367
+ $clear = $('<i />')
368
+ .addClass('remove icon')
369
+ .insertAfter($icon)
370
+ ;
371
+ }
372
+ if (module.is.search() && !module.has.search()) {
373
+ module.verbose('Adding search input');
374
+ var
375
+ labelNode = $module.prev('label')
376
+ ;
377
+ $search = $('<input />')
378
+ .addClass(className.search)
379
+ .prop('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
380
+ ;
381
+ if (labelNode.length > 0) {
382
+ if (!labelNode.attr('id')) {
383
+ labelNode.attr('id', '_' + module.get.id() + '_formLabel');
384
+ }
385
+ $search.attr('aria-labelledby', labelNode.attr('id'));
386
+ }
387
+ $search.insertBefore($text);
388
+ }
389
+ if (module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
390
+ module.create.sizer();
391
+ }
392
+ if (settings.allowTab) {
393
+ module.set.tabbable();
394
+ }
395
+ },
396
+ select: function () {
397
+ var
398
+ selectValues = module.get.selectValues()
399
+ ;
400
+ module.debug('Dropdown initialized on a select', selectValues);
401
+ if ($module.is('select')) {
402
+ $input = $module;
403
+ }
404
+ // see if select is placed correctly already
405
+ if ($input.parent(selector.dropdown).length > 0) {
406
+ module.debug('UI dropdown already exists. Creating dropdown menu only');
407
+ $module = $input.closest(selector.dropdown);
408
+ if (!module.has.menu()) {
409
+ module.create.menu();
410
+ }
411
+ $menu = $module.children(selector.menu);
412
+ module.setup.menu(selectValues);
413
+ } else {
414
+ module.debug('Creating entire dropdown from select');
415
+ $module = $('<div />')
416
+ .attr('class', $input.attr('class'))
417
+ .addClass(className.selection)
418
+ .addClass(className.dropdown)
419
+ .html(templates.dropdown(selectValues, fields, settings.preserveHTML, settings.className))
420
+ .insertBefore($input)
421
+ ;
422
+ if ($input.hasClass(className.multiple) && $input.prop('multiple') === false) {
423
+ module.error(error.missingMultiple);
424
+ $input.prop('multiple', true);
425
+ }
426
+ if ($input.is('[multiple]')) {
427
+ module.set.multiple();
428
+ }
429
+ if ($input.prop('disabled')) {
430
+ module.debug('Disabling dropdown');
431
+ $module.addClass(className.disabled);
432
+ }
433
+ if ($input.is('[required]')) {
434
+ settings.forceSelection = true;
435
+ }
436
+ if (!settings.allowTab) {
437
+ $input.removeAttr('tabindex');
438
+ }
439
+ $input
440
+ .prop('required', false)
441
+ .removeAttr('class')
442
+ .detach()
443
+ .prependTo($module)
444
+ ;
445
+ }
446
+ module.refresh();
447
+ },
448
+ menu: function (values) {
449
+ $menu.html(templates.menu(values, fields, settings.preserveHTML, settings.className));
450
+ $item = $menu.find(selector.item);
451
+ $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
452
+ },
453
+ reference: function () {
454
+ module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
455
+ // replace module reference
456
+ $module = $module.parent(selector.dropdown);
457
+ instance = $module.data(moduleNamespace);
458
+ element = $module[0];
459
+ module.refresh();
460
+ module.setup.returnedObject();
461
+ },
462
+ returnedObject: function () {
463
+ var
464
+ $firstModules = $allModules.slice(0, elementIndex),
465
+ $lastModules = $allModules.slice(elementIndex + 1)
466
+ ;
467
+ // adjust all modules to use correct reference
468
+ $allModules = $firstModules.add($module).add($lastModules);
469
+ },
470
+ },
471
+
472
+ refresh: function () {
473
+ module.refreshSelectors();
474
+ module.refreshData();
475
+ },
476
+
477
+ refreshItems: function () {
478
+ $item = $menu.find(selector.item);
479
+ $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
480
+ },
481
+
482
+ refreshSelectors: function () {
483
+ module.verbose('Refreshing selector cache');
484
+ $text = $module.find(selector.text);
485
+ $search = $module.find(selector.search);
486
+ $input = $module.find(selector.input);
487
+ $icon = $module.find(selector.icon);
488
+ $combo = $module.prev().find(selector.text).length > 0
489
+ ? $module.prev().find(selector.text)
490
+ : $module.prev();
491
+ $menu = $module.children(selector.menu);
492
+ $item = $menu.find(selector.item);
493
+ $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
494
+ },
495
+
496
+ refreshData: function () {
497
+ module.verbose('Refreshing cached metadata');
498
+ $item
499
+ .removeData(metadata.text)
500
+ .removeData(metadata.value)
501
+ ;
502
+ },
503
+
504
+ clearData: function () {
505
+ module.verbose('Clearing metadata');
506
+ $item
507
+ .removeData(metadata.text)
508
+ .removeData(metadata.value)
509
+ ;
510
+ $module
511
+ .removeData(metadata.defaultText)
512
+ .removeData(metadata.defaultValue)
513
+ .removeData(metadata.placeholderText)
514
+ ;
515
+ },
516
+
517
+ clearItems: function () {
518
+ $menu.empty();
519
+ module.refreshItems();
520
+ },
521
+
522
+ toggle: function () {
523
+ module.verbose('Toggling menu visibility');
524
+ if (!module.is.active()) {
525
+ module.show();
526
+ } else {
527
+ module.hide();
528
+ }
529
+ },
530
+
531
+ show: function (callback, preventFocus) {
532
+ callback = isFunction(callback)
533
+ ? callback
534
+ : function () {};
535
+ if ((focused || iconClicked) && module.is.remote() && module.is.noApiCache() && !module.has.maxSelections()) {
536
+ module.clearItems();
537
+ }
538
+ if (!module.can.show() && module.is.remote()) {
539
+ module.debug('No API results retrieved, searching before show');
540
+ module.queryRemote(module.get.query(), module.show, [callback, preventFocus]);
541
+ }
542
+ if (module.can.show() && !module.is.active()) {
543
+ module.debug('Showing dropdown');
544
+ if (module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered())) {
545
+ module.remove.message();
546
+ }
547
+ if (module.is.allFiltered()) {
548
+ return true;
549
+ }
550
+ if (settings.onShow.call(element) !== false) {
551
+ module.remove.empty();
552
+ module.animate.show(function () {
553
+ module.bind.intent();
554
+ if (module.has.search() && !preventFocus) {
555
+ module.focusSearch();
556
+ }
557
+ module.set.visible();
558
+ callback.call(element);
559
+ });
560
+ }
561
+ }
562
+ },
563
+
564
+ hide: function (callback, preventBlur) {
565
+ callback = isFunction(callback)
566
+ ? callback
567
+ : function () {};
568
+ if (module.is.active() && !module.is.animatingOutward()) {
569
+ module.debug('Hiding dropdown');
570
+ if (settings.onHide.call(element) !== false) {
571
+ module.animate.hide(function () {
572
+ module.remove.visible();
573
+ // hiding search focus
574
+ if (module.is.focusedOnSearch() && preventBlur !== true) {
575
+ $search.trigger('blur');
576
+ }
577
+ callback.call(element);
578
+ });
579
+ // Hide submenus explicitly. On some browsers (esp. mobile), they will not automatically receive a
580
+ // mouseleave event
581
+ var $subMenu = $module.find(selector.menu);
582
+ if ($subMenu.length > 0) {
583
+ module.verbose('Hiding sub-menu', $subMenu);
584
+ $subMenu.each(function () {
585
+ var $sub = $(this);
586
+ if (!module.is.animating($sub)) {
587
+ module.animate.hide(false, $sub);
588
+ }
589
+ });
590
+ }
591
+ }
592
+ } else {
593
+ module.unbind.intent();
594
+ }
595
+ iconClicked = false;
596
+ focused = false;
597
+ },
598
+
599
+ hideOthers: function () {
600
+ module.verbose('Finding other dropdowns to hide');
601
+ $allModules
602
+ .not($module)
603
+ .has(selector.menu + '.' + className.visible)
604
+ .dropdown('hide')
605
+ ;
606
+ },
607
+
608
+ hideMenu: function () {
609
+ module.verbose('Hiding menu instantaneously');
610
+ module.remove.active();
611
+ module.remove.visible();
612
+ $menu.transition('destroy').transition('hide');
613
+ },
614
+
615
+ hideSubMenus: function () {
616
+ var
617
+ $subMenus = $menu.children(selector.item).find(selector.menu)
618
+ ;
619
+ module.verbose('Hiding sub menus', $subMenus);
620
+ $subMenus.transition('hide');
621
+ },
622
+
623
+ bind: {
624
+ events: function () {
625
+ module.bind.keyboardEvents();
626
+ module.bind.inputEvents();
627
+ module.bind.mouseEvents();
628
+ },
629
+ keyboardEvents: function () {
630
+ module.verbose('Binding keyboard events');
631
+ $module
632
+ .on('keydown' + eventNamespace, module.event.keydown)
633
+ ;
634
+ if (module.has.search()) {
635
+ $module
636
+ .on(module.get.inputEvent() + eventNamespace, selector.search, module.event.input)
637
+ ;
638
+ }
639
+ if (module.is.multiple()) {
640
+ $document
641
+ .on('keydown' + elementNamespace, module.event.document.keydown)
642
+ ;
643
+ }
644
+ },
645
+ inputEvents: function () {
646
+ module.verbose('Binding input change events');
647
+ $module
648
+ .on('change' + eventNamespace, selector.input, module.event.change)
649
+ ;
650
+ if (module.is.multiple() && module.is.searchSelection()) {
651
+ $module
652
+ .on('paste' + eventNamespace, selector.search, module.event.paste)
653
+ ;
654
+ }
655
+ },
656
+ mouseEvents: function () {
657
+ module.verbose('Binding mouse events');
658
+ if (module.is.multiple()) {
659
+ $module
660
+ .on('click' + eventNamespace, selector.label, module.event.label.click)
661
+ .on('click' + eventNamespace, selector.remove, module.event.remove.click)
662
+ ;
663
+ }
664
+ if (module.is.searchSelection()) {
665
+ $module
666
+ .on('mousedown' + eventNamespace, module.event.mousedown)
667
+ .on('mouseup' + eventNamespace, module.event.mouseup)
668
+ .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
669
+ .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
670
+ .on('click' + eventNamespace, selector.icon, module.event.icon.click)
671
+ .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
672
+ .on('focus' + eventNamespace, selector.search, module.event.search.focus)
673
+ .on('click' + eventNamespace, selector.search, module.event.search.focus)
674
+ .on('blur' + eventNamespace, selector.search, module.event.search.blur)
675
+ .on('click' + eventNamespace, selector.text, module.event.text.focus)
676
+ ;
677
+ if (module.is.multiple()) {
678
+ $module
679
+ .on('click' + eventNamespace, module.event.click)
680
+ .on('click' + eventNamespace, module.event.search.focus)
681
+ ;
682
+ }
683
+ } else {
684
+ if (settings.on === 'click') {
685
+ $module
686
+ .on('click' + eventNamespace, selector.icon, module.event.icon.click)
687
+ .on('click' + eventNamespace, module.event.test.toggle)
688
+ ;
689
+ } else if (settings.on === 'hover') {
690
+ $module
691
+ .on('mouseenter' + eventNamespace, module.delay.show)
692
+ .on('mouseleave' + eventNamespace, module.delay.hide)
693
+ .on('touchstart' + eventNamespace, module.event.test.toggle)
694
+ .on('touchstart' + eventNamespace, selector.icon, module.event.icon.click)
695
+ ;
696
+ } else {
697
+ $module
698
+ .on(settings.on + eventNamespace, module.toggle)
699
+ ;
700
+ }
701
+ $module
702
+ .on('mousedown' + eventNamespace, module.event.mousedown)
703
+ .on('mouseup' + eventNamespace, module.event.mouseup)
704
+ .on('focus' + eventNamespace, module.event.focus)
705
+ .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
706
+ ;
707
+ if (module.has.menuSearch()) {
708
+ $module
709
+ .on('blur' + eventNamespace, selector.search, module.event.search.blur)
710
+ ;
711
+ } else {
712
+ $module
713
+ .on('blur' + eventNamespace, module.event.blur)
714
+ ;
715
+ }
716
+ }
717
+ $menu
718
+ .on('mouseenter' + eventNamespace, selector.item, module.event.item.mouseenter)
719
+ .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
720
+ .on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
721
+ .on('click' + eventNamespace, selector.item, module.event.item.click)
722
+ ;
723
+ },
724
+ intent: function () {
725
+ module.verbose('Binding hide intent event to document');
726
+ $document
727
+ .on('click' + elementNamespace, module.event.test.hide)
728
+ ;
729
+ },
730
+ },
731
+
732
+ unbind: {
733
+ intent: function () {
734
+ module.verbose('Removing hide intent event from document');
735
+ $document
736
+ .off('click' + elementNamespace)
737
+ ;
738
+ },
739
+ },
740
+
741
+ filter: function (query) {
742
+ var
743
+ searchTerm = query !== undefined
744
+ ? query
745
+ : module.get.query(),
746
+ afterFiltered = function () {
747
+ if (module.is.multiple()) {
748
+ module.filterActive();
749
+ }
750
+ if (query || (!query && module.get.activeItem().length === 0)) {
751
+ module.select.firstUnfiltered();
752
+ }
753
+ if (module.has.allResultsFiltered()) {
754
+ if (settings.onNoResults.call(element, searchTerm)) {
755
+ if (settings.allowAdditions) {
756
+ if (settings.hideAdditions) {
757
+ module.verbose('User addition with no menu, setting empty style');
758
+ module.set.empty();
759
+ module.hideMenu();
760
+ }
761
+ } else {
762
+ module.verbose('All items filtered, showing message', searchTerm);
763
+ module.add.message(message.noResults);
764
+ }
765
+ } else {
766
+ module.verbose('All items filtered, hiding dropdown', searchTerm);
767
+ module.set.empty();
768
+ module.hideMenu();
769
+ }
770
+ } else {
771
+ module.remove.empty();
772
+ module.remove.message();
773
+ }
774
+ if (settings.allowAdditions) {
775
+ module.add.userSuggestion(module.escape.htmlEntities(query));
776
+ }
777
+ if (module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() && !module.is.empty()) {
778
+ module.show();
779
+ }
780
+ }
781
+ ;
782
+ if (settings.useLabels && module.has.maxSelections()) {
783
+ module.show();
784
+
785
+ return;
786
+ }
787
+ if (settings.apiSettings) {
788
+ if (module.can.useAPI()) {
789
+ module.queryRemote(searchTerm, function () {
790
+ if (settings.filterRemoteData) {
791
+ module.filterItems(searchTerm);
792
+ }
793
+ var preSelected = $input.val();
794
+ if (!Array.isArray(preSelected)) {
795
+ preSelected = preSelected && preSelected !== '' ? preSelected.split(settings.delimiter) : [];
796
+ }
797
+ if (module.is.multiple()) {
798
+ $.each(preSelected, function (index, value) {
799
+ $item.filter('[data-' + metadata.value + '="' + value + '"]')
800
+ .addClass(className.filtered)
801
+ ;
802
+ });
803
+ }
804
+ module.focusSearch(true);
805
+ afterFiltered();
806
+ });
807
+ } else {
808
+ module.error(error.noAPI);
809
+ }
810
+ } else {
811
+ module.filterItems(searchTerm);
812
+ afterFiltered();
813
+ }
814
+ },
815
+
816
+ queryRemote: function (query, callback, callbackParameters) {
817
+ if (!Array.isArray(callbackParameters)) {
818
+ callbackParameters = [callbackParameters];
819
+ }
820
+ var
821
+ apiSettings = {
822
+ errorDuration: false,
823
+ cache: 'local',
824
+ throttle: settings.throttle,
825
+ urlData: {
826
+ query: query,
827
+ },
828
+ },
829
+ apiCallbacks = {
830
+ onError: function (errorMessage, $module, xhr) {
831
+ module.add.message(message.serverError);
832
+ iconClicked = false;
833
+ focused = false;
834
+ callback.apply(null, callbackParameters);
835
+ if (typeof settings.apiSettings.onError === 'function') {
836
+ settings.apiSettings.onError.call(this, errorMessage, $module, xhr);
837
+ }
838
+ },
839
+ onFailure: function (response, $module, xhr) {
840
+ module.add.message(message.serverError);
841
+ iconClicked = false;
842
+ focused = false;
843
+ callback.apply(null, callbackParameters);
844
+ if (typeof settings.apiSettings.onFailure === 'function') {
845
+ settings.apiSettings.onFailure.call(this, response, $module, xhr);
846
+ }
847
+ },
848
+ onSuccess: function (response, $module, xhr) {
849
+ var
850
+ values = response[fields.remoteValues]
851
+ ;
852
+ if (!Array.isArray(values)) {
853
+ values = [];
854
+ }
855
+ module.remove.message();
856
+ var menuConfig = {};
857
+ menuConfig[fields.values] = values;
858
+ module.setup.menu(menuConfig);
859
+
860
+ if (values.length === 0 && !settings.allowAdditions) {
861
+ module.add.message(message.noResults);
862
+ } else {
863
+ var value = module.is.multiple() ? module.get.values() : module.get.value();
864
+ if (value !== '') {
865
+ module.verbose('Value(s) present after click icon, select value(s) in items');
866
+ module.set.selected(value, null, true, true);
867
+ }
868
+ }
869
+ iconClicked = false;
870
+ focused = false;
871
+ callback.apply(null, callbackParameters);
872
+ if (typeof settings.apiSettings.onSuccess === 'function') {
873
+ settings.apiSettings.onSuccess.call(this, response, $module, xhr);
874
+ }
875
+ },
876
+ }
877
+ ;
878
+ if (!$module.api('get request')) {
879
+ module.setup.api();
880
+ }
881
+ apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings, apiCallbacks, tempDisableApiCache ? { cache: false } : {});
882
+ $module
883
+ .api('setting', apiSettings)
884
+ .api('query')
885
+ ;
886
+ tempDisableApiCache = false;
887
+ },
888
+
889
+ filterItems: function (query) {
890
+ var
891
+ searchTerm = module.remove.diacritics(
892
+ query !== undefined
893
+ ? query
894
+ : module.get.query()
895
+ ),
896
+ results = null,
897
+ escapedTerm = module.escape.string(searchTerm),
898
+ regExpIgnore = settings.ignoreSearchCase ? 'i' : '',
899
+ regExpFlags = regExpIgnore + 'gm',
900
+ beginsWithRegExp = new RegExp('^' + escapedTerm, regExpFlags)
901
+ ;
902
+ module.remove.filteredItem();
903
+ // avoid loop if we're matching nothing
904
+ if (module.has.query()) {
905
+ results = [];
906
+
907
+ module.verbose('Searching for matching values', searchTerm);
908
+ $item
909
+ .each(function () {
910
+ var
911
+ $choice = $(this),
912
+ text,
913
+ value
914
+ ;
915
+ if ($choice.hasClass(className.unfilterable)) {
916
+ results.push(this);
917
+
918
+ return true;
919
+ }
920
+ if (settings.match === 'both' || settings.match === 'text') {
921
+ text = module.remove.diacritics(String(module.get.choiceText($choice, false)));
922
+ if (text.search(beginsWithRegExp) !== -1
923
+ || (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text))
924
+ || (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text))
925
+ ) {
926
+ results.push(this);
927
+
928
+ return true;
929
+ }
930
+ }
931
+ if (settings.match === 'both' || settings.match === 'value') {
932
+ value = module.remove.diacritics(String(module.get.choiceValue($choice, text)));
933
+ if (value.search(beginsWithRegExp) !== -1
934
+ || (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value))
935
+ || (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value))
936
+ ) {
937
+ results.push(this);
938
+
939
+ return true;
940
+ }
941
+ }
942
+ })
943
+ ;
944
+ }
945
+ module.debug('Showing only matched items', searchTerm);
946
+ if (results) {
947
+ $item
948
+ .not(results)
949
+ .addClass(className.filtered)
950
+ ;
951
+ if (settings.highlightMatches && (settings.match === 'both' || settings.match === 'text')) {
952
+ var querySplit = query.split(''),
953
+ diacriticReg = settings.ignoreDiacritics ? '[\u0300-\u036F]?' : '',
954
+ htmlReg = '(?![^<]*>)',
955
+ markedRegExp = new RegExp(htmlReg + '(' + querySplit.join(diacriticReg + ')(.*?)' + htmlReg + '(') + diacriticReg + ')', regExpIgnore),
956
+ markedReplacer = function () {
957
+ var args = [].slice.call(arguments, 1, querySplit.length * 2).map(function (x, i) {
958
+ return i & 1 ? x : '<mark>' + x + '</mark>'; // eslint-disable-line no-bitwise
959
+ });
960
+
961
+ return args.join('');
962
+ }
963
+ ;
964
+ $.each(results, function (index, result) {
965
+ var $result = $(result),
966
+ markedHTML = module.get.choiceText($result, true)
967
+ ;
968
+ if (settings.ignoreDiacritics) {
969
+ markedHTML = markedHTML.normalize('NFD');
970
+ }
971
+ $result.html(markedHTML.replace(markedRegExp, markedReplacer));
972
+ });
973
+ }
974
+ }
975
+
976
+ if (!module.has.query()) {
977
+ $divider
978
+ .removeClass(className.hidden)
979
+ ;
980
+ } else if (settings.hideDividers === true) {
981
+ $divider
982
+ .addClass(className.hidden)
983
+ ;
984
+ } else if (settings.hideDividers === 'empty') {
985
+ $divider
986
+ .removeClass(className.hidden)
987
+ .filter(function () {
988
+ // First find the last divider in this divider group
989
+ // Dividers which are direct siblings are considered a group
990
+ var $lastDivider = $(this).nextUntil(selector.item);
991
+
992
+ return ($lastDivider.length > 0 ? $lastDivider : $(this))
993
+ // Count all non-filtered items until the next divider (or end of the dropdown)
994
+ .nextUntil(selector.divider)
995
+ .filter(selector.item + ':not(.' + className.filtered + ')')
996
+ // Hide divider if no items are found
997
+ .length === 0;
998
+ })
999
+ .addClass(className.hidden)
1000
+ ;
1001
+ }
1002
+ },
1003
+
1004
+ fuzzySearch: function (query, term) {
1005
+ var
1006
+ termLength = term.length,
1007
+ queryLength = query.length
1008
+ ;
1009
+ if (settings.ignoreSearchCase) {
1010
+ query = query.toLowerCase();
1011
+ term = term.toLowerCase();
1012
+ }
1013
+ if (queryLength > termLength) {
1014
+ return false;
1015
+ }
1016
+ if (queryLength === termLength) {
1017
+ return query === term;
1018
+ }
1019
+ for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
1020
+ var
1021
+ continueSearch = false,
1022
+ queryCharacter = query.charCodeAt(characterIndex)
1023
+ ;
1024
+ while (nextCharacterIndex < termLength) {
1025
+ if (term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
1026
+ continueSearch = true;
1027
+
1028
+ break;
1029
+ }
1030
+ }
1031
+
1032
+ if (!continueSearch) {
1033
+ return false;
1034
+ }
1035
+ }
1036
+
1037
+ return true;
1038
+ },
1039
+ exactSearch: function (query, term) {
1040
+ query = settings.ignoreSearchCase ? query.toLowerCase() : query;
1041
+ term = settings.ignoreSearchCase ? term.toLowerCase() : term;
1042
+
1043
+ return term.indexOf(query) > -1;
1044
+ },
1045
+ filterActive: function () {
1046
+ if (settings.useLabels) {
1047
+ $item.filter('.' + className.active)
1048
+ .addClass(className.filtered)
1049
+ ;
1050
+ }
1051
+ },
1052
+
1053
+ focusSearch: function (skipHandler) {
1054
+ if (module.has.search() && !module.is.focusedOnSearch()) {
1055
+ if (skipHandler) {
1056
+ $module.off('focus' + eventNamespace, selector.search);
1057
+ $search.trigger('focus');
1058
+ $module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
1059
+ } else {
1060
+ $search.trigger('focus');
1061
+ }
1062
+ }
1063
+ },
1064
+
1065
+ blurSearch: function () {
1066
+ if (module.has.search()) {
1067
+ $search.trigger('blur');
1068
+ }
1069
+ },
1070
+
1071
+ forceSelection: function () {
1072
+ var
1073
+ $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
1074
+ $activeItem = $item.not(className.filtered).filter('.' + className.active).eq(0),
1075
+ $selectedItem = $currentlySelected.length > 0
1076
+ ? $currentlySelected
1077
+ : $activeItem,
1078
+ hasSelected = $selectedItem.length > 0
1079
+ ;
1080
+ if (settings.allowAdditions || (hasSelected && !module.is.multiple())) {
1081
+ module.debug('Forcing partial selection to selected item', $selectedItem);
1082
+ module.event.item.click.call($selectedItem, {}, true);
1083
+ } else {
1084
+ module.remove.searchTerm();
1085
+ }
1086
+ },
1087
+
1088
+ change: {
1089
+ values: function (values) {
1090
+ if (!settings.allowAdditions) {
1091
+ module.clear();
1092
+ }
1093
+ module.debug('Creating dropdown with specified values', values);
1094
+ var menuConfig = {};
1095
+ menuConfig[fields.values] = values;
1096
+ module.setup.menu(menuConfig);
1097
+ $.each(values, function (index, item) {
1098
+ if (item.selected === true) {
1099
+ module.debug('Setting initial selection to', item[fields.value]);
1100
+ module.set.selected(item[fields.value]);
1101
+ if (!module.is.multiple()) {
1102
+ return false;
1103
+ }
1104
+ }
1105
+ });
1106
+
1107
+ if (module.has.selectInput()) {
1108
+ module.disconnect.selectObserver();
1109
+ $input.html('');
1110
+ $input.append('<option disabled selected value></option>');
1111
+ $.each(values, function (index, item) {
1112
+ var
1113
+ value = settings.templates.deQuote(item[fields.value]),
1114
+ name = settings.templates.escape(
1115
+ item[fields.name] || '',
1116
+ settings.preserveHTML
1117
+ )
1118
+ ;
1119
+ $input.append('<option value="' + value + '"' + (item.selected === true ? ' selected' : '') + '>' + name + '</option>');
1120
+ });
1121
+ module.observe.select();
1122
+ }
1123
+ },
1124
+ },
1125
+
1126
+ event: {
1127
+ paste: function (event) {
1128
+ var
1129
+ pasteValue = (event.originalEvent.clipboardData || window.clipboardData).getData('text'),
1130
+ tokens = pasteValue.split(settings.delimiter),
1131
+ notFoundTokens = []
1132
+ ;
1133
+ tokens.forEach(function (value) {
1134
+ if (module.set.selected(module.escape.htmlEntities(value.trim()), null, false, true) === false) {
1135
+ notFoundTokens.push(value.trim());
1136
+ }
1137
+ });
1138
+ event.preventDefault();
1139
+ if (notFoundTokens.length > 0) {
1140
+ var searchEl = $search[0],
1141
+ startPos = searchEl.selectionStart,
1142
+ endPos = searchEl.selectionEnd,
1143
+ orgText = searchEl.value,
1144
+ pasteText = notFoundTokens.join(settings.delimiter),
1145
+ newEndPos = startPos + pasteText.length
1146
+ ;
1147
+ $search.val(orgText.slice(0, startPos) + pasteText + orgText.slice(endPos));
1148
+ searchEl.selectionStart = newEndPos;
1149
+ searchEl.selectionEnd = newEndPos;
1150
+ module.event.input(event);
1151
+ }
1152
+ },
1153
+ change: function () {
1154
+ if (!internalChange) {
1155
+ module.debug('Input changed, updating selection');
1156
+ module.set.selected();
1157
+ }
1158
+ },
1159
+ focus: function () {
1160
+ if (settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
1161
+ focused = true;
1162
+ module.show();
1163
+ }
1164
+ },
1165
+ blur: function (event) {
1166
+ pageLostFocus = document.activeElement === this;
1167
+ if (!activated && !pageLostFocus) {
1168
+ module.remove.activeLabel();
1169
+ module.hide();
1170
+ }
1171
+ },
1172
+ mousedown: function () {
1173
+ if (module.is.searchSelection(true)) {
1174
+ // prevent menu hiding on immediate re-focus
1175
+ willRefocus = true;
1176
+ } else {
1177
+ // prevents focus callback from occurring on mousedown
1178
+ activated = true;
1179
+ }
1180
+ },
1181
+ mouseup: function () {
1182
+ if (module.is.searchSelection(true)) {
1183
+ // prevent menu hiding on immediate re-focus
1184
+ willRefocus = false;
1185
+ } else {
1186
+ activated = false;
1187
+ }
1188
+ },
1189
+ click: function (event) {
1190
+ var
1191
+ $target = $(event.target)
1192
+ ;
1193
+ // focus search
1194
+ if ($target.is($module)) {
1195
+ if (!module.is.focusedOnSearch()) {
1196
+ module.focusSearch();
1197
+ } else {
1198
+ module.show();
1199
+ }
1200
+ }
1201
+ },
1202
+ search: {
1203
+ focus: function (event) {
1204
+ activated = true;
1205
+ if (module.is.multiple()) {
1206
+ module.remove.activeLabel();
1207
+ }
1208
+ if (!focused && !module.is.active() && (settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin')) && event.type !== 'touchstart') {
1209
+ focused = true;
1210
+ module.search();
1211
+ }
1212
+ },
1213
+ blur: function (event) {
1214
+ pageLostFocus = document.activeElement === this;
1215
+ if (module.is.searchSelection(true) && !willRefocus) {
1216
+ if (!itemActivated && !pageLostFocus) {
1217
+ if (settings.forceSelection) {
1218
+ module.forceSelection();
1219
+ } else if (!settings.allowAdditions && !settings.keepSearchTerm && !module.has.menuSearch()) {
1220
+ module.remove.searchTerm();
1221
+ }
1222
+ module.hide();
1223
+ }
1224
+ }
1225
+ willRefocus = false;
1226
+ },
1227
+ },
1228
+ clearIcon: {
1229
+ click: function (event) {
1230
+ module.clear();
1231
+ if (module.is.searchSelection()) {
1232
+ module.remove.searchTerm();
1233
+ }
1234
+ if (settings.collapseOnClearable) {
1235
+ module.hide();
1236
+ }
1237
+ event.stopPropagation();
1238
+ },
1239
+ },
1240
+ icon: {
1241
+ click: function (event) {
1242
+ iconClicked = true;
1243
+ if (module.has.search()) {
1244
+ if (!module.is.active()) {
1245
+ if (settings.showOnFocus) {
1246
+ module.focusSearch();
1247
+ } else {
1248
+ module.toggle();
1249
+ }
1250
+ } else {
1251
+ module.blurSearch();
1252
+ }
1253
+ } else {
1254
+ module.toggle();
1255
+ }
1256
+ event.stopPropagation();
1257
+ },
1258
+ },
1259
+ text: {
1260
+ focus: function (event) {
1261
+ activated = true;
1262
+ module.focusSearch();
1263
+ },
1264
+ },
1265
+ input: function (event) {
1266
+ if (module.is.multiple() || module.is.searchSelection()) {
1267
+ module.set.filtered();
1268
+ }
1269
+ clearTimeout(module.timer);
1270
+ module.timer = setTimeout(function () {
1271
+ module.search();
1272
+ }, settings.delay.search);
1273
+ },
1274
+ label: {
1275
+ click: function (event) {
1276
+ var
1277
+ $label = $(this),
1278
+ $labels = $module.find(selector.label),
1279
+ $activeLabels = $labels.filter('.' + className.active),
1280
+ $nextActive = $label.nextAll('.' + className.active),
1281
+ $prevActive = $label.prevAll('.' + className.active),
1282
+ $range = $nextActive.length > 0
1283
+ ? $label.nextUntil($nextActive).add($activeLabels).add($label)
1284
+ : $label.prevUntil($prevActive).add($activeLabels).add($label)
1285
+ ;
1286
+ if (event.shiftKey) {
1287
+ $activeLabels.removeClass(className.active);
1288
+ $range.addClass(className.active);
1289
+ } else if (event.ctrlKey) {
1290
+ $label.toggleClass(className.active);
1291
+ } else {
1292
+ $activeLabels.removeClass(className.active);
1293
+ $label.addClass(className.active);
1294
+ }
1295
+ settings.onLabelSelect.apply(this, $labels.filter('.' + className.active));
1296
+ event.stopPropagation();
1297
+ },
1298
+ },
1299
+ remove: {
1300
+ click: function (event) {
1301
+ var
1302
+ $label = $(this).parent()
1303
+ ;
1304
+ if ($label.hasClass(className.active)) {
1305
+ // remove all selected labels
1306
+ module.remove.activeLabels();
1307
+ } else {
1308
+ // remove this label only
1309
+ module.remove.activeLabels($label);
1310
+ }
1311
+ event.stopPropagation();
1312
+ },
1313
+ },
1314
+ test: {
1315
+ toggle: function (event) {
1316
+ var
1317
+ toggleBehavior = module.is.multiple()
1318
+ ? module.show
1319
+ : module.toggle
1320
+ ;
1321
+ if (module.is.bubbledLabelClick(event) || module.is.bubbledIconClick(event)) {
1322
+ return;
1323
+ }
1324
+ if (!module.is.multiple() || (module.is.multiple() && !module.is.active())) {
1325
+ focused = true;
1326
+ }
1327
+ if (module.determine.eventOnElement(event, toggleBehavior) && event.type !== 'touchstart') {
1328
+ // do not preventDefault of touchstart; so emulated mouseenter is triggered on first touch and not later
1329
+ // (when selecting an item). The double-showing of the dropdown through both events does not hurt.
1330
+ event.preventDefault();
1331
+ }
1332
+ },
1333
+ hide: function (event) {
1334
+ if (module.determine.eventInModule(event, module.hide)) {
1335
+ if (element.id && $(event.target).attr('for') === element.id) {
1336
+ event.preventDefault();
1337
+ }
1338
+ }
1339
+ },
1340
+ },
1341
+ class: {
1342
+ mutation: function (mutations) {
1343
+ mutations.forEach(function (mutation) {
1344
+ if (mutation.attributeName === 'class') {
1345
+ module.check.disabled();
1346
+ }
1347
+ });
1348
+ },
1349
+ },
1350
+ select: {
1351
+ mutation: function (mutations) {
1352
+ if (module.is.selectMutation(mutations)) {
1353
+ module.debug('<select> modified, recreating menu');
1354
+ module.disconnect.selectObserver();
1355
+ module.refresh();
1356
+ module.setup.select();
1357
+ module.set.selected();
1358
+ module.observe.select();
1359
+ }
1360
+ },
1361
+ },
1362
+ menu: {
1363
+ mutation: function (mutations) {
1364
+ var
1365
+ mutation = mutations[0],
1366
+ $addedNode = mutation.addedNodes
1367
+ ? $(mutation.addedNodes[0])
1368
+ : $(false),
1369
+ $removedNode = mutation.removedNodes
1370
+ ? $(mutation.removedNodes[0])
1371
+ : $(false),
1372
+ $changedNodes = $addedNode.add($removedNode),
1373
+ isUserAddition = $changedNodes.is(selector.addition) || $changedNodes.closest(selector.addition).length > 0,
1374
+ isMessage = $changedNodes.is(selector.message) || $changedNodes.closest(selector.message).length > 0
1375
+ ;
1376
+ if (isUserAddition || isMessage) {
1377
+ module.debug('Updating item selector cache');
1378
+ module.refreshItems();
1379
+ } else {
1380
+ module.debug('Menu modified, updating selector cache');
1381
+ module.refresh();
1382
+ }
1383
+ },
1384
+ mousedown: function () {
1385
+ itemActivated = true;
1386
+ },
1387
+ mouseup: function () {
1388
+ itemActivated = false;
1389
+ },
1390
+ },
1391
+ item: {
1392
+ mouseenter: function (event) {
1393
+ var
1394
+ $target = $(event.target),
1395
+ $item = $(this),
1396
+ $subMenu = $item.children(selector.menu),
1397
+ $otherMenus = $item.siblings(selector.item).children(selector.menu),
1398
+ hasSubMenu = $subMenu.length > 0,
1399
+ isBubbledEvent = $subMenu.find($target).length > 0
1400
+ ;
1401
+ if (!isBubbledEvent && hasSubMenu) {
1402
+ clearTimeout(module.itemTimer);
1403
+ module.itemTimer = setTimeout(function () {
1404
+ module.verbose('Showing sub-menu', $subMenu);
1405
+ $.each($otherMenus, function () {
1406
+ module.animate.hide(false, $(this));
1407
+ });
1408
+ module.animate.show(false, $subMenu);
1409
+ }, settings.delay.show);
1410
+ event.preventDefault();
1411
+ }
1412
+ },
1413
+ mouseleave: function (event) {
1414
+ var
1415
+ $subMenu = $(this).find(selector.menu)
1416
+ ;
1417
+ if ($subMenu.length > 0) {
1418
+ clearTimeout(module.itemTimer);
1419
+ module.itemTimer = setTimeout(function () {
1420
+ module.verbose('Hiding sub-menu', $subMenu);
1421
+ $subMenu.each(function () {
1422
+ module.animate.hide(false, $(this));
1423
+ });
1424
+ }, settings.delay.hide);
1425
+ }
1426
+ },
1427
+ click: function (event, skipRefocus) {
1428
+ var
1429
+ $choice = $(this),
1430
+ $target = event
1431
+ ? $(event.target || '')
1432
+ : $(''),
1433
+ $subMenu = $choice.find(selector.menu),
1434
+ text = module.get.choiceText($choice),
1435
+ value = module.get.choiceValue($choice, text),
1436
+ hasSubMenu = $subMenu.length > 0,
1437
+ isBubbledEvent = $subMenu.find($target).length > 0
1438
+ ;
1439
+ // prevents IE11 bug where menu receives focus even though `tabindex=-1`
1440
+ if (document.activeElement.tagName.toLowerCase() !== 'input') {
1441
+ $(document.activeElement).trigger('blur');
1442
+ }
1443
+ if (!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
1444
+ if (module.is.searchSelection()) {
1445
+ if (settings.allowAdditions) {
1446
+ module.remove.userAddition();
1447
+ }
1448
+ if (!settings.keepSearchTerm) {
1449
+ if (module.is.multiple()) {
1450
+ module.remove.filteredItem();
1451
+ }
1452
+ module.remove.searchTerm();
1453
+ }
1454
+ if (!module.is.visible() && $target.length > 0) {
1455
+ module.show();
1456
+ }
1457
+ if (!module.is.focusedOnSearch() && skipRefocus !== true) {
1458
+ module.focusSearch(true);
1459
+ }
1460
+ }
1461
+ if (!settings.useLabels) {
1462
+ module.remove.filteredItem();
1463
+ module.set.scrollPosition($choice);
1464
+ }
1465
+ module.determine.selectAction.call(this, text, value);
1466
+ }
1467
+ },
1468
+ },
1469
+
1470
+ document: {
1471
+ // label selection should occur even when element has no focus
1472
+ keydown: function (event) {
1473
+ var
1474
+ pressedKey = event.which,
1475
+ isShortcutKey = module.is.inObject(pressedKey, keys)
1476
+ ;
1477
+ if (isShortcutKey) {
1478
+ var
1479
+ $label = $module.find(selector.label),
1480
+ $activeLabel = $label.filter('.' + className.active),
1481
+ activeValue = $activeLabel.data(metadata.value),
1482
+ labelIndex = $label.index($activeLabel),
1483
+ labelCount = $label.length,
1484
+ hasActiveLabel = $activeLabel.length > 0,
1485
+ hasMultipleActive = $activeLabel.length > 1,
1486
+ isFirstLabel = labelIndex === 0,
1487
+ isLastLabel = labelIndex + 1 === labelCount,
1488
+ isSearch = module.is.searchSelection(),
1489
+ isFocusedOnSearch = module.is.focusedOnSearch(),
1490
+ isFocused = module.is.focused(),
1491
+ caretAtStart = isFocusedOnSearch && module.get.caretPosition(false) === 0,
1492
+ isSelectedSearch = caretAtStart && module.get.caretPosition(true) !== 0
1493
+ ;
1494
+ if (isSearch && !hasActiveLabel && !isFocusedOnSearch) {
1495
+ return;
1496
+ }
1497
+
1498
+ switch (pressedKey) {
1499
+ case keys.leftArrow: {
1500
+ // activate previous label
1501
+ if ((isFocused || caretAtStart) && !hasActiveLabel) {
1502
+ module.verbose('Selecting previous label');
1503
+ $label.last().addClass(className.active);
1504
+ } else if (hasActiveLabel) {
1505
+ if (!event.shiftKey) {
1506
+ module.verbose('Selecting previous label');
1507
+ $label.removeClass(className.active);
1508
+ } else {
1509
+ module.verbose('Adding previous label to selection');
1510
+ }
1511
+ if (isFirstLabel && !hasMultipleActive) {
1512
+ $activeLabel.addClass(className.active);
1513
+ } else {
1514
+ $activeLabel.prev(selector.siblingLabel)
1515
+ .addClass(className.active)
1516
+ .end()
1517
+ ;
1518
+ }
1519
+ event.preventDefault();
1520
+ }
1521
+
1522
+ break;
1523
+ }
1524
+ case keys.rightArrow: {
1525
+ // activate first label
1526
+ if (isFocused && !hasActiveLabel) {
1527
+ $label.first().addClass(className.active);
1528
+ }
1529
+ // activate next label
1530
+ if (hasActiveLabel) {
1531
+ if (!event.shiftKey) {
1532
+ module.verbose('Selecting next label');
1533
+ $label.removeClass(className.active);
1534
+ } else {
1535
+ module.verbose('Adding next label to selection');
1536
+ }
1537
+ if (isLastLabel) {
1538
+ if (isSearch) {
1539
+ if (!isFocusedOnSearch) {
1540
+ module.focusSearch();
1541
+ } else {
1542
+ $label.removeClass(className.active);
1543
+ }
1544
+ } else if (hasMultipleActive) {
1545
+ $activeLabel.next(selector.siblingLabel).addClass(className.active);
1546
+ } else {
1547
+ $activeLabel.addClass(className.active);
1548
+ }
1549
+ } else {
1550
+ $activeLabel.next(selector.siblingLabel).addClass(className.active);
1551
+ }
1552
+ event.preventDefault();
1553
+ }
1554
+
1555
+ break;
1556
+ }
1557
+ case keys.deleteKey:
1558
+ case keys.backspace: {
1559
+ if (hasActiveLabel) {
1560
+ module.verbose('Removing active labels');
1561
+ if (isLastLabel) {
1562
+ if (isSearch && !isFocusedOnSearch) {
1563
+ module.focusSearch();
1564
+ }
1565
+ }
1566
+ $activeLabel.last().next(selector.siblingLabel).addClass(className.active);
1567
+ module.remove.activeLabels($activeLabel);
1568
+ if (!module.is.visible()) {
1569
+ module.show();
1570
+ }
1571
+ event.preventDefault();
1572
+ } else if (caretAtStart && !isSelectedSearch && !hasActiveLabel && pressedKey === keys.backspace) {
1573
+ module.verbose('Removing last label on input backspace');
1574
+ $activeLabel = $label.last().addClass(className.active);
1575
+ module.remove.activeLabels($activeLabel);
1576
+ if (!module.is.visible()) {
1577
+ module.show();
1578
+ }
1579
+ }
1580
+
1581
+ break;
1582
+ }
1583
+ default: {
1584
+ $activeLabel.removeClass(className.active);
1585
+ }
1586
+ }
1587
+ }
1588
+ },
1589
+ },
1590
+
1591
+ keydown: function (event) {
1592
+ var
1593
+ pressedKey = event.which,
1594
+ isShortcutKey = module.is.inObject(pressedKey, keys) || event.key === settings.delimiter
1595
+ ;
1596
+ if (isShortcutKey) {
1597
+ var
1598
+ $currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
1599
+ $activeItem = $menu.children('.' + className.active).eq(0),
1600
+ $selectedItem = $currentlySelected.length > 0
1601
+ ? $currentlySelected
1602
+ : $activeItem,
1603
+ $visibleItems = $selectedItem.length > 0
1604
+ ? $selectedItem.siblings(':not(.' + className.filtered + ')').addBack()
1605
+ : $menu.children(':not(.' + className.filtered + ')'),
1606
+ $subMenu = $selectedItem.children(selector.menu),
1607
+ $parentMenu = $selectedItem.closest(selector.menu),
1608
+ inVisibleMenu = $parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0,
1609
+ hasSubMenu = $subMenu.length > 0,
1610
+ hasSelectedItem = $selectedItem.length > 0,
1611
+ selectedIsSelectable = $selectedItem.not(selector.unselectable).length > 0,
1612
+ delimiterPressed = event.key === settings.delimiter && module.is.multiple(),
1613
+ isAdditionWithoutMenu = settings.allowAdditions && (pressedKey === keys.enter || delimiterPressed),
1614
+ $nextItem,
1615
+ isSubMenuItem
1616
+ ;
1617
+ // allow selection with menu closed
1618
+ if (isAdditionWithoutMenu) {
1619
+ if (selectedIsSelectable && settings.hideAdditions) {
1620
+ module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1621
+ module.event.item.click.call($selectedItem, event);
1622
+ }
1623
+ if (module.is.searchSelection() && !settings.keepSearchTerm) {
1624
+ module.remove.searchTerm();
1625
+ }
1626
+ if (module.is.multiple()) {
1627
+ event.preventDefault();
1628
+ }
1629
+ }
1630
+
1631
+ // visible menu keyboard shortcuts
1632
+ if (module.is.visible()) {
1633
+ // enter (select or open sub-menu)
1634
+ if (pressedKey === keys.enter || delimiterPressed) {
1635
+ if (pressedKey === keys.enter && hasSelectedItem && hasSubMenu && !settings.allowCategorySelection) {
1636
+ module.verbose('Pressed enter on unselectable category, opening sub menu');
1637
+ pressedKey = keys.rightArrow;
1638
+ } else if (selectedIsSelectable) {
1639
+ module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1640
+ module.event.item.click.call($selectedItem, event);
1641
+ if (module.is.searchSelection()) {
1642
+ if (!settings.keepSearchTerm) {
1643
+ module.remove.searchTerm();
1644
+ }
1645
+ if (module.is.multiple()) {
1646
+ $search.trigger('focus');
1647
+ }
1648
+ }
1649
+ }
1650
+ event.preventDefault();
1651
+ }
1652
+
1653
+ // sub-menu actions
1654
+ if (hasSelectedItem) {
1655
+ if (pressedKey === keys.leftArrow) {
1656
+ isSubMenuItem = $parentMenu[0] !== $menu[0];
1657
+
1658
+ if (isSubMenuItem) {
1659
+ module.verbose('Left key pressed, closing sub-menu');
1660
+ module.animate.hide(false, $parentMenu);
1661
+ $selectedItem
1662
+ .removeClass(className.selected)
1663
+ ;
1664
+ $parentMenu
1665
+ .closest(selector.item)
1666
+ .addClass(className.selected)
1667
+ ;
1668
+ event.preventDefault();
1669
+ }
1670
+ }
1671
+
1672
+ // right arrow (show sub-menu)
1673
+ if (pressedKey === keys.rightArrow) {
1674
+ if (hasSubMenu) {
1675
+ module.verbose('Right key pressed, opening sub-menu');
1676
+ module.animate.show(false, $subMenu);
1677
+ $selectedItem
1678
+ .removeClass(className.selected)
1679
+ ;
1680
+ $subMenu
1681
+ .find(selector.item).eq(0)
1682
+ .addClass(className.selected)
1683
+ ;
1684
+ event.preventDefault();
1685
+ }
1686
+ }
1687
+ }
1688
+
1689
+ // up arrow (traverse menu up)
1690
+ if (pressedKey === keys.upArrow) {
1691
+ $nextItem = hasSelectedItem && inVisibleMenu
1692
+ ? $selectedItem.prevAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
1693
+ : $item.eq(0);
1694
+ if ($visibleItems.index($nextItem) < 0) {
1695
+ module.verbose('Up key pressed but reached top of current menu');
1696
+ event.preventDefault();
1697
+
1698
+ return;
1699
+ }
1700
+
1701
+ module.verbose('Up key pressed, changing active item');
1702
+ $selectedItem
1703
+ .removeClass(className.selected)
1704
+ ;
1705
+ $nextItem
1706
+ .addClass(className.selected)
1707
+ ;
1708
+ module.set.scrollPosition($nextItem);
1709
+ if (settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
1710
+ module.set.selectedItem($nextItem);
1711
+ }
1712
+
1713
+ event.preventDefault();
1714
+ }
1715
+
1716
+ // down arrow (traverse menu down)
1717
+ if (pressedKey === keys.downArrow) {
1718
+ $nextItem = hasSelectedItem && inVisibleMenu
1719
+ ? $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
1720
+ : $item.eq(0);
1721
+ if ($nextItem.length === 0) {
1722
+ module.verbose('Down key pressed but reached bottom of current menu');
1723
+ event.preventDefault();
1724
+
1725
+ return;
1726
+ }
1727
+
1728
+ module.verbose('Down key pressed, changing active item');
1729
+ $item
1730
+ .removeClass(className.selected)
1731
+ ;
1732
+ $nextItem
1733
+ .addClass(className.selected)
1734
+ ;
1735
+ module.set.scrollPosition($nextItem);
1736
+ if (settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
1737
+ module.set.selectedItem($nextItem);
1738
+ }
1739
+
1740
+ event.preventDefault();
1741
+ }
1742
+
1743
+ // page down (show next page)
1744
+ if (pressedKey === keys.pageUp) {
1745
+ module.scrollPage('up');
1746
+ event.preventDefault();
1747
+ }
1748
+ if (pressedKey === keys.pageDown) {
1749
+ module.scrollPage('down');
1750
+ event.preventDefault();
1751
+ }
1752
+
1753
+ // escape (close menu)
1754
+ if (pressedKey === keys.escape) {
1755
+ module.verbose('Escape key pressed, closing dropdown');
1756
+ module.hide();
1757
+ event.stopPropagation();
1758
+ }
1759
+ } else {
1760
+ // delimiter key
1761
+ if (pressedKey === keys.enter || delimiterPressed) {
1762
+ event.preventDefault();
1763
+ }
1764
+ // down arrow (open menu)
1765
+ if (pressedKey === keys.downArrow && !module.is.visible()) {
1766
+ module.verbose('Down key pressed, showing dropdown');
1767
+ module.show();
1768
+ event.preventDefault();
1769
+ }
1770
+ }
1771
+ } else {
1772
+ if (!module.has.search()) {
1773
+ module.set.selectedLetter(String.fromCharCode(pressedKey));
1774
+ }
1775
+ }
1776
+ },
1777
+ },
1778
+
1779
+ trigger: {
1780
+ change: function () {
1781
+ var
1782
+ inputElement = $input[0]
1783
+ ;
1784
+ if (inputElement) {
1785
+ var events = document.createEvent('HTMLEvents');
1786
+ module.verbose('Triggering native change event');
1787
+ events.initEvent('change', true, false);
1788
+ inputElement.dispatchEvent(events);
1789
+ }
1790
+ },
1791
+ },
1792
+
1793
+ determine: {
1794
+ selectAction: function (text, value) {
1795
+ selectActionActive = true;
1796
+ module.verbose('Determining action', settings.action);
1797
+ if (isFunction(module.action[settings.action])) {
1798
+ module.verbose('Triggering preset action', settings.action, text, value);
1799
+ module.action[settings.action].call(element, text, value, this);
1800
+ } else if (isFunction(settings.action)) {
1801
+ module.verbose('Triggering user action', settings.action, text, value);
1802
+ settings.action.call(element, text, value, this);
1803
+ } else {
1804
+ module.error(error.action, settings.action);
1805
+ }
1806
+ selectActionActive = false;
1807
+ },
1808
+ eventInModule: function (event, callback) {
1809
+ var
1810
+ $target = $(event.target),
1811
+ inDocument = $target.closest(document.documentElement).length > 0,
1812
+ inModule = $target.closest($module).length > 0
1813
+ ;
1814
+ callback = isFunction(callback)
1815
+ ? callback
1816
+ : function () {};
1817
+ if (inDocument && !inModule) {
1818
+ module.verbose('Triggering event', callback);
1819
+ callback();
1820
+
1821
+ return true;
1822
+ }
1823
+
1824
+ module.verbose('Event occurred in dropdown, canceling callback');
1825
+
1826
+ return false;
1827
+ },
1828
+ eventOnElement: function (event, callback) {
1829
+ var
1830
+ $target = $(event.target),
1831
+ $label = $target.closest(selector.siblingLabel),
1832
+ inVisibleDOM = document.body.contains(event.target),
1833
+ notOnLabel = $module.find($label).length === 0 || !(module.is.multiple() && settings.useLabels),
1834
+ notInMenu = $target.closest($menu).length === 0
1835
+ ;
1836
+ callback = isFunction(callback)
1837
+ ? callback
1838
+ : function () {};
1839
+ if (inVisibleDOM && notOnLabel && notInMenu) {
1840
+ module.verbose('Triggering event', callback);
1841
+ callback();
1842
+
1843
+ return true;
1844
+ }
1845
+
1846
+ module.verbose('Event occurred in dropdown menu, canceling callback');
1847
+
1848
+ return false;
1849
+ },
1850
+ },
1851
+
1852
+ action: {
1853
+
1854
+ nothing: function () {},
1855
+
1856
+ activate: function (text, value, element) {
1857
+ value = value !== undefined
1858
+ ? value
1859
+ : text;
1860
+ if (module.can.activate($(element))) {
1861
+ module.set.selected(value, $(element), false, settings.keepSearchTerm);
1862
+ if (!module.is.multiple() && !(!settings.collapseOnActionable && $(element).hasClass(className.actionable))) {
1863
+ module.hideAndClear();
1864
+ }
1865
+ }
1866
+ },
1867
+
1868
+ select: function (text, value, element) {
1869
+ value = value !== undefined
1870
+ ? value
1871
+ : text;
1872
+ if (module.can.activate($(element))) {
1873
+ module.set.value(value, text, $(element));
1874
+ if (!module.is.multiple() && !(!settings.collapseOnActionable && $(element).hasClass(className.actionable))) {
1875
+ module.hideAndClear();
1876
+ }
1877
+ }
1878
+ },
1879
+
1880
+ combo: function (text, value, element) {
1881
+ value = value !== undefined
1882
+ ? value
1883
+ : text;
1884
+ module.set.selected(value, $(element));
1885
+ module.hideAndClear();
1886
+ },
1887
+
1888
+ hide: function (text, value, element) {
1889
+ module.set.value(value, text, $(element));
1890
+ module.hideAndClear();
1891
+ },
1892
+
1893
+ },
1894
+
1895
+ get: {
1896
+ id: function () {
1897
+ return id;
1898
+ },
1899
+ defaultText: function () {
1900
+ return $module.data(metadata.defaultText);
1901
+ },
1902
+ defaultValue: function () {
1903
+ return $module.data(metadata.defaultValue);
1904
+ },
1905
+ placeholderText: function () {
1906
+ if (settings.placeholder !== 'auto' && typeof settings.placeholder === 'string') {
1907
+ return settings.placeholder;
1908
+ }
1909
+
1910
+ return $module.data(metadata.placeholderText) || '';
1911
+ },
1912
+ text: function () {
1913
+ return settings.preserveHTML ? $text.html() : $text.text();
1914
+ },
1915
+ query: function () {
1916
+ return String($search.val()).trim();
1917
+ },
1918
+ searchWidth: function (value) {
1919
+ value = value !== undefined
1920
+ ? value
1921
+ : $search.val();
1922
+ $sizer.text(value);
1923
+
1924
+ // prevent rounding issues
1925
+ return Math.ceil($sizer.width() + (module.is.edge() ? 3 : 1));
1926
+ },
1927
+ selectionCount: function () {
1928
+ var
1929
+ values = module.get.values(),
1930
+ count
1931
+ ;
1932
+ count = module.is.multiple()
1933
+ ? (Array.isArray(values) ? values.length : 0)
1934
+ : (module.get.value() !== '' ? 1 : 0);
1935
+
1936
+ return count;
1937
+ },
1938
+ transition: function ($subMenu) {
1939
+ return settings.transition === 'auto'
1940
+ ? (module.is.upward($subMenu) ? 'slide up' : 'slide down')
1941
+ : settings.transition;
1942
+ },
1943
+ userValues: function () {
1944
+ var
1945
+ values = module.get.values(true)
1946
+ ;
1947
+ if (!values) {
1948
+ return false;
1949
+ }
1950
+ values = Array.isArray(values)
1951
+ ? values
1952
+ : [values];
1953
+
1954
+ return $.grep(values, function (value) {
1955
+ return module.get.item(value) === false;
1956
+ });
1957
+ },
1958
+ uniqueArray: function (array) {
1959
+ return $.grep(array, function (value, index) {
1960
+ return $.inArray(value, array) === index;
1961
+ });
1962
+ },
1963
+ caretPosition: function (returnEndPos) {
1964
+ var
1965
+ input = $search[0],
1966
+ range,
1967
+ rangeLength
1968
+ ;
1969
+ if (returnEndPos && 'selectionEnd' in input) {
1970
+ return input.selectionEnd;
1971
+ }
1972
+ if (!returnEndPos && 'selectionStart' in input) {
1973
+ return input.selectionStart;
1974
+ }
1975
+ if (document.selection) {
1976
+ input.focus();
1977
+ range = document.selection.createRange();
1978
+ rangeLength = range.text.length;
1979
+ if (returnEndPos) {
1980
+ return rangeLength;
1981
+ }
1982
+ range.moveStart('character', -input.value.length);
1983
+
1984
+ return range.text.length - rangeLength;
1985
+ }
1986
+ },
1987
+ value: function () {
1988
+ var
1989
+ value = $input.length > 0
1990
+ ? $input.val()
1991
+ : $module.data(metadata.value),
1992
+ isEmptyMultiselect = Array.isArray(value) && value.length === 1 && value[0] === ''
1993
+ ;
1994
+
1995
+ // prevents placeholder element from being selected when multiple
1996
+ return value === undefined || isEmptyMultiselect
1997
+ ? ''
1998
+ : value;
1999
+ },
2000
+ values: function (raw) {
2001
+ var
2002
+ value = module.get.value()
2003
+ ;
2004
+ if (value === '') {
2005
+ return '';
2006
+ }
2007
+
2008
+ return !module.has.selectInput() && module.is.multiple()
2009
+ ? (typeof value === 'string' // delimited string
2010
+ ? (raw
2011
+ ? value
2012
+ : module.escape.htmlEntities(value)).split(settings.delimiter)
2013
+ : '')
2014
+ : value;
2015
+ },
2016
+ remoteValues: function () {
2017
+ var
2018
+ values = module.get.values(),
2019
+ remoteValues = false
2020
+ ;
2021
+ if (values) {
2022
+ if (typeof values === 'string') {
2023
+ values = [values];
2024
+ }
2025
+ $.each(values, function (index, value) {
2026
+ var
2027
+ name = module.read.remoteData(value)
2028
+ ;
2029
+ module.verbose('Restoring value from session data', name, value);
2030
+ if (name) {
2031
+ if (!remoteValues) {
2032
+ remoteValues = {};
2033
+ }
2034
+ remoteValues[value] = name;
2035
+ }
2036
+ });
2037
+ }
2038
+
2039
+ return remoteValues;
2040
+ },
2041
+ choiceText: function ($choice, preserveHTML) {
2042
+ preserveHTML = preserveHTML !== undefined
2043
+ ? preserveHTML
2044
+ : settings.preserveHTML;
2045
+ if ($choice) {
2046
+ if ($choice.find(selector.menu).length > 0) {
2047
+ module.verbose('Retrieving text of element with sub-menu');
2048
+ $choice = $choice.clone();
2049
+ $choice.find(selector.menu).remove();
2050
+ $choice.find(selector.menuIcon).remove();
2051
+ }
2052
+
2053
+ return $choice.data(metadata.text) !== undefined
2054
+ ? $choice.data(metadata.text)
2055
+ : (preserveHTML
2056
+ ? $choice.html() && $choice.html().trim()
2057
+ : $choice.text() && $choice.text().trim());
2058
+ }
2059
+ },
2060
+ choiceValue: function ($choice, choiceText) {
2061
+ choiceText = choiceText || module.get.choiceText($choice);
2062
+ if (!$choice) {
2063
+ return false;
2064
+ }
2065
+
2066
+ return $choice.data(metadata.value) !== undefined
2067
+ ? String($choice.data(metadata.value))
2068
+ : (typeof choiceText === 'string'
2069
+ ? String(
2070
+ settings.ignoreSearchCase
2071
+ ? choiceText.toLowerCase()
2072
+ : choiceText
2073
+ ).trim()
2074
+ : String(choiceText));
2075
+ },
2076
+ inputEvent: function () {
2077
+ var
2078
+ input = $search[0]
2079
+ ;
2080
+ if (input) {
2081
+ return input.oninput !== undefined
2082
+ ? 'input'
2083
+ : (input.onpropertychange !== undefined
2084
+ ? 'propertychange'
2085
+ : 'keyup');
2086
+ }
2087
+
2088
+ return false;
2089
+ },
2090
+ selectValues: function () {
2091
+ var
2092
+ select = {},
2093
+ oldGroup = [],
2094
+ values = []
2095
+ ;
2096
+ $module
2097
+ .find('option')
2098
+ .each(function () {
2099
+ var
2100
+ $option = $(this),
2101
+ name = $option.html(),
2102
+ disabled = $option.attr('disabled'),
2103
+ value = $option.attr('value') !== undefined
2104
+ ? $option.attr('value')
2105
+ : name,
2106
+ text = $option.data(metadata.text) !== undefined
2107
+ ? $option.data(metadata.text)
2108
+ : name,
2109
+ group = $option.parent('optgroup')
2110
+ ;
2111
+ if (settings.placeholder === 'auto' && value === '') {
2112
+ select.placeholder = name;
2113
+ } else {
2114
+ if (group.length !== oldGroup.length || group[0] !== oldGroup[0]) {
2115
+ values.push({
2116
+ type: 'header',
2117
+ divider: settings.headerDivider,
2118
+ name: group.attr('label') || '',
2119
+ });
2120
+ oldGroup = group;
2121
+ }
2122
+ values.push({
2123
+ name: name,
2124
+ value: value,
2125
+ text: module.escape.htmlEntities(text, true),
2126
+ disabled: disabled,
2127
+ });
2128
+ }
2129
+ })
2130
+ ;
2131
+ if (settings.placeholder && settings.placeholder !== 'auto') {
2132
+ module.debug('Setting placeholder value to', settings.placeholder);
2133
+ select.placeholder = settings.placeholder;
2134
+ }
2135
+ if (settings.sortSelect) {
2136
+ if (settings.sortSelect === true) {
2137
+ values.sort(function (a, b) {
2138
+ return a.name.localeCompare(b.name);
2139
+ });
2140
+ } else if (settings.sortSelect === 'natural') {
2141
+ values.sort(function (a, b) {
2142
+ return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
2143
+ });
2144
+ } else if (isFunction(settings.sortSelect)) {
2145
+ values.sort(settings.sortSelect);
2146
+ }
2147
+ select[fields.values] = values;
2148
+ module.debug('Retrieved and sorted values from select', select);
2149
+ } else {
2150
+ select[fields.values] = values;
2151
+ module.debug('Retrieved values from select', select);
2152
+ }
2153
+
2154
+ return select;
2155
+ },
2156
+ activeItem: function () {
2157
+ return $item.filter('.' + className.active);
2158
+ },
2159
+ selectedItem: function () {
2160
+ var
2161
+ $selectedItem = $item.not(selector.unselectable).filter('.' + className.selected)
2162
+ ;
2163
+
2164
+ return $selectedItem.length > 0
2165
+ ? $selectedItem
2166
+ : $item.eq(0);
2167
+ },
2168
+ itemWithAdditions: function (value) {
2169
+ var
2170
+ $items = module.get.item(value),
2171
+ $userItems = module.create.userChoice(value),
2172
+ hasUserItems = $userItems && $userItems.length > 0
2173
+ ;
2174
+ if (hasUserItems) {
2175
+ $items = $items.length > 0
2176
+ ? $items.add($userItems)
2177
+ : $userItems;
2178
+ }
2179
+
2180
+ return $items;
2181
+ },
2182
+ item: function (value, strict) {
2183
+ var
2184
+ $selectedItem = false,
2185
+ shouldSearch,
2186
+ isMultiple
2187
+ ;
2188
+ value = value !== undefined
2189
+ ? value
2190
+ : (module.get.values() !== undefined
2191
+ ? module.get.values()
2192
+ : module.get.text());
2193
+ isMultiple = module.is.multiple() && Array.isArray(value);
2194
+ shouldSearch = isMultiple
2195
+ ? value.length > 0
2196
+ : value !== undefined && value !== null;
2197
+ strict = value === '' || value === false || value === true
2198
+ ? true
2199
+ : strict || false;
2200
+ if (shouldSearch) {
2201
+ $item
2202
+ .each(function () {
2203
+ var
2204
+ $choice = $(this),
2205
+ optionText = module.get.choiceText($choice),
2206
+ optionValue = module.get.choiceValue($choice, optionText)
2207
+ ;
2208
+ // safe early exit
2209
+ if (optionValue === null || optionValue === undefined) {
2210
+ return;
2211
+ }
2212
+ if (isMultiple) {
2213
+ if ($.inArray(module.escape.htmlEntities(String(optionValue)), value.map(String).map(module.escape.htmlEntities)) !== -1) {
2214
+ $selectedItem = $selectedItem
2215
+ ? $selectedItem.add($choice)
2216
+ : $choice;
2217
+ }
2218
+ } else if (strict) {
2219
+ module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
2220
+ if (optionValue === value) {
2221
+ $selectedItem = $choice;
2222
+
2223
+ return true;
2224
+ }
2225
+ } else {
2226
+ if (settings.ignoreCase) {
2227
+ optionValue = optionValue.toLowerCase();
2228
+ value = value.toLowerCase();
2229
+ }
2230
+ if (module.escape.htmlEntities(String(optionValue)) === module.escape.htmlEntities(String(value))) {
2231
+ module.verbose('Found select item by value', optionValue, value);
2232
+ $selectedItem = $choice;
2233
+
2234
+ return true;
2235
+ }
2236
+ }
2237
+ })
2238
+ ;
2239
+ }
2240
+
2241
+ return $selectedItem;
2242
+ },
2243
+ displayType: function () {
2244
+ return $module.hasClass('column') ? 'flex' : settings.displayType;
2245
+ },
2246
+ },
2247
+
2248
+ check: {
2249
+ maxSelections: function (selectionCount) {
2250
+ if (settings.maxSelections) {
2251
+ selectionCount = selectionCount !== undefined
2252
+ ? selectionCount
2253
+ : module.get.selectionCount();
2254
+ if (selectionCount >= settings.maxSelections) {
2255
+ module.debug('Maximum selection count reached');
2256
+ if (settings.useLabels) {
2257
+ $item.addClass(className.filtered);
2258
+ module.add.message(message.maxSelections);
2259
+ }
2260
+
2261
+ return true;
2262
+ }
2263
+
2264
+ module.verbose('No longer at maximum selection count');
2265
+ module.remove.message();
2266
+ module.remove.filteredItem();
2267
+ if (module.is.searchSelection()) {
2268
+ module.filterItems();
2269
+ }
2270
+
2271
+ return false;
2272
+ }
2273
+
2274
+ return false;
2275
+ },
2276
+ disabled: function () {
2277
+ $search.attr('tabindex', module.is.disabled() ? -1 : 0);
2278
+ },
2279
+ },
2280
+
2281
+ restore: {
2282
+ defaults: function (preventChangeTrigger) {
2283
+ module.clear(preventChangeTrigger);
2284
+ module.restore.defaultText();
2285
+ module.restore.defaultValue();
2286
+ },
2287
+ defaultText: function () {
2288
+ var
2289
+ defaultText = module.get.defaultText(),
2290
+ placeholderText = module.get.placeholderText
2291
+ ;
2292
+ if (defaultText === placeholderText) {
2293
+ module.debug('Restoring default placeholder text', defaultText);
2294
+ module.set.placeholderText(defaultText);
2295
+ } else {
2296
+ module.debug('Restoring default text', defaultText);
2297
+ module.set.text(defaultText);
2298
+ }
2299
+ },
2300
+ placeholderText: function () {
2301
+ module.set.placeholderText();
2302
+ },
2303
+ defaultValue: function () {
2304
+ var
2305
+ defaultValue = module.get.defaultValue()
2306
+ ;
2307
+ if (defaultValue !== undefined) {
2308
+ module.debug('Restoring default value', defaultValue);
2309
+ if (defaultValue !== '') {
2310
+ module.set.value(defaultValue);
2311
+ module.set.selected();
2312
+ } else {
2313
+ module.remove.activeItem();
2314
+ module.remove.selectedItem();
2315
+ }
2316
+ }
2317
+ },
2318
+ labels: function () {
2319
+ if (settings.allowAdditions) {
2320
+ if (!settings.useLabels) {
2321
+ module.error(error.labels);
2322
+ settings.useLabels = true;
2323
+ }
2324
+ module.debug('Restoring selected values');
2325
+ module.create.userLabels();
2326
+ }
2327
+ module.check.maxSelections();
2328
+ },
2329
+ selected: function () {
2330
+ module.restore.values();
2331
+ if (module.is.multiple()) {
2332
+ module.debug('Restoring previously selected values and labels');
2333
+ module.restore.labels();
2334
+ } else {
2335
+ module.debug('Restoring previously selected values');
2336
+ }
2337
+ },
2338
+ values: function () {
2339
+ // prevents callbacks from occurring on initial load
2340
+ module.set.initialLoad();
2341
+ if (settings.apiSettings && settings.saveRemoteData && module.get.remoteValues()) {
2342
+ module.restore.remoteValues();
2343
+ } else {
2344
+ module.set.selected();
2345
+ }
2346
+ var value = module.get.value();
2347
+ if (value && value !== '' && !(Array.isArray(value) && value.length === 0)) {
2348
+ $input.removeClass(className.noselection);
2349
+ } else {
2350
+ $input.addClass(className.noselection);
2351
+ }
2352
+ module.remove.initialLoad();
2353
+ },
2354
+ remoteValues: function () {
2355
+ var
2356
+ values = module.get.remoteValues()
2357
+ ;
2358
+ module.debug('Recreating selected from session data', values);
2359
+ if (values) {
2360
+ if (module.is.single()) {
2361
+ $.each(values, function (value, name) {
2362
+ module.set.text(name);
2363
+ });
2364
+ } else if (settings.useLabels) {
2365
+ $.each(values, function (value, name) {
2366
+ module.add.label(value, name);
2367
+ });
2368
+ }
2369
+ }
2370
+ },
2371
+ },
2372
+
2373
+ read: {
2374
+ remoteData: function (value) {
2375
+ var
2376
+ name
2377
+ ;
2378
+ if (window.Storage === undefined) {
2379
+ module.error(error.noStorage);
2380
+
2381
+ return;
2382
+ }
2383
+ name = sessionStorage.getItem(value + elementNamespace);
2384
+
2385
+ return name !== undefined
2386
+ ? name
2387
+ : false;
2388
+ },
2389
+ },
2390
+
2391
+ save: {
2392
+ defaults: function () {
2393
+ module.save.defaultText();
2394
+ module.save.placeholderText();
2395
+ module.save.defaultValue();
2396
+ },
2397
+ defaultValue: function () {
2398
+ var
2399
+ value = module.get.value()
2400
+ ;
2401
+ module.verbose('Saving default value as', value);
2402
+ $module.data(metadata.defaultValue, value);
2403
+ },
2404
+ defaultText: function () {
2405
+ var
2406
+ text = module.get.text()
2407
+ ;
2408
+ module.verbose('Saving default text as', text);
2409
+ $module.data(metadata.defaultText, text);
2410
+ },
2411
+ placeholderText: function () {
2412
+ var
2413
+ text
2414
+ ;
2415
+ if (settings.placeholder !== false && $text.hasClass(className.placeholder)) {
2416
+ text = module.get.text();
2417
+ module.verbose('Saving placeholder text as', text);
2418
+ $module.data(metadata.placeholderText, text);
2419
+ }
2420
+ },
2421
+ remoteData: function (name, value) {
2422
+ if (window.Storage === undefined) {
2423
+ module.error(error.noStorage);
2424
+
2425
+ return;
2426
+ }
2427
+ module.verbose('Saving remote data to session storage', value, name);
2428
+ sessionStorage.setItem(value + elementNamespace, name);
2429
+ },
2430
+ },
2431
+
2432
+ clear: function (preventChangeTrigger) {
2433
+ if (module.is.multiple() && settings.useLabels) {
2434
+ module.remove.labels($module.find(selector.label), preventChangeTrigger);
2435
+ } else {
2436
+ module.remove.activeItem();
2437
+ module.remove.selectedItem();
2438
+ module.remove.filteredItem();
2439
+ }
2440
+ module.set.placeholderText();
2441
+ module.clearValue(preventChangeTrigger);
2442
+ },
2443
+
2444
+ clearValue: function (preventChangeTrigger) {
2445
+ module.set.value('', null, null, preventChangeTrigger);
2446
+ },
2447
+
2448
+ clearCache: function () {
2449
+ module.debug('Clearing API cache once');
2450
+ tempDisableApiCache = true;
2451
+ },
2452
+
2453
+ scrollPage: function (direction, $selectedItem) {
2454
+ var
2455
+ $currentItem = $selectedItem || module.get.selectedItem(),
2456
+ $menu = $currentItem.closest(selector.menu),
2457
+ menuHeight = $menu.outerHeight(),
2458
+ currentScroll = $menu.scrollTop(),
2459
+ itemHeight = $item.eq(0).outerHeight(),
2460
+ itemsPerPage = Math.floor(menuHeight / itemHeight),
2461
+ newScroll = direction === 'up'
2462
+ ? currentScroll - (itemHeight * itemsPerPage)
2463
+ : currentScroll + (itemHeight * itemsPerPage),
2464
+ $selectableItem = $item.not(selector.unselectable),
2465
+ isWithinRange,
2466
+ $nextSelectedItem,
2467
+ elementIndex
2468
+ ;
2469
+ elementIndex = direction === 'up'
2470
+ ? $selectableItem.index($currentItem) - itemsPerPage
2471
+ : $selectableItem.index($currentItem) + itemsPerPage;
2472
+ isWithinRange = direction === 'up'
2473
+ ? elementIndex >= 0
2474
+ : elementIndex < $selectableItem.length;
2475
+ $nextSelectedItem = isWithinRange
2476
+ ? $selectableItem.eq(elementIndex)
2477
+ : (direction === 'up'
2478
+ ? $selectableItem.first()
2479
+ : $selectableItem.last());
2480
+ if ($nextSelectedItem.length > 0) {
2481
+ module.debug('Scrolling page', direction, $nextSelectedItem);
2482
+ $currentItem
2483
+ .removeClass(className.selected)
2484
+ ;
2485
+ $nextSelectedItem
2486
+ .addClass(className.selected)
2487
+ ;
2488
+ if (settings.selectOnKeydown && module.is.single() && !$nextSelectedItem.hasClass(className.actionable)) {
2489
+ module.set.selectedItem($nextSelectedItem);
2490
+ }
2491
+ $menu
2492
+ .scrollTop(newScroll)
2493
+ ;
2494
+ }
2495
+ },
2496
+
2497
+ set: {
2498
+ filtered: function () {
2499
+ var
2500
+ isMultiple = module.is.multiple(),
2501
+ isSearch = module.is.searchSelection(),
2502
+ isSearchMultiple = isMultiple && isSearch,
2503
+ searchValue = isSearch
2504
+ ? module.get.query()
2505
+ : '',
2506
+ hasSearchValue = typeof searchValue === 'string' && searchValue.length > 0,
2507
+ searchWidth = module.get.searchWidth(),
2508
+ valueIsSet = searchValue !== ''
2509
+ ;
2510
+ if (isMultiple && hasSearchValue) {
2511
+ module.verbose('Adjusting input width', searchWidth);
2512
+ $search.css('width', searchWidth + 'px');
2513
+ }
2514
+ if (hasSearchValue || (isSearchMultiple && valueIsSet)) {
2515
+ module.verbose('Hiding placeholder text');
2516
+ $text.addClass(className.filtered);
2517
+ } else if (!isMultiple || (isSearchMultiple && !valueIsSet)) {
2518
+ module.verbose('Showing placeholder text');
2519
+ $text.removeClass(className.filtered);
2520
+ }
2521
+ },
2522
+ empty: function () {
2523
+ $module.addClass(className.empty);
2524
+ },
2525
+ loading: function () {
2526
+ $module.addClass(className.loading);
2527
+ },
2528
+ placeholderText: function (text) {
2529
+ text = text || module.get.placeholderText();
2530
+ module.debug('Setting placeholder text', text);
2531
+ module.set.text(text);
2532
+ $text.addClass(className.placeholder);
2533
+ },
2534
+ tabbable: function () {
2535
+ if (module.is.searchSelection()) {
2536
+ module.debug('Added tabindex to searchable dropdown');
2537
+ $search
2538
+ .val('')
2539
+ ;
2540
+ module.check.disabled();
2541
+ $menu
2542
+ .attr('tabindex', -1)
2543
+ ;
2544
+ } else {
2545
+ module.debug('Added tabindex to dropdown');
2546
+ if ($module.attr('tabindex') === undefined) {
2547
+ $module
2548
+ .attr('tabindex', $input.attr('tabindex') || 0)
2549
+ ;
2550
+ $menu
2551
+ .attr('tabindex', -1)
2552
+ ;
2553
+ }
2554
+ }
2555
+ $input.removeAttr('tabindex');
2556
+ },
2557
+ initialLoad: function () {
2558
+ module.verbose('Setting initial load');
2559
+ initialLoad = true;
2560
+ },
2561
+ activeItem: function ($item) {
2562
+ if (settings.allowAdditions && $item.filter(selector.addition).length > 0) {
2563
+ $item.addClass(className.filtered);
2564
+ } else {
2565
+ $item.addClass(className.active);
2566
+ }
2567
+ },
2568
+ partialSearch: function (text) {
2569
+ var
2570
+ length = module.get.query().length
2571
+ ;
2572
+ $search.val(text.slice(0, length));
2573
+ },
2574
+ scrollPosition: function ($item, forceScroll) {
2575
+ var
2576
+ edgeTolerance = 5,
2577
+ $menu,
2578
+ hasActive,
2579
+ offset,
2580
+ itemOffset,
2581
+ menuOffset,
2582
+ menuScroll,
2583
+ menuHeight,
2584
+ abovePage,
2585
+ belowPage
2586
+ ;
2587
+
2588
+ $item = $item || module.get.selectedItem();
2589
+ $menu = $item.closest(selector.menu);
2590
+ hasActive = $item && $item.length > 0;
2591
+ forceScroll = forceScroll !== undefined
2592
+ ? forceScroll
2593
+ : false;
2594
+ if (module.get.activeItem().length === 0) {
2595
+ forceScroll = false;
2596
+ }
2597
+ if ($item && $menu.length > 0 && hasActive) {
2598
+ itemOffset = $item.position().top;
2599
+
2600
+ $menu.addClass(className.loading);
2601
+ menuScroll = $menu.scrollTop();
2602
+ menuOffset = $menu.offset().top;
2603
+ itemOffset = $item.offset().top;
2604
+ offset = menuScroll - menuOffset + itemOffset;
2605
+ if (!forceScroll) {
2606
+ menuHeight = $menu.height();
2607
+ belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
2608
+ abovePage = (offset - edgeTolerance) < menuScroll;
2609
+ }
2610
+ module.debug('Scrolling to active item', offset);
2611
+ if (forceScroll || abovePage || belowPage) {
2612
+ $menu.scrollTop(offset);
2613
+ }
2614
+ $menu.removeClass(className.loading);
2615
+ }
2616
+ },
2617
+ text: function (text, isNotPlaceholder) {
2618
+ if (settings.action === 'combo') {
2619
+ module.debug('Changing combo button text', text, $combo);
2620
+ if (settings.preserveHTML) {
2621
+ $combo.html(text);
2622
+ } else {
2623
+ $combo.text(text);
2624
+ }
2625
+ } else if (settings.action === 'activate' || isFunction(settings.action)) {
2626
+ if (text !== module.get.placeholderText() || isNotPlaceholder) {
2627
+ $text.removeClass(className.placeholder);
2628
+ }
2629
+ module.debug('Changing text', text, $text);
2630
+ $text
2631
+ .removeClass(className.filtered)
2632
+ ;
2633
+ if (settings.preserveHTML) {
2634
+ $text.html(text);
2635
+ } else {
2636
+ $text.text(text);
2637
+ }
2638
+ }
2639
+ },
2640
+ selectedItem: function ($item) {
2641
+ var
2642
+ value = module.get.choiceValue($item),
2643
+ searchText = module.get.choiceText($item, false),
2644
+ text = module.get.choiceText($item)
2645
+ ;
2646
+ module.debug('Setting user selection to item', $item);
2647
+ module.remove.activeItem();
2648
+ module.set.partialSearch(searchText);
2649
+ module.set.activeItem($item);
2650
+ module.set.selected(value, $item);
2651
+ module.set.text(text);
2652
+ },
2653
+ selectedLetter: function (letter) {
2654
+ var
2655
+ $selectedItem = $item.filter('.' + className.selected),
2656
+ alreadySelectedLetter = $selectedItem.length > 0 && module.has.firstLetter($selectedItem, letter),
2657
+ $nextValue = false,
2658
+ $nextItem
2659
+ ;
2660
+ // check next of same letter
2661
+ if (alreadySelectedLetter) {
2662
+ $nextItem = $selectedItem.nextAll($item).eq(0);
2663
+ if (module.has.firstLetter($nextItem, letter)) {
2664
+ $nextValue = $nextItem;
2665
+ }
2666
+ }
2667
+ // check all values
2668
+ if (!$nextValue) {
2669
+ $item
2670
+ .each(function () {
2671
+ if (module.has.firstLetter($(this), letter)) {
2672
+ $nextValue = $(this);
2673
+
2674
+ return false;
2675
+ }
2676
+ })
2677
+ ;
2678
+ }
2679
+ // set next value
2680
+ if ($nextValue) {
2681
+ module.verbose('Scrolling to next value with letter', letter);
2682
+ module.set.scrollPosition($nextValue);
2683
+ $selectedItem.removeClass(className.selected);
2684
+ $nextValue.addClass(className.selected);
2685
+ if (settings.selectOnKeydown && module.is.single() && (!$nextItem || !$nextItem.hasClass(className.actionable))) {
2686
+ module.set.selectedItem($nextValue);
2687
+ }
2688
+ }
2689
+ },
2690
+ direction: function ($menu) {
2691
+ if (settings.direction === 'auto') {
2692
+ // reset position, remove upward if it's base menu
2693
+ if (!$menu) {
2694
+ module.remove.upward();
2695
+ } else if (module.is.upward($menu)) {
2696
+ // we need make sure when make assertion openDownward for $menu, $menu does not have upward class
2697
+ module.remove.upward($menu);
2698
+ }
2699
+
2700
+ if (module.can.openDownward($menu)) {
2701
+ module.remove.upward($menu);
2702
+ } else {
2703
+ module.set.upward($menu);
2704
+ }
2705
+ if (!module.is.leftward($menu) && !module.can.openRightward($menu)) {
2706
+ module.set.leftward($menu);
2707
+ }
2708
+ } else if (settings.direction === 'upward') {
2709
+ module.set.upward($menu);
2710
+ }
2711
+ },
2712
+ upward: function ($currentMenu) {
2713
+ var $element = $currentMenu || $module;
2714
+ $element.addClass(className.upward);
2715
+ },
2716
+ leftward: function ($currentMenu) {
2717
+ var $element = $currentMenu || $menu;
2718
+ $element.addClass(className.leftward);
2719
+ },
2720
+ value: function (value, text, $selected, preventChangeTrigger) {
2721
+ if (typeof text === 'boolean') {
2722
+ preventChangeTrigger = text;
2723
+ $selected = undefined;
2724
+ text = undefined;
2725
+ }
2726
+ if (value !== undefined && value !== '' && !(Array.isArray(value) && value.length === 0)) {
2727
+ $input.removeClass(className.noselection);
2728
+ } else {
2729
+ $input.addClass(className.noselection);
2730
+ }
2731
+ var
2732
+ escapedValue = module.escape.value(value),
2733
+ hasInput = $input.length > 0,
2734
+ currentValue = module.get.values(),
2735
+ stringValue = value !== undefined
2736
+ ? String(value)
2737
+ : value
2738
+ ;
2739
+ if (hasInput) {
2740
+ if (!settings.allowReselection && stringValue == currentValue) {
2741
+ module.verbose('Skipping value update already same value', value, currentValue);
2742
+ if (!module.is.initialLoad()) {
2743
+ return;
2744
+ }
2745
+ }
2746
+
2747
+ if (module.is.single() && module.has.selectInput() && module.can.extendSelect()) {
2748
+ module.debug('Adding user option', value);
2749
+ module.add.optionValue(value);
2750
+ }
2751
+ module.debug('Updating input value', escapedValue, currentValue);
2752
+ internalChange = true;
2753
+ $input
2754
+ .val(escapedValue)
2755
+ ;
2756
+ if (settings.fireOnInit === false && module.is.initialLoad()) {
2757
+ module.debug('Input native change event ignored on initial load');
2758
+ } else if (preventChangeTrigger !== true) {
2759
+ module.trigger.change();
2760
+ }
2761
+ internalChange = false;
2762
+ } else {
2763
+ module.verbose('Storing value in metadata', escapedValue, $input);
2764
+ if (escapedValue !== currentValue) {
2765
+ $module.data(metadata.value, stringValue);
2766
+ }
2767
+ }
2768
+ if (settings.fireOnInit === false && module.is.initialLoad()) {
2769
+ module.verbose('No callback on initial load', settings.onChange);
2770
+ } else if (preventChangeTrigger !== true) {
2771
+ settings.onChange.call(element, value, text, $selected);
2772
+ }
2773
+ },
2774
+ active: function () {
2775
+ $module
2776
+ .addClass(className.active)
2777
+ ;
2778
+ },
2779
+ multiple: function () {
2780
+ $module.addClass(className.multiple);
2781
+ },
2782
+ visible: function () {
2783
+ $module.addClass(className.visible);
2784
+ },
2785
+ exactly: function (value, $selectedItem, preventChangeTrigger) {
2786
+ if (typeof $selectedItem === 'boolean') {
2787
+ preventChangeTrigger = $selectedItem;
2788
+ $selectedItem = undefined;
2789
+ }
2790
+ module.debug('Setting selected to exact values');
2791
+ module.clear();
2792
+ module.set.selected(value, $selectedItem, preventChangeTrigger);
2793
+ },
2794
+ selected: function (value, $selectedItem, preventChangeTrigger, keepSearchTerm) {
2795
+ if (typeof $selectedItem === 'boolean') {
2796
+ keepSearchTerm = preventChangeTrigger;
2797
+ preventChangeTrigger = $selectedItem;
2798
+ $selectedItem = undefined;
2799
+ }
2800
+ var
2801
+ isMultiple = module.is.multiple()
2802
+ ;
2803
+ $selectedItem = settings.allowAdditions
2804
+ ? $selectedItem || module.get.itemWithAdditions(value)
2805
+ : $selectedItem || module.get.item(value);
2806
+ if (!$selectedItem && value !== undefined) {
2807
+ return false;
2808
+ }
2809
+ if (isMultiple) {
2810
+ if (!keepSearchTerm) {
2811
+ module.remove.searchWidth();
2812
+ }
2813
+ if (settings.useLabels) {
2814
+ module.remove.selectedItem();
2815
+ if (value === undefined) {
2816
+ module.remove.labels($module.find(selector.label), true);
2817
+ }
2818
+ }
2819
+ } else {
2820
+ module.remove.activeItem();
2821
+ module.remove.selectedItem();
2822
+ }
2823
+ if (!$selectedItem) {
2824
+ return false;
2825
+ }
2826
+ module.debug('Setting selected menu item to', $selectedItem);
2827
+ // select each item
2828
+ $selectedItem
2829
+ .each(function () {
2830
+ var
2831
+ $selected = $(this),
2832
+ selectedText = module.get.choiceText($selected),
2833
+ selectedValue = module.get.choiceValue($selected, selectedText),
2834
+
2835
+ isFiltered = $selected.hasClass(className.filtered),
2836
+ isActive = $selected.hasClass(className.active),
2837
+ isActionable = $selected.hasClass(className.actionable),
2838
+ isUserValue = $selected.hasClass(className.addition),
2839
+ shouldAnimate = isMultiple && $selectedItem && $selectedItem.length === 1
2840
+ ;
2841
+ if (isActionable) {
2842
+ if ((!isMultiple || (!isActive || isUserValue)) && settings.apiSettings && settings.saveRemoteData) {
2843
+ module.save.remoteData(selectedText, selectedValue);
2844
+ }
2845
+ settings.onActionable.call(element, selectedValue, selectedText, $selected);
2846
+ } else if (isMultiple) {
2847
+ if (!isActive || isUserValue) {
2848
+ if (settings.apiSettings && settings.saveRemoteData) {
2849
+ module.save.remoteData(selectedText, selectedValue);
2850
+ }
2851
+ if (settings.useLabels) {
2852
+ module.add.label(selectedValue, selectedText, shouldAnimate);
2853
+ module.add.value(selectedValue, selectedText, $selected, preventChangeTrigger);
2854
+ module.set.activeItem($selected);
2855
+ module.filterActive();
2856
+ module.select.nextAvailable($selectedItem);
2857
+ } else {
2858
+ module.add.value(selectedValue, selectedText, $selected, preventChangeTrigger);
2859
+ module.set.text(module.add.variables(message.count));
2860
+ module.set.activeItem($selected);
2861
+ }
2862
+ } else if (!isFiltered && (settings.useLabels || selectActionActive)) {
2863
+ module.debug('Selected active value, removing label');
2864
+ module.remove.selected(selectedValue);
2865
+ }
2866
+ } else {
2867
+ if (settings.apiSettings && settings.saveRemoteData) {
2868
+ module.save.remoteData(selectedText, selectedValue);
2869
+ }
2870
+ if (!keepSearchTerm && !$selected.hasClass(className.actionable)) {
2871
+ module.set.text(selectedText, true);
2872
+ }
2873
+ module.set.value(selectedValue, selectedText, $selected, preventChangeTrigger);
2874
+ $selected
2875
+ .addClass(className.active)
2876
+ .addClass(className.selected)
2877
+ ;
2878
+ }
2879
+ })
2880
+ ;
2881
+ if (!keepSearchTerm) {
2882
+ module.remove.searchTerm();
2883
+ }
2884
+ if (module.is.allFiltered()) {
2885
+ module.set.empty();
2886
+ module.hideMenu();
2887
+ }
2888
+ },
2889
+ },
2890
+
2891
+ add: {
2892
+ label: function (value, text, shouldAnimate) {
2893
+ var
2894
+ $next = module.is.searchSelection()
2895
+ ? $search
2896
+ : $text,
2897
+ escapedValue = module.escape.value(value),
2898
+ $label
2899
+ ;
2900
+ if (settings.ignoreCase) {
2901
+ escapedValue = escapedValue.toLowerCase();
2902
+ }
2903
+ $label = $('<a />')
2904
+ .addClass(className.label)
2905
+ .attr('data-' + metadata.value, escapedValue)
2906
+ .html(templates.label(escapedValue, text, settings.preserveHTML, settings.className))
2907
+ ;
2908
+ $label = settings.onLabelCreate.call($label, escapedValue, text);
2909
+
2910
+ if (module.has.label(value)) {
2911
+ module.debug('User selection already exists, skipping', escapedValue);
2912
+
2913
+ return;
2914
+ }
2915
+ if (settings.label.variation) {
2916
+ $label.addClass(settings.label.variation);
2917
+ }
2918
+ if (shouldAnimate === true && settings.label.transition) {
2919
+ module.debug('Animating in label', $label);
2920
+ $label
2921
+ .addClass(className.hidden)
2922
+ .insertBefore($next)
2923
+ .transition({
2924
+ animation: settings.label.transition,
2925
+ debug: settings.debug,
2926
+ verbose: settings.verbose,
2927
+ silent: settings.silent,
2928
+ duration: settings.label.duration,
2929
+ })
2930
+ ;
2931
+ } else {
2932
+ module.debug('Adding selection label', $label);
2933
+ $label
2934
+ .insertBefore($next)
2935
+ ;
2936
+ }
2937
+ },
2938
+ message: function (message) {
2939
+ var
2940
+ $message = $menu.children(selector.message),
2941
+ html = settings.templates.message(module.add.variables(message))
2942
+ ;
2943
+ if ($message.length > 0) {
2944
+ $message
2945
+ .html(html)
2946
+ ;
2947
+ } else {
2948
+ $('<div/>')
2949
+ .html(html)
2950
+ .addClass(className.message)
2951
+ .appendTo($menu)
2952
+ ;
2953
+ }
2954
+ },
2955
+ optionValue: function (value) {
2956
+ var
2957
+ escapedValue = module.escape.value(value),
2958
+ $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
2959
+ hasOption = $option.length > 0
2960
+ ;
2961
+ if (hasOption) {
2962
+ return;
2963
+ }
2964
+ // temporarily disconnect observer
2965
+ module.disconnect.selectObserver();
2966
+ if (module.is.single()) {
2967
+ module.verbose('Removing previous user addition');
2968
+ $input.find('option.' + className.addition).remove();
2969
+ }
2970
+ $('<option/>')
2971
+ .prop('value', escapedValue)
2972
+ .addClass(className.addition)
2973
+ .text(value)
2974
+ .appendTo($input)
2975
+ ;
2976
+ module.verbose('Adding user addition as an <option>', value);
2977
+ module.observe.select();
2978
+ },
2979
+ userSuggestion: function (value) {
2980
+ var
2981
+ $addition = $menu.children(selector.addition),
2982
+ $existingItem = module.get.item(value),
2983
+ alreadyHasValue = $existingItem && $existingItem.not(selector.addition).length > 0,
2984
+ hasUserSuggestion = $addition.length > 0,
2985
+ html
2986
+ ;
2987
+ if (settings.useLabels && module.has.maxSelections()) {
2988
+ return;
2989
+ }
2990
+ if (value === '' || alreadyHasValue) {
2991
+ $addition.remove();
2992
+
2993
+ return;
2994
+ }
2995
+ if (hasUserSuggestion) {
2996
+ $addition
2997
+ .data(metadata.value, value)
2998
+ .data(metadata.text, value)
2999
+ .attr('data-' + metadata.value, value)
3000
+ .attr('data-' + metadata.text, value)
3001
+ .removeClass(className.filtered)
3002
+ ;
3003
+ if (!settings.hideAdditions) {
3004
+ html = settings.templates.addition(module.add.variables(message.addResult, value));
3005
+ $addition
3006
+ .html(html)
3007
+ ;
3008
+ }
3009
+ module.verbose('Replacing user suggestion with new value', $addition);
3010
+ } else {
3011
+ $addition = module.create.userChoice(value);
3012
+ $addition
3013
+ .prependTo($menu)
3014
+ ;
3015
+ module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
3016
+ }
3017
+ if (!settings.hideAdditions || module.is.allFiltered()) {
3018
+ $addition
3019
+ .addClass(className.selected)
3020
+ .siblings()
3021
+ .removeClass(className.selected)
3022
+ ;
3023
+ }
3024
+ module.refreshItems();
3025
+ },
3026
+ variables: function (message, term) {
3027
+ var
3028
+ hasCount = message.search('{count}') !== -1,
3029
+ hasMaxCount = message.search('{maxCount}') !== -1,
3030
+ hasTerm = message.search('{term}') !== -1,
3031
+ query
3032
+ ;
3033
+ module.verbose('Adding templated variables to message', message);
3034
+ if (hasCount) {
3035
+ message = message.replace('{count}', module.get.selectionCount());
3036
+ }
3037
+ if (hasMaxCount) {
3038
+ message = message.replace('{maxCount}', settings.maxSelections);
3039
+ }
3040
+ if (hasTerm) {
3041
+ query = term || module.get.query();
3042
+ message = message.replace('{term}', query);
3043
+ }
3044
+
3045
+ return message;
3046
+ },
3047
+ value: function (addedValue, addedText, $selectedItem, preventChangeTrigger) {
3048
+ if (typeof addedText === 'boolean') {
3049
+ preventChangeTrigger = addedText;
3050
+ $selectedItem = undefined;
3051
+ addedText = undefined;
3052
+ }
3053
+ var
3054
+ currentValue = module.get.values(true),
3055
+ newValue
3056
+ ;
3057
+ if (module.has.value(addedValue)) {
3058
+ module.debug('Value already selected');
3059
+
3060
+ return;
3061
+ }
3062
+ if (addedValue === '') {
3063
+ module.debug('Cannot select blank values from multiselect');
3064
+
3065
+ return;
3066
+ }
3067
+ // extend current array
3068
+ if (Array.isArray(currentValue)) {
3069
+ newValue = $selectedItem && $selectedItem.hasClass(className.actionable) ? currentValue : currentValue.concat([addedValue]);
3070
+ newValue = module.get.uniqueArray(newValue);
3071
+ } else {
3072
+ newValue = [addedValue];
3073
+ }
3074
+ // add values
3075
+ if (module.has.selectInput()) {
3076
+ if (module.can.extendSelect()) {
3077
+ module.debug('Adding value to select', addedValue, newValue, $input);
3078
+ module.add.optionValue(addedValue);
3079
+ }
3080
+ } else {
3081
+ newValue = newValue.join(settings.delimiter);
3082
+ module.debug('Setting hidden input to delimited value', newValue, $input);
3083
+ }
3084
+
3085
+ if (settings.fireOnInit === false && module.is.initialLoad()) {
3086
+ module.verbose('Skipping onadd callback on initial load', settings.onAdd);
3087
+ } else {
3088
+ settings.onAdd.call(element, addedValue, addedText, $selectedItem);
3089
+ }
3090
+ module.set.value(newValue, addedText, $selectedItem, preventChangeTrigger);
3091
+ module.check.maxSelections();
3092
+ },
3093
+ },
3094
+
3095
+ remove: {
3096
+ active: function () {
3097
+ $module.removeClass(className.active);
3098
+ },
3099
+ activeLabel: function () {
3100
+ $module.find(selector.label).removeClass(className.active);
3101
+ },
3102
+ empty: function () {
3103
+ $module.removeClass(className.empty);
3104
+ },
3105
+ loading: function () {
3106
+ $module.removeClass(className.loading);
3107
+ },
3108
+ initialLoad: function () {
3109
+ initialLoad = false;
3110
+ },
3111
+ upward: function ($currentMenu) {
3112
+ var $element = $currentMenu || $module;
3113
+ $element.removeClass(className.upward);
3114
+ },
3115
+ leftward: function ($currentMenu) {
3116
+ var $element = $currentMenu || $menu;
3117
+ $element.removeClass(className.leftward);
3118
+ },
3119
+ visible: function () {
3120
+ $module.removeClass(className.visible);
3121
+ },
3122
+ activeItem: function () {
3123
+ $item.removeClass(className.active);
3124
+ },
3125
+ filteredItem: function () {
3126
+ if (settings.highlightMatches) {
3127
+ $.each($item, function (index, item) {
3128
+ var $markItem = $(item);
3129
+ $markItem.html($markItem.html().replace(/<\/?mark>/g, ''));
3130
+ });
3131
+ }
3132
+ if (settings.useLabels && module.has.maxSelections()) {
3133
+ return;
3134
+ }
3135
+ if (settings.useLabels && module.is.multiple()) {
3136
+ $item.not('.' + className.active).removeClass(className.filtered);
3137
+ } else {
3138
+ $item.removeClass(className.filtered);
3139
+ }
3140
+ if (settings.hideDividers) {
3141
+ $divider.removeClass(className.hidden);
3142
+ }
3143
+ module.remove.empty();
3144
+ },
3145
+ optionValue: function (value) {
3146
+ var
3147
+ escapedValue = module.escape.value(value),
3148
+ $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
3149
+ hasOption = $option.length > 0
3150
+ ;
3151
+ if (!hasOption || !$option.hasClass(className.addition)) {
3152
+ return;
3153
+ }
3154
+ // temporarily disconnect observer
3155
+ module.disconnect.selectObserver();
3156
+ $option.remove();
3157
+ module.verbose('Removing user addition as an <option>', escapedValue);
3158
+ module.observe.select();
3159
+ },
3160
+ message: function () {
3161
+ $menu.children(selector.message).remove();
3162
+ },
3163
+ searchWidth: function () {
3164
+ $search.css('width', '');
3165
+ },
3166
+ searchTerm: function () {
3167
+ module.verbose('Cleared search term');
3168
+ $search.val('');
3169
+ module.set.filtered();
3170
+ },
3171
+ userAddition: function () {
3172
+ $item.filter(selector.addition).remove();
3173
+ },
3174
+ selected: function (value, $selectedItem, preventChangeTrigger) {
3175
+ $selectedItem = settings.allowAdditions
3176
+ ? $selectedItem || module.get.itemWithAdditions(value)
3177
+ : $selectedItem || module.get.item(value);
3178
+
3179
+ if (!$selectedItem) {
3180
+ return false;
3181
+ }
3182
+
3183
+ $selectedItem
3184
+ .each(function () {
3185
+ var
3186
+ $selected = $(this),
3187
+ selectedText = module.get.choiceText($selected),
3188
+ selectedValue = module.get.choiceValue($selected, selectedText)
3189
+ ;
3190
+ if (module.is.multiple()) {
3191
+ if (settings.useLabels) {
3192
+ module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
3193
+ module.remove.label(selectedValue);
3194
+ } else {
3195
+ module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
3196
+ if (module.get.selectionCount() === 0) {
3197
+ module.set.placeholderText();
3198
+ } else {
3199
+ module.set.text(module.add.variables(message.count));
3200
+ }
3201
+ }
3202
+ } else {
3203
+ module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
3204
+ }
3205
+ $selected
3206
+ .removeClass(className.filtered)
3207
+ .removeClass(className.active)
3208
+ ;
3209
+ if (settings.useLabels) {
3210
+ $selected.removeClass(className.selected);
3211
+ }
3212
+ })
3213
+ ;
3214
+ },
3215
+ selectedItem: function () {
3216
+ $item.removeClass(className.selected);
3217
+ },
3218
+ value: function (removedValue, removedText, $removedItem, preventChangeTrigger) {
3219
+ var
3220
+ values = module.get.values(true),
3221
+ newValue
3222
+ ;
3223
+ if (module.has.selectInput()) {
3224
+ module.verbose('Input is <select> removing selected option', removedValue);
3225
+ newValue = module.remove.arrayValue(removedValue, values);
3226
+ module.remove.optionValue(removedValue);
3227
+ } else {
3228
+ module.verbose('Removing from delimited values', removedValue);
3229
+ newValue = module.remove.arrayValue(removedValue, values);
3230
+ newValue = newValue.join(settings.delimiter);
3231
+ }
3232
+ if (settings.fireOnInit === false && module.is.initialLoad()) {
3233
+ module.verbose('No callback on initial load', settings.onRemove);
3234
+ } else {
3235
+ settings.onRemove.call(element, removedValue, removedText, $removedItem);
3236
+ }
3237
+ module.set.value(newValue, removedText, $removedItem, preventChangeTrigger);
3238
+ module.check.maxSelections();
3239
+ },
3240
+ arrayValue: function (removedValue, values) {
3241
+ if (!Array.isArray(values)) {
3242
+ values = [values];
3243
+ }
3244
+ values = $.grep(values, function (value) {
3245
+ return removedValue != value;
3246
+ });
3247
+ module.verbose('Removed value from delimited string', removedValue, values);
3248
+
3249
+ return values;
3250
+ },
3251
+ label: function (value, shouldAnimate) {
3252
+ var
3253
+ escapedValue = module.escape.value(value),
3254
+ $labels = $module.find(selector.label),
3255
+ $removedLabel = $labels.filter('[data-' + metadata.value + '="' + module.escape.string(settings.ignoreCase ? escapedValue.toLowerCase() : escapedValue) + '"]')
3256
+ ;
3257
+ module.verbose('Removing label', $removedLabel);
3258
+ $removedLabel.remove();
3259
+ },
3260
+ activeLabels: function ($activeLabels) {
3261
+ $activeLabels = $activeLabels || $module.find(selector.label).filter('.' + className.active);
3262
+ module.verbose('Removing active label selections', $activeLabels);
3263
+ module.remove.labels($activeLabels);
3264
+ },
3265
+ labels: function ($labels, preventChangeTrigger) {
3266
+ $labels = $labels || $module.find(selector.label);
3267
+ module.verbose('Removing labels', $labels);
3268
+ $labels
3269
+ .each(function () {
3270
+ var
3271
+ $label = $(this),
3272
+ value = $label.data(metadata.value),
3273
+ stringValue = value !== undefined
3274
+ ? String(value)
3275
+ : value,
3276
+ isUserValue = module.is.userValue(stringValue)
3277
+ ;
3278
+ if (settings.onLabelRemove.call($label, value) === false) {
3279
+ module.debug('Label remove callback cancelled removal');
3280
+
3281
+ return;
3282
+ }
3283
+ module.remove.message();
3284
+ if (isUserValue) {
3285
+ module.remove.value(stringValue, stringValue, module.get.item(stringValue), preventChangeTrigger);
3286
+ module.remove.label(stringValue);
3287
+ } else {
3288
+ // selected will also remove label
3289
+ module.remove.selected(stringValue, false, preventChangeTrigger);
3290
+ }
3291
+ })
3292
+ ;
3293
+ },
3294
+ tabbable: function () {
3295
+ if (module.is.searchSelection()) {
3296
+ module.debug('Searchable dropdown initialized');
3297
+ $search
3298
+ .removeAttr('tabindex')
3299
+ ;
3300
+ $menu
3301
+ .removeAttr('tabindex')
3302
+ ;
3303
+ } else {
3304
+ module.debug('Simple selection dropdown initialized');
3305
+ $module
3306
+ .removeAttr('tabindex')
3307
+ ;
3308
+ $menu
3309
+ .removeAttr('tabindex')
3310
+ ;
3311
+ }
3312
+ },
3313
+ diacritics: function (text) {
3314
+ return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036F]/g, '') : text;
3315
+ },
3316
+ },
3317
+
3318
+ has: {
3319
+ menuSearch: function () {
3320
+ return module.has.search() && $search.closest($menu).length > 0;
3321
+ },
3322
+ clearItem: function () {
3323
+ return $clear.length > 0;
3324
+ },
3325
+ search: function () {
3326
+ return $search.length > 0;
3327
+ },
3328
+ sizer: function () {
3329
+ return $sizer.length > 0;
3330
+ },
3331
+ selectInput: function () {
3332
+ return $input.is('select');
3333
+ },
3334
+ minCharacters: function (searchTerm) {
3335
+ if (settings.minCharacters && !iconClicked) {
3336
+ searchTerm = searchTerm !== undefined
3337
+ ? String(searchTerm)
3338
+ : String(module.get.query());
3339
+
3340
+ return searchTerm.length >= settings.minCharacters;
3341
+ }
3342
+ iconClicked = false;
3343
+
3344
+ return true;
3345
+ },
3346
+ firstLetter: function ($item, letter) {
3347
+ var
3348
+ text,
3349
+ firstLetter
3350
+ ;
3351
+ if (!$item || $item.length === 0 || typeof letter !== 'string') {
3352
+ return false;
3353
+ }
3354
+ text = module.get.choiceText($item, false);
3355
+ letter = letter.toLowerCase();
3356
+ firstLetter = String(text).charAt(0).toLowerCase();
3357
+
3358
+ return letter == firstLetter;
3359
+ },
3360
+ input: function () {
3361
+ return $input.length > 0;
3362
+ },
3363
+ items: function () {
3364
+ return $item.length > 0;
3365
+ },
3366
+ menu: function () {
3367
+ return $menu.length > 0;
3368
+ },
3369
+ subMenu: function ($currentMenu) {
3370
+ return ($currentMenu || $menu).find(selector.menu).length > 0;
3371
+ },
3372
+ message: function () {
3373
+ return $menu.children(selector.message).length > 0;
3374
+ },
3375
+ label: function (value) {
3376
+ var
3377
+ escapedValue = module.escape.value(value),
3378
+ $labels = $module.find(selector.label)
3379
+ ;
3380
+ if (settings.ignoreCase) {
3381
+ escapedValue = escapedValue.toLowerCase();
3382
+ }
3383
+
3384
+ return $labels.filter('[data-' + metadata.value + '="' + module.escape.string(escapedValue) + '"]').length > 0;
3385
+ },
3386
+ maxSelections: function () {
3387
+ return settings.maxSelections && module.get.selectionCount() >= settings.maxSelections;
3388
+ },
3389
+ allResultsFiltered: function () {
3390
+ var
3391
+ $normalResults = $item.not(selector.addition)
3392
+ ;
3393
+
3394
+ return $normalResults.filter(selector.unselectable).length === $normalResults.length;
3395
+ },
3396
+ userSuggestion: function () {
3397
+ return $menu.children(selector.addition).length > 0;
3398
+ },
3399
+ query: function () {
3400
+ return module.get.query() !== '';
3401
+ },
3402
+ value: function (value) {
3403
+ return settings.ignoreCase
3404
+ ? module.has.valueIgnoringCase(value)
3405
+ : module.has.valueMatchingCase(value);
3406
+ },
3407
+ valueMatchingCase: function (value) {
3408
+ var
3409
+ values = module.get.values(true),
3410
+ hasValue = Array.isArray(values)
3411
+ ? values && ($.inArray(value, values) !== -1)
3412
+ : values == value
3413
+ ;
3414
+
3415
+ return !!hasValue;
3416
+ },
3417
+ valueIgnoringCase: function (value) {
3418
+ var
3419
+ values = module.get.values(true),
3420
+ hasValue = false
3421
+ ;
3422
+ if (!Array.isArray(values)) {
3423
+ values = [values];
3424
+ }
3425
+ $.each(values, function (index, existingValue) {
3426
+ if (String(value).toLowerCase() === String(existingValue).toLowerCase()) {
3427
+ hasValue = true;
3428
+
3429
+ return false;
3430
+ }
3431
+ });
3432
+
3433
+ return hasValue;
3434
+ },
3435
+ },
3436
+
3437
+ is: {
3438
+ active: function () {
3439
+ return $module.hasClass(className.active);
3440
+ },
3441
+ animatingInward: function () {
3442
+ return $menu.transition('is inward');
3443
+ },
3444
+ animatingOutward: function () {
3445
+ return $menu.transition('is outward');
3446
+ },
3447
+ bubbledLabelClick: function (event) {
3448
+ return $(event.target).is('select, input') && $module.closest('label').length > 0;
3449
+ },
3450
+ bubbledIconClick: function (event) {
3451
+ return $(event.target).closest($icon).length > 0;
3452
+ },
3453
+ edge: function () {
3454
+ return !!window.chrome && !!window.StyleMedia;
3455
+ },
3456
+ empty: function () {
3457
+ return $module.hasClass(className.empty);
3458
+ },
3459
+ chrome: function () {
3460
+ return !!window.chrome && !window.StyleMedia;
3461
+ },
3462
+ alreadySetup: function () {
3463
+ return $module.is('select') && $module.parent(selector.dropdown).data(moduleNamespace) !== undefined && $module.prev().length === 0;
3464
+ },
3465
+ animating: function ($subMenu) {
3466
+ return $subMenu
3467
+ ? $subMenu.transition && $subMenu.transition('is animating')
3468
+ : $menu.transition && $menu.transition('is animating');
3469
+ },
3470
+ leftward: function ($subMenu) {
3471
+ var $selectedMenu = $subMenu || $menu;
3472
+
3473
+ return $selectedMenu.hasClass(className.leftward);
3474
+ },
3475
+ clearable: function () {
3476
+ var hasClearableClass = $module.hasClass(className.clearable);
3477
+ if (!hasClearableClass && settings.clearable) {
3478
+ $module.addClass(className.clearable);
3479
+ }
3480
+
3481
+ return hasClearableClass || settings.clearable;
3482
+ },
3483
+ disabled: function () {
3484
+ return $module.hasClass(className.disabled);
3485
+ },
3486
+ focused: function () {
3487
+ return document.activeElement === $module[0];
3488
+ },
3489
+ focusedOnSearch: function () {
3490
+ return document.activeElement === $search[0];
3491
+ },
3492
+ allFiltered: function () {
3493
+ return (module.is.multiple() || module.has.search()) && !(!settings.hideAdditions && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered();
3494
+ },
3495
+ hidden: function ($subMenu) {
3496
+ return !module.is.visible($subMenu);
3497
+ },
3498
+ initialLoad: function () {
3499
+ return initialLoad;
3500
+ },
3501
+ inObject: function (needle, object) {
3502
+ var
3503
+ found = false
3504
+ ;
3505
+ $.each(object, function (index, property) {
3506
+ if (property == needle) {
3507
+ found = true;
3508
+
3509
+ return true;
3510
+ }
3511
+ });
3512
+
3513
+ return found;
3514
+ },
3515
+ multiple: function () {
3516
+ return $module.hasClass(className.multiple);
3517
+ },
3518
+ remote: function () {
3519
+ return settings.apiSettings && module.can.useAPI();
3520
+ },
3521
+ noApiCache: function () {
3522
+ return tempDisableApiCache || (settings.apiSettings && !settings.apiSettings.cache);
3523
+ },
3524
+ single: function () {
3525
+ return !module.is.multiple();
3526
+ },
3527
+ selectMutation: function (mutations) {
3528
+ var
3529
+ selectChanged = false
3530
+ ;
3531
+ $.each(mutations, function (index, mutation) {
3532
+ if ($(mutation.target).is('option, optgroup') || $(mutation.addedNodes).is('select') || ($(mutation.target).is('select') && mutation.type !== 'attributes')) {
3533
+ selectChanged = true;
3534
+
3535
+ return false;
3536
+ }
3537
+ });
3538
+
3539
+ return selectChanged;
3540
+ },
3541
+ search: function () {
3542
+ return $module.hasClass(className.search);
3543
+ },
3544
+ searchSelection: function (deep) {
3545
+ return module.has.search() && (deep ? $search.parents(selector.dropdown) : $search.parent(selector.dropdown)).length === 1;
3546
+ },
3547
+ selection: function () {
3548
+ return $module.hasClass(className.selection);
3549
+ },
3550
+ userValue: function (value) {
3551
+ return $.inArray(value, module.get.userValues()) !== -1;
3552
+ },
3553
+ upward: function ($menu) {
3554
+ var $element = $menu || $module;
3555
+
3556
+ return $element.hasClass(className.upward);
3557
+ },
3558
+ visible: function ($subMenu) {
3559
+ return $subMenu
3560
+ ? $subMenu.hasClass(className.visible)
3561
+ : $menu.hasClass(className.visible);
3562
+ },
3563
+ verticallyScrollableContext: function () {
3564
+ var
3565
+ overflowY = $context[0] !== window
3566
+ ? $context.css('overflow-y')
3567
+ : false
3568
+ ;
3569
+
3570
+ return overflowY === 'auto' || overflowY === 'scroll';
3571
+ },
3572
+ horizontallyScrollableContext: function () {
3573
+ var
3574
+ overflowX = $context[0] !== window
3575
+ ? $context.css('overflow-X')
3576
+ : false
3577
+ ;
3578
+
3579
+ return overflowX === 'auto' || overflowX === 'scroll';
3580
+ },
3581
+ },
3582
+
3583
+ can: {
3584
+ activate: function ($item) {
3585
+ return (
3586
+ settings.useLabels
3587
+ || !module.has.maxSelections()
3588
+ || (module.has.maxSelections() && $item.hasClass(className.active))
3589
+ );
3590
+ },
3591
+ openDownward: function ($subMenu) {
3592
+ var
3593
+ $currentMenu = $subMenu || $menu,
3594
+ canOpenDownward,
3595
+ onScreen,
3596
+ calculations
3597
+ ;
3598
+ $currentMenu
3599
+ .addClass(className.loading)
3600
+ ;
3601
+ calculations = {
3602
+ context: {
3603
+ offset: $context[0] === window
3604
+ ? { top: 0, left: 0 }
3605
+ : $context.offset(),
3606
+ scrollTop: $context.scrollTop(),
3607
+ height: $context.outerHeight(),
3608
+ },
3609
+ menu: {
3610
+ offset: $currentMenu.offset(),
3611
+ height: $currentMenu.outerHeight(),
3612
+ },
3613
+ };
3614
+ if (module.is.verticallyScrollableContext()) {
3615
+ calculations.menu.offset.top += calculations.context.scrollTop;
3616
+ }
3617
+ if (module.has.subMenu($currentMenu)) {
3618
+ calculations.menu.height += $currentMenu.find(selector.menu).first().outerHeight();
3619
+ }
3620
+ onScreen = {
3621
+ above: calculations.context.scrollTop <= calculations.menu.offset.top - calculations.context.offset.top - calculations.menu.height,
3622
+ below: (calculations.context.scrollTop + calculations.context.height) >= calculations.menu.offset.top - calculations.context.offset.top + calculations.menu.height,
3623
+ };
3624
+ if (onScreen.below) {
3625
+ module.verbose('Dropdown can fit in context downward', onScreen);
3626
+ canOpenDownward = true;
3627
+ } else if (!onScreen.below && !onScreen.above) {
3628
+ module.verbose('Dropdown cannot fit in either direction, favoring downward', onScreen);
3629
+ canOpenDownward = true;
3630
+ } else {
3631
+ module.verbose('Dropdown cannot fit below, opening upward', onScreen);
3632
+ canOpenDownward = false;
3633
+ }
3634
+ $currentMenu.removeClass(className.loading);
3635
+
3636
+ return canOpenDownward;
3637
+ },
3638
+ openRightward: function ($subMenu) {
3639
+ var
3640
+ $currentMenu = $subMenu || $menu,
3641
+ canOpenRightward = true,
3642
+ isOffscreenRight = false,
3643
+ calculations
3644
+ ;
3645
+ $currentMenu
3646
+ .addClass(className.loading)
3647
+ ;
3648
+ calculations = {
3649
+ context: {
3650
+ offset: $context[0] === window
3651
+ ? { top: 0, left: 0 }
3652
+ : $context.offset(),
3653
+ scrollLeft: $context.scrollLeft(),
3654
+ width: $context.outerWidth(),
3655
+ },
3656
+ menu: {
3657
+ offset: $currentMenu.offset(),
3658
+ width: $currentMenu.outerWidth(),
3659
+ },
3660
+ };
3661
+ if (module.is.horizontallyScrollableContext()) {
3662
+ calculations.menu.offset.left += calculations.context.scrollLeft;
3663
+ }
3664
+ isOffscreenRight = calculations.menu.offset.left - calculations.context.offset.left + calculations.menu.width >= calculations.context.scrollLeft + calculations.context.width;
3665
+ if (isOffscreenRight) {
3666
+ module.verbose('Dropdown cannot fit in context rightward', isOffscreenRight);
3667
+ canOpenRightward = false;
3668
+ }
3669
+ $currentMenu.removeClass(className.loading);
3670
+
3671
+ return canOpenRightward;
3672
+ },
3673
+ extendSelect: function () {
3674
+ return settings.allowAdditions || settings.apiSettings;
3675
+ },
3676
+ show: function () {
3677
+ return !module.is.disabled() && (module.has.items() || module.has.message());
3678
+ },
3679
+ useAPI: function () {
3680
+ return $.fn.api !== undefined;
3681
+ },
3682
+ useElement: function (element) {
3683
+ if ($.fn[element] !== undefined) {
3684
+ return true;
3685
+ }
3686
+ module.error(error.noElement.replace('{element}', element));
3687
+
3688
+ return false;
3689
+ },
3690
+ },
3691
+
3692
+ animate: {
3693
+ show: function (callback, $subMenu) {
3694
+ var
3695
+ $currentMenu = $subMenu || $menu,
3696
+ start = $subMenu
3697
+ ? function () {}
3698
+ : function () {
3699
+ module.hideSubMenus();
3700
+ module.hideOthers();
3701
+ module.set.active();
3702
+ },
3703
+ transition
3704
+ ;
3705
+ callback = isFunction(callback)
3706
+ ? callback
3707
+ : function () {};
3708
+ module.verbose('Doing menu show animation', $currentMenu);
3709
+ module.set.direction($subMenu);
3710
+ transition = settings.transition.showMethod || module.get.transition($subMenu);
3711
+ if (module.is.selection()) {
3712
+ module.set.scrollPosition(module.get.selectedItem(), true);
3713
+ }
3714
+ if (module.is.hidden($currentMenu) || module.is.animating($currentMenu)) {
3715
+ if (transition === 'none') {
3716
+ start();
3717
+ $currentMenu.transition({
3718
+ displayType: module.get.displayType(),
3719
+ }).transition('show');
3720
+ callback.call(element);
3721
+ } else if (module.can.useElement('transition')) {
3722
+ $currentMenu
3723
+ .transition({
3724
+ animation: transition + ' in',
3725
+ debug: settings.debug,
3726
+ verbose: settings.verbose,
3727
+ silent: settings.silent,
3728
+ duration: settings.transition.showDuration || settings.duration,
3729
+ queue: true,
3730
+ onStart: start,
3731
+ displayType: module.get.displayType(),
3732
+ onComplete: function () {
3733
+ callback.call(element);
3734
+ },
3735
+ })
3736
+ ;
3737
+ }
3738
+ }
3739
+ },
3740
+ hide: function (callback, $subMenu) {
3741
+ var
3742
+ $currentMenu = $subMenu || $menu,
3743
+ start = $subMenu
3744
+ ? function () {}
3745
+ : function () {
3746
+ module.unbind.intent();
3747
+ module.remove.active();
3748
+ },
3749
+ transition = settings.transition.hideMethod || module.get.transition($subMenu)
3750
+ ;
3751
+ callback = isFunction(callback)
3752
+ ? callback
3753
+ : function () {};
3754
+ if (module.is.visible($currentMenu) || module.is.animating($currentMenu)) {
3755
+ module.verbose('Doing menu hide animation', $currentMenu);
3756
+
3757
+ if (transition === 'none') {
3758
+ start();
3759
+ $currentMenu.transition({
3760
+ displayType: module.get.displayType(),
3761
+ }).transition('hide');
3762
+ callback.call(element);
3763
+ } else if ($.fn.transition !== undefined) {
3764
+ $currentMenu
3765
+ .transition({
3766
+ animation: transition + ' out',
3767
+ duration: settings.transition.hideDuration || settings.duration,
3768
+ debug: settings.debug,
3769
+ verbose: settings.verbose,
3770
+ silent: settings.silent,
3771
+ queue: false,
3772
+ onStart: start,
3773
+ displayType: module.get.displayType(),
3774
+ onComplete: function () {
3775
+ callback.call(element);
3776
+ },
3777
+ })
3778
+ ;
3779
+ } else {
3780
+ module.error(error.transition);
3781
+ }
3782
+ }
3783
+ },
3784
+ },
3785
+
3786
+ hideAndClear: function () {
3787
+ module.remove.searchTerm();
3788
+ if (module.has.maxSelections()) {
3789
+ return;
3790
+ }
3791
+ if (module.has.search()) {
3792
+ module.hide(function () {
3793
+ module.remove.filteredItem();
3794
+ });
3795
+ } else {
3796
+ module.hide();
3797
+ }
3798
+ },
3799
+
3800
+ delay: {
3801
+ show: function () {
3802
+ module.verbose('Delaying show event to ensure user intent');
3803
+ clearTimeout(module.timer);
3804
+ module.timer = setTimeout(function () {
3805
+ module.show();
3806
+ }, settings.delay.show);
3807
+ },
3808
+ hide: function () {
3809
+ module.verbose('Delaying hide event to ensure user intent');
3810
+ clearTimeout(module.timer);
3811
+ module.timer = setTimeout(function () {
3812
+ module.hide();
3813
+ }, settings.delay.hide);
3814
+ },
3815
+ },
3816
+
3817
+ escape: {
3818
+ value: function (value) {
3819
+ var
3820
+ multipleValues = Array.isArray(value),
3821
+ stringValue = typeof value === 'string',
3822
+ isUnparsable = !stringValue && !multipleValues,
3823
+ hasQuotes = stringValue && value.search(regExp.quote) !== -1,
3824
+ values = []
3825
+ ;
3826
+ if (isUnparsable || !hasQuotes) {
3827
+ return value;
3828
+ }
3829
+ module.debug('Encoding quote values for use in select', value);
3830
+ if (multipleValues) {
3831
+ $.each(value, function (index, value) {
3832
+ values.push(value.replace(regExp.quote, '&quot;'));
3833
+ });
3834
+
3835
+ return values;
3836
+ }
3837
+
3838
+ return value.replace(regExp.quote, '&quot;');
3839
+ },
3840
+ string: function (text) {
3841
+ text = String(text);
3842
+
3843
+ return text.replace(regExp.escape, '\\$&');
3844
+ },
3845
+ htmlEntities: function (string, forceAmpersand) {
3846
+ forceAmpersand = typeof forceAmpersand === 'number' ? false : forceAmpersand;
3847
+ var
3848
+ badChars = /["'<>`]/g,
3849
+ shouldEscape = /["&'<>`]/,
3850
+ escape = {
3851
+ '<': '&lt;',
3852
+ '>': '&gt;',
3853
+ '"': '&quot;',
3854
+ "'": '&#x27;',
3855
+ '`': '&#x60;',
3856
+ },
3857
+ escapedChar = function (chr) {
3858
+ return escape[chr];
3859
+ }
3860
+ ;
3861
+ if (shouldEscape.test(string)) {
3862
+ string = string.replace(forceAmpersand ? /&/g : /&(?![\d#a-z]{1,12};)/gi, '&amp;');
3863
+ string = string.replace(badChars, escapedChar);
3864
+ }
3865
+
3866
+ return string;
3867
+ },
3868
+ },
3869
+
3870
+ setting: function (name, value) {
3871
+ module.debug('Changing setting', name, value);
3872
+ if ($.isPlainObject(name)) {
3873
+ $.extend(true, settings, name);
3874
+ } else if (value !== undefined) {
3875
+ if ($.isPlainObject(settings[name])) {
3876
+ $.extend(true, settings[name], value);
3877
+ } else {
3878
+ settings[name] = value;
3879
+ }
3880
+ } else {
3881
+ return settings[name];
3882
+ }
3883
+ },
3884
+ internal: function (name, value) {
3885
+ if ($.isPlainObject(name)) {
3886
+ $.extend(true, module, name);
3887
+ } else if (value !== undefined) {
3888
+ module[name] = value;
3889
+ } else {
3890
+ return module[name];
3891
+ }
3892
+ },
3893
+ debug: function () {
3894
+ if (!settings.silent && settings.debug) {
3895
+ if (settings.performance) {
3896
+ module.performance.log(arguments);
3897
+ } else {
3898
+ module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
3899
+ module.debug.apply(console, arguments);
3900
+ }
3901
+ }
3902
+ },
3903
+ verbose: function () {
3904
+ if (!settings.silent && settings.verbose && settings.debug) {
3905
+ if (settings.performance) {
3906
+ module.performance.log(arguments);
3907
+ } else {
3908
+ module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
3909
+ module.verbose.apply(console, arguments);
3910
+ }
3911
+ }
3912
+ },
3913
+ error: function () {
3914
+ if (!settings.silent) {
3915
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
3916
+ module.error.apply(console, arguments);
3917
+ }
3918
+ },
3919
+ performance: {
3920
+ log: function (message) {
3921
+ var
3922
+ currentTime,
3923
+ executionTime,
3924
+ previousTime
3925
+ ;
3926
+ if (settings.performance) {
3927
+ currentTime = Date.now();
3928
+ previousTime = time || currentTime;
3929
+ executionTime = currentTime - previousTime;
3930
+ time = currentTime;
3931
+ performance.push({
3932
+ Name: message[0],
3933
+ Arguments: [].slice.call(message, 1) || '',
3934
+ Element: element,
3935
+ 'Execution Time': executionTime,
3936
+ });
3937
+ }
3938
+ clearTimeout(module.performance.timer);
3939
+ module.performance.timer = setTimeout(function () {
3940
+ module.performance.display();
3941
+ }, 500);
3942
+ },
3943
+ display: function () {
3944
+ var
3945
+ title = settings.name + ':',
3946
+ totalTime = 0
3947
+ ;
3948
+ time = false;
3949
+ clearTimeout(module.performance.timer);
3950
+ $.each(performance, function (index, data) {
3951
+ totalTime += data['Execution Time'];
3952
+ });
3953
+ title += ' ' + totalTime + 'ms';
3954
+ if (performance.length > 0) {
3955
+ console.groupCollapsed(title);
3956
+ if (console.table) {
3957
+ console.table(performance);
3958
+ } else {
3959
+ $.each(performance, function (index, data) {
3960
+ console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
3961
+ });
3962
+ }
3963
+ console.groupEnd();
3964
+ }
3965
+ performance = [];
3966
+ },
3967
+ },
3968
+ invoke: function (query, passedArguments, context) {
3969
+ var
3970
+ object = instance,
3971
+ maxDepth,
3972
+ found,
3973
+ response
3974
+ ;
3975
+ passedArguments = passedArguments || queryArguments;
3976
+ context = context || element;
3977
+ if (typeof query === 'string' && object !== undefined) {
3978
+ query = query.split(/[ .]/);
3979
+ maxDepth = query.length - 1;
3980
+ $.each(query, function (depth, value) {
3981
+ var camelCaseValue = depth !== maxDepth
3982
+ ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
3983
+ : query
3984
+ ;
3985
+ if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
3986
+ object = object[camelCaseValue];
3987
+ } else if (object[camelCaseValue] !== undefined) {
3988
+ found = object[camelCaseValue];
3989
+
3990
+ return false;
3991
+ } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
3992
+ object = object[value];
3993
+ } else if (object[value] !== undefined) {
3994
+ found = object[value];
3995
+
3996
+ return false;
3997
+ } else {
3998
+ module.error(error.method, query);
3999
+
4000
+ return false;
4001
+ }
4002
+ });
4003
+ }
4004
+ if (isFunction(found)) {
4005
+ response = found.apply(context, passedArguments);
4006
+ } else if (found !== undefined) {
4007
+ response = found;
4008
+ }
4009
+ if (Array.isArray(returnedValue)) {
4010
+ returnedValue.push(response);
4011
+ } else if (returnedValue !== undefined) {
4012
+ returnedValue = [returnedValue, response];
4013
+ } else if (response !== undefined) {
4014
+ returnedValue = response;
4015
+ }
4016
+
4017
+ return found;
4018
+ },
4019
+ };
4020
+
4021
+ if (methodInvoked) {
4022
+ if (instance === undefined) {
4023
+ module.initialize();
4024
+ }
4025
+ module.invoke(query);
4026
+ } else {
4027
+ if (instance !== undefined) {
4028
+ instance.invoke('destroy');
4029
+ }
4030
+ module.initialize();
4031
+ }
4032
+ });
4033
+
4034
+ return returnedValue !== undefined
4035
+ ? returnedValue
4036
+ : $allModules;
4037
+ };
4038
+
4039
+ $.fn.dropdown.settings = {
4040
+
4041
+ silent: false,
4042
+ debug: false,
4043
+ verbose: false,
4044
+ performance: true,
4045
+
4046
+ on: 'click', // what event should show menu action on item selection
4047
+ action: 'activate', // action on item selection (nothing, activate, select, combo, hide, function(){})
4048
+
4049
+ values: false, // specify values to use for dropdown
4050
+
4051
+ clearable: false, // whether the value of the dropdown can be cleared
4052
+
4053
+ apiSettings: false,
4054
+ selectOnKeydown: true, // Whether selection should occur automatically when keyboard shortcuts used
4055
+ minCharacters: 0, // Minimum characters required to trigger API call
4056
+
4057
+ filterRemoteData: false, // Whether API results should be filtered after being returned for query term
4058
+ saveRemoteData: true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
4059
+
4060
+ throttle: 200, // How long to wait after last user input to search remotely
4061
+
4062
+ context: window, // Context to use when determining if on screen
4063
+ direction: 'auto', // Whether dropdown should always open in one direction
4064
+ keepOnScreen: true, // Whether dropdown should check whether it is on screen before showing
4065
+
4066
+ match: 'both', // what to match against with search selection (both, text, or label)
4067
+ fullTextSearch: 'exact', // search anywhere in value (set to 'exact' to require exact matches)
4068
+ highlightMatches: false, // Whether search result should highlight matching strings
4069
+ 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...)
4070
+ 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)
4071
+
4072
+ placeholder: 'auto', // whether to convert blank <select> values to placeholder text
4073
+ preserveHTML: true, // preserve html when selecting value
4074
+ sortSelect: false, // sort selection on init
4075
+
4076
+ forceSelection: false, // force a choice on blur with search selection
4077
+
4078
+ allowAdditions: false, // whether multiple select should allow user added values
4079
+ keepSearchTerm: false, // whether the search value should be kept and menu stays filtered on item selection
4080
+ ignoreCase: false, // whether to consider case sensitivity when creating labels
4081
+ ignoreSearchCase: true, // whether to consider case sensitivity when filtering items
4082
+ hideAdditions: true, // whether or not to hide special message prompting a user they can enter a value
4083
+
4084
+ maxSelections: false, // When set to a number limits the number of selections to this count
4085
+ useLabels: true, // whether multiple select should filter currently active selections from choices
4086
+ delimiter: ',', // when multiselect uses normal <input> the values will be delimited with this character
4087
+
4088
+ showOnFocus: false, // show menu on focus
4089
+ allowReselection: false, // whether current value should trigger callbacks when reselected
4090
+ allowTab: true, // add tabindex to element
4091
+ allowCategorySelection: false, // allow elements with sub-menus to be selected
4092
+
4093
+ fireOnInit: false, // Whether callbacks should fire when initializing dropdown values
4094
+
4095
+ transition: 'auto', // auto transition will slide down or up based on direction
4096
+ duration: 200, // duration of transition
4097
+ displayType: false, // displayType of transition
4098
+
4099
+ headerDivider: true, // whether option headers should have an additional divider line underneath when converted from <select> <optgroup>
4100
+
4101
+ collapseOnActionable: true, // whether the dropdown should collapse upon selection of an actionable item
4102
+ collapseOnClearable: false, // whether the dropdown should collapse upon clicking the clearable icon
4103
+
4104
+ // label settings on multi-select
4105
+ label: {
4106
+ transition: 'scale',
4107
+ duration: 200,
4108
+ variation: false,
4109
+ },
4110
+
4111
+ // delay before event
4112
+ delay: {
4113
+ hide: 300,
4114
+ show: 200,
4115
+ search: 20,
4116
+ },
4117
+
4118
+ /* Callbacks */
4119
+ onChange: function (value, text, $selected) {},
4120
+ onAdd: function (value, text, $selected) {},
4121
+ onRemove: function (value, text, $selected) {},
4122
+ onActionable: function (value, text, $selected) {},
4123
+ onSearch: function (searchTerm) {},
4124
+
4125
+ onLabelSelect: function ($selectedLabels) {},
4126
+ onLabelCreate: function (value, text) {
4127
+ return $(this);
4128
+ },
4129
+ onLabelRemove: function (value) {
4130
+ return true;
4131
+ },
4132
+ onNoResults: function (searchTerm) {
4133
+ return true;
4134
+ },
4135
+ onShow: function () {},
4136
+ onHide: function () {},
4137
+
4138
+ /* Component */
4139
+ name: 'Dropdown',
4140
+ namespace: 'dropdown',
4141
+
4142
+ message: {
4143
+ addResult: 'Add <b>{term}</b>',
4144
+ count: '{count} selected',
4145
+ maxSelections: 'Max {maxCount} selections',
4146
+ noResults: 'No results found.',
4147
+ serverError: 'There was an error contacting the server',
4148
+ },
4149
+
4150
+ error: {
4151
+ action: 'You called a dropdown action that was not defined',
4152
+ alreadySetup: 'Once a select has been initialized behaviors must be called on the created ui dropdown',
4153
+ labels: 'Allowing user additions currently requires the use of labels.',
4154
+ missingMultiple: '<select> requires multiple property to be set to correctly preserve multiple values',
4155
+ method: 'The method you called is not defined.',
4156
+ noAPI: 'The API module is required to load resources remotely',
4157
+ noStorage: 'Saving remote data requires session storage',
4158
+ noElement: 'This module requires ui {element}',
4159
+ noNormalize: '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.',
4160
+ },
4161
+
4162
+ regExp: {
4163
+ escape: /[\s#$()*+,.:=?@[\\\]^{|}-]/g,
4164
+ quote: /"/g,
4165
+ },
4166
+
4167
+ metadata: {
4168
+ defaultText: 'defaultText',
4169
+ defaultValue: 'defaultValue',
4170
+ placeholderText: 'placeholder',
4171
+ text: 'text',
4172
+ value: 'value',
4173
+ },
4174
+
4175
+ // property names for remote query
4176
+ fields: {
4177
+ remoteValues: 'results', // grouping for api results
4178
+ values: 'values', // grouping for all dropdown values
4179
+ disabled: 'disabled', // whether value should be disabled
4180
+ name: 'name', // displayed dropdown text
4181
+ description: 'description', // displayed dropdown description
4182
+ descriptionVertical: 'descriptionVertical', // whether description should be vertical
4183
+ value: 'value', // actual dropdown value
4184
+ text: 'text', // displayed text when selected
4185
+ data: 'data', // custom data attributes
4186
+ type: 'type', // type of dropdown element
4187
+ image: 'image', // optional image path
4188
+ imageClass: 'imageClass', // optional individual class for image
4189
+ alt: 'alt', // optional alt text for image
4190
+ icon: 'icon', // optional icon name
4191
+ iconClass: 'iconClass', // optional individual class for icon (for example to use flag instead)
4192
+ class: 'class', // optional individual class for item/header
4193
+ divider: 'divider', // optional divider append for group headers
4194
+ actionable: 'actionable', // optional actionable item
4195
+ },
4196
+
4197
+ keys: {
4198
+ backspace: 8,
4199
+ deleteKey: 46,
4200
+ enter: 13,
4201
+ escape: 27,
4202
+ pageUp: 33,
4203
+ pageDown: 34,
4204
+ leftArrow: 37,
4205
+ upArrow: 38,
4206
+ rightArrow: 39,
4207
+ downArrow: 40,
4208
+ },
4209
+
4210
+ selector: {
4211
+ addition: '.addition',
4212
+ divider: '.divider, .header',
4213
+ dropdown: '.ui.dropdown',
4214
+ hidden: '.hidden',
4215
+ icon: '> .dropdown.icon',
4216
+ input: '> input[type="hidden"], > select',
4217
+ item: '.item',
4218
+ label: '> .label',
4219
+ remove: '> .label > .delete.icon',
4220
+ siblingLabel: '.label',
4221
+ menu: '.menu',
4222
+ message: '.message',
4223
+ menuIcon: '.dropdown.icon',
4224
+ search: 'input.search, .menu > .search > input, .menu input.search',
4225
+ sizer: '> span.sizer',
4226
+ text: '> .text:not(.icon)',
4227
+ unselectable: '.disabled, .filtered',
4228
+ clearIcon: '> .remove.icon',
4229
+ },
4230
+
4231
+ className: {
4232
+ active: 'active',
4233
+ addition: 'addition',
4234
+ animating: 'animating',
4235
+ description: 'description',
4236
+ descriptionVertical: 'vertical',
4237
+ disabled: 'disabled',
4238
+ empty: 'empty',
4239
+ dropdown: 'ui dropdown',
4240
+ filtered: 'filtered',
4241
+ hidden: 'hidden transition',
4242
+ icon: 'icon',
4243
+ image: 'image',
4244
+ item: 'item',
4245
+ label: 'ui label',
4246
+ loading: 'loading',
4247
+ menu: 'menu',
4248
+ message: 'message',
4249
+ multiple: 'multiple',
4250
+ placeholder: 'default',
4251
+ sizer: 'sizer',
4252
+ search: 'search',
4253
+ selected: 'selected',
4254
+ selection: 'selection',
4255
+ text: 'text',
4256
+ upward: 'upward',
4257
+ leftward: 'left',
4258
+ visible: 'visible',
4259
+ clearable: 'clearable',
4260
+ noselection: 'noselection',
4261
+ delete: 'delete',
4262
+ header: 'header',
4263
+ divider: 'divider',
4264
+ groupIcon: '',
4265
+ unfilterable: 'unfilterable',
4266
+ actionable: 'actionable',
4267
+ },
4268
+
4269
+ };
4270
+
4271
+ /* Templates */
4272
+ $.fn.dropdown.settings.templates = {
4273
+ deQuote: function (string, encode) {
4274
+ return String(string).replace(/"/g, encode ? '&quot;' : '');
4275
+ },
4276
+ escape: function (string, preserveHTML) {
4277
+ if (preserveHTML) {
4278
+ return string;
4279
+ }
4280
+ var
4281
+ badChars = /["'<>`]/g,
4282
+ shouldEscape = /["&'<>`]/,
4283
+ escape = {
4284
+ '<': '&lt;',
4285
+ '>': '&gt;',
4286
+ '"': '&quot;',
4287
+ "'": '&#x27;',
4288
+ '`': '&#x60;',
4289
+ },
4290
+ escapedChar = function (chr) {
4291
+ return escape[chr];
4292
+ }
4293
+ ;
4294
+ if (shouldEscape.test(string)) {
4295
+ string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
4296
+ string = string.replace(badChars, escapedChar);
4297
+ }
4298
+
4299
+ return string;
4300
+ },
4301
+ // generates dropdown from select values
4302
+ dropdown: function (select, fields, preserveHTML, className) {
4303
+ var
4304
+ placeholder = select.placeholder || false,
4305
+ html = '',
4306
+ escape = $.fn.dropdown.settings.templates.escape,
4307
+ deQuote = $.fn.dropdown.settings.templates.deQuote
4308
+ ;
4309
+ html += '<i class="dropdown icon"></i>';
4310
+ html += placeholder
4311
+ ? '<div class="default text">' + escape(placeholder, preserveHTML) + '</div>'
4312
+ : '<div class="text"></div>';
4313
+ html += '<div class="' + deQuote(className.menu) + '">';
4314
+ html += $.fn.dropdown.settings.templates.menu(select, fields, preserveHTML, className);
4315
+ html += '</div>';
4316
+
4317
+ return html;
4318
+ },
4319
+
4320
+ // generates just menu from select
4321
+ menu: function (response, fields, preserveHTML, className) {
4322
+ var
4323
+ values = response[fields.values] || [],
4324
+ html = '',
4325
+ escape = $.fn.dropdown.settings.templates.escape,
4326
+ deQuote = $.fn.dropdown.settings.templates.deQuote
4327
+ ;
4328
+ $.each(values, function (index, option) {
4329
+ var
4330
+ itemType = option[fields.type] || 'item',
4331
+ isMenu = itemType.indexOf('menu') !== -1,
4332
+ maybeData = '',
4333
+ dataObject = option[fields.data]
4334
+ ;
4335
+ if (dataObject) {
4336
+ var dataKey,
4337
+ dataKeyEscaped
4338
+ ;
4339
+ for (dataKey in dataObject) {
4340
+ dataKeyEscaped = String(dataKey).replace(/\W/g, '');
4341
+ if (Object.prototype.hasOwnProperty.call(dataObject, dataKey) && ['text', 'value'].indexOf(dataKeyEscaped.toLowerCase()) === -1) {
4342
+ maybeData += ' data-' + dataKeyEscaped + '="' + deQuote(String(dataObject[dataKey])) + '"';
4343
+ }
4344
+ }
4345
+ }
4346
+ if (itemType === 'item' || isMenu) {
4347
+ var
4348
+ maybeText = option[fields.text]
4349
+ ? ' data-text="' + deQuote(option[fields.text], true) + '"'
4350
+ : '',
4351
+ maybeActionable = option[fields.actionable]
4352
+ ? className.actionable + ' '
4353
+ : '',
4354
+ maybeDisabled = option[fields.disabled]
4355
+ ? className.disabled + ' '
4356
+ : '',
4357
+ maybeDescriptionVertical = option[fields.descriptionVertical]
4358
+ ? className.descriptionVertical + ' '
4359
+ : '',
4360
+ hasDescription = escape(option[fields.description] || '', preserveHTML) !== ''
4361
+ ;
4362
+ html += '<div class="' + deQuote(maybeActionable + maybeDisabled + maybeDescriptionVertical + (option[fields.class] || className.item)) + '" data-value="' + deQuote(option[fields.value], true) + '"' + maybeText + maybeData + '>';
4363
+ if (isMenu) {
4364
+ html += '<i class="' + (itemType.indexOf('left') !== -1 ? 'left' : '') + ' dropdown icon"></i>';
4365
+ }
4366
+ if (option[fields.image]) {
4367
+ html += '<img class="' + deQuote(option[fields.imageClass] || className.image) + '" src="' + deQuote(option[fields.image]) + (option[fields.alt] ? '" alt="' + deQuote(option[fields.alt]) : '') + '">';
4368
+ }
4369
+ if (option[fields.icon]) {
4370
+ html += '<i class="' + deQuote(option[fields.icon] + ' ' + (option[fields.iconClass] || className.icon)) + '"></i>';
4371
+ }
4372
+ if (hasDescription) {
4373
+ html += '<span class="' + deQuote(className.description) + '">' + escape(option[fields.description] || '', preserveHTML) + '</span>';
4374
+ html += !isMenu ? '<span class="' + deQuote(className.text) + '">' : '';
4375
+ }
4376
+ if (isMenu) {
4377
+ html += '<span class="' + deQuote(className.text) + '">';
4378
+ }
4379
+ html += escape(option[fields.name] || '', preserveHTML);
4380
+ if (isMenu) {
4381
+ html += '</span>';
4382
+ html += '<div class="' + deQuote(itemType) + '">';
4383
+ html += $.fn.dropdown.settings.templates.menu(option, fields, preserveHTML, className);
4384
+ html += '</div>';
4385
+ } else if (hasDescription) {
4386
+ html += '</span>';
4387
+ }
4388
+ html += '</div>';
4389
+ } else if (itemType === 'header') {
4390
+ var
4391
+ groupName = escape(option[fields.name] || '', preserveHTML),
4392
+ groupIcon = deQuote(option[fields.icon] || className.groupIcon)
4393
+ ;
4394
+ if (groupName !== '' || groupIcon !== '') {
4395
+ html += '<div class="' + deQuote(option[fields.class] || className.header) + '">';
4396
+ if (groupIcon !== '') {
4397
+ html += '<i class="' + deQuote(groupIcon + ' ' + (option[fields.iconClass] || className.icon)) + '"></i>';
4398
+ }
4399
+ html += groupName;
4400
+ html += '</div>';
4401
+ }
4402
+ if (option[fields.divider]) {
4403
+ html += '<div class="' + deQuote(className.divider) + '"></div>';
4404
+ }
4405
+ }
4406
+ });
4407
+
4408
+ return html;
4409
+ },
4410
+
4411
+ // generates label for multiselect
4412
+ label: function (value, text, preserveHTML, className) {
4413
+ var
4414
+ escape = $.fn.dropdown.settings.templates.escape,
4415
+ deQuote = $.fn.dropdown.settings.templates.deQuote
4416
+ ;
4417
+
4418
+ return escape(text, preserveHTML) + '<i class="' + deQuote(className.delete) + ' icon"></i>';
4419
+ },
4420
+
4421
+ // generates messages like "No results"
4422
+ message: function (message) {
4423
+ return message;
4424
+ },
4425
+
4426
+ // generates user addition to selection menu
4427
+ addition: function (choice) {
4428
+ return choice;
4429
+ },
4430
+
4431
+ };
4432
+ })(jQuery, window, document);