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