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