/*!
* # Fomantic-UI 2.9.2 - Dropdown
* https://github.com/fomantic/Fomantic-UI/
*
*
* Released under the MIT license
* https://opensource.org/licenses/MIT
*
*/
(function ($, window, document) {
'use strict';
function isFunction(obj) {
return typeof obj === 'function' && typeof obj.nodeType !== 'number';
}
window = window !== undefined && window.Math === Math
? window
: globalThis;
$.fn.dropdown = function (parameters) {
var
$allModules = $(this),
$document = $(document),
moduleSelector = $allModules.selector || '',
time = Date.now(),
performance = [],
query = arguments[0],
methodInvoked = typeof query === 'string',
queryArguments = [].slice.call(arguments, 1),
returnedValue
;
$allModules.each(function (elementIndex) {
var
settings = $.isPlainObject(parameters)
? $.extend(true, {}, $.fn.dropdown.settings, parameters)
: $.extend({}, $.fn.dropdown.settings),
className = settings.className,
message = settings.message,
fields = settings.fields,
keys = settings.keys,
metadata = settings.metadata,
namespace = settings.namespace,
regExp = settings.regExp,
selector = settings.selector,
error = settings.error,
templates = settings.templates,
eventNamespace = '.' + namespace,
moduleNamespace = 'module-' + namespace,
$module = $(this),
$context = [window, document].indexOf(settings.context) < 0 ? $document.find(settings.context) : $(settings.context),
$text = $module.find(selector.text),
$search = $module.find(selector.search),
$sizer = $module.find(selector.sizer),
$input = $module.find(selector.input),
$icon = $module.find(selector.icon),
$clear = $module.find(selector.clearIcon),
$combo = $module.prev().find(selector.text).length > 0
? $module.prev().find(selector.text)
: $module.prev(),
$menu = $module.children(selector.menu),
$item = $menu.find(selector.item),
$divider = settings.hideDividers
? $item.parent().children(selector.divider)
: $(),
activated = false,
itemActivated = false,
internalChange = false,
iconClicked = false,
element = this,
focused = false,
instance = $module.data(moduleNamespace),
selectActionActive,
initialLoad,
pageLostFocus,
willRefocus,
elementNamespace,
id,
selectObserver,
menuObserver,
classObserver,
module
;
module = {
initialize: function () {
module.debug('Initializing dropdown', settings);
if (module.is.alreadySetup()) {
module.setup.reference();
} else {
if (settings.ignoreDiacritics && !String.prototype.normalize) {
settings.ignoreDiacritics = false;
module.error(error.noNormalize, element);
}
module.create.id();
module.setup.layout();
if (settings.values) {
module.set.initialLoad();
module.change.values(settings.values);
module.remove.initialLoad();
}
module.refreshData();
module.save.defaults();
module.restore.selected();
module.bind.events();
module.observeChanges();
module.instantiate();
}
},
instantiate: function () {
module.verbose('Storing instance of dropdown', module);
instance = module;
$module
.data(moduleNamespace, module)
;
},
destroy: function () {
module.verbose('Destroying previous dropdown', $module);
module.remove.tabbable();
module.remove.active();
$menu.transition('stop all');
$menu.removeClass(className.visible).addClass(className.hidden);
$module
.off(eventNamespace)
.removeData(moduleNamespace)
;
$menu
.off(eventNamespace)
;
$document
.off(elementNamespace)
;
module.disconnect.menuObserver();
module.disconnect.selectObserver();
module.disconnect.classObserver();
},
observeChanges: function () {
if ('MutationObserver' in window) {
selectObserver = new MutationObserver(module.event.select.mutation);
menuObserver = new MutationObserver(module.event.menu.mutation);
classObserver = new MutationObserver(module.event.class.mutation);
module.debug('Setting up mutation observer', selectObserver, menuObserver, classObserver);
module.observe.select();
module.observe.menu();
module.observe.class();
}
},
disconnect: {
menuObserver: function () {
if (menuObserver) {
menuObserver.disconnect();
}
},
selectObserver: function () {
if (selectObserver) {
selectObserver.disconnect();
}
},
classObserver: function () {
if (classObserver) {
classObserver.disconnect();
}
},
},
observe: {
select: function () {
if (module.has.input() && selectObserver) {
selectObserver.observe($module[0], {
attributes: true,
childList: true,
subtree: true,
});
}
},
menu: function () {
if (module.has.menu() && menuObserver) {
menuObserver.observe($menu[0], {
childList: true,
subtree: true,
});
}
},
class: function () {
if (module.has.search() && classObserver) {
classObserver.observe($module[0], {
attributes: true,
});
}
},
},
create: {
id: function () {
id = (Math.random().toString(16) + '000000000').slice(2, 10);
elementNamespace = '.' + id;
module.verbose('Creating unique id for element', id);
},
userChoice: function (values) {
var
$userChoices,
$userChoice,
html
;
values = values || module.get.userValues();
if (!values) {
return false;
}
values = Array.isArray(values)
? values
: [values];
$.each(values, function (index, value) {
if (module.get.item(value) === false) {
html = settings.templates.addition(module.add.variables(message.addResult, value));
$userChoice = $('
')
.html(html)
.attr('data-' + metadata.value, value)
.attr('data-' + metadata.text, value)
.addClass(className.addition)
.addClass(className.item)
;
if (settings.hideAdditions) {
$userChoice.addClass(className.hidden);
}
$userChoices = $userChoices === undefined
? $userChoice
: $userChoices.add($userChoice);
module.verbose('Creating user choices for value', value, $userChoice);
}
});
return $userChoices;
},
userLabels: function (value) {
var
userValues = module.get.userValues()
;
if (userValues) {
module.debug('Adding user labels', userValues);
$.each(userValues, function (index, value) {
module.verbose('Adding custom user value');
module.add.label(value, value);
});
}
},
menu: function () {
$menu = $('')
.addClass(className.menu)
.appendTo($module)
;
},
sizer: function () {
$sizer = $('')
.addClass(className.sizer)
.insertAfter($search)
;
},
},
search: function (query) {
query = query !== undefined
? query
: module.get.query();
module.verbose('Searching for query', query);
if (settings.fireOnInit === false && module.is.initialLoad()) {
module.verbose('Skipping callback on initial load', settings.onSearch);
} else if (module.has.minCharacters(query) && settings.onSearch.call(element, query) !== false) {
module.filter(query);
} else {
module.hide(null, true);
}
},
select: {
firstUnfiltered: function () {
module.verbose('Selecting first non-filtered element');
module.remove.selectedItem();
$item
.not(selector.unselectable)
.not(selector.addition + selector.hidden)
.eq(0)
.addClass(className.selected)
;
},
nextAvailable: function ($selected) {
$selected = $selected.eq(0);
var
$nextAvailable = $selected.nextAll(selector.item).not(selector.unselectable).eq(0),
$prevAvailable = $selected.prevAll(selector.item).not(selector.unselectable).eq(0),
hasNext = $nextAvailable.length > 0
;
if (hasNext) {
module.verbose('Moving selection to', $nextAvailable);
$nextAvailable.addClass(className.selected);
} else {
module.verbose('Moving selection to', $prevAvailable);
$prevAvailable.addClass(className.selected);
}
},
},
setup: {
api: function () {
var
apiSettings = {
debug: settings.debug,
urlData: {
value: module.get.value(),
query: module.get.query(),
},
on: false,
}
;
module.verbose('First request, initializing API');
$module
.api(apiSettings)
;
},
layout: function () {
if ($module.is('select')) {
module.setup.select();
module.setup.returnedObject();
}
if (!module.has.menu()) {
module.create.menu();
}
if (module.is.clearable() && !module.has.clearItem()) {
module.verbose('Adding clear icon');
$clear = $('')
.addClass('remove icon')
.insertBefore($text)
;
}
if (module.is.search() && !module.has.search()) {
module.verbose('Adding search input');
var
labelNode = $module.prev('label')
;
$search = $('')
.addClass(className.search)
.prop('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
;
if (labelNode.length > 0) {
if (!labelNode.attr('id')) {
labelNode.attr('id', '_' + module.get.id() + '_formLabel');
}
$search.attr('aria-labelledby', labelNode.attr('id'));
}
$search.insertBefore($text);
}
if (module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
module.create.sizer();
}
if (settings.allowTab) {
module.set.tabbable();
}
},
select: function () {
var
selectValues = module.get.selectValues()
;
module.debug('Dropdown initialized on a select', selectValues);
if ($module.is('select')) {
$input = $module;
}
// see if select is placed correctly already
if ($input.parent(selector.dropdown).length > 0) {
module.debug('UI dropdown already exists. Creating dropdown menu only');
$module = $input.closest(selector.dropdown);
if (!module.has.menu()) {
module.create.menu();
}
$menu = $module.children(selector.menu);
module.setup.menu(selectValues);
} else {
module.debug('Creating entire dropdown from select');
$module = $('')
.attr('class', $input.attr('class'))
.addClass(className.selection)
.addClass(className.dropdown)
.html(templates.dropdown(selectValues, fields, settings.preserveHTML, settings.className))
.insertBefore($input)
;
if ($input.hasClass(className.multiple) && $input.prop('multiple') === false) {
module.error(error.missingMultiple);
$input.prop('multiple', true);
}
if ($input.is('[multiple]')) {
module.set.multiple();
}
if ($input.prop('disabled')) {
module.debug('Disabling dropdown');
$module.addClass(className.disabled);
}
if ($input.is('[required]')) {
settings.forceSelection = true;
}
if (!settings.allowTab) {
$input.removeAttr('tabindex');
}
$input
.prop('required', false)
.removeAttr('class')
.detach()
.prependTo($module)
;
}
module.refresh();
},
menu: function (values) {
$menu.html(templates.menu(values, fields, settings.preserveHTML, settings.className));
$item = $menu.find(selector.item);
$divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
},
reference: function () {
module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
// replace module reference
$module = $module.parent(selector.dropdown);
instance = $module.data(moduleNamespace);
element = $module[0];
module.refresh();
module.setup.returnedObject();
},
returnedObject: function () {
var
$firstModules = $allModules.slice(0, elementIndex),
$lastModules = $allModules.slice(elementIndex + 1)
;
// adjust all modules to use correct reference
$allModules = $firstModules.add($module).add($lastModules);
},
},
refresh: function () {
module.refreshSelectors();
module.refreshData();
},
refreshItems: function () {
$item = $menu.find(selector.item);
$divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
},
refreshSelectors: function () {
module.verbose('Refreshing selector cache');
$text = $module.find(selector.text);
$search = $module.find(selector.search);
$input = $module.find(selector.input);
$icon = $module.find(selector.icon);
$combo = $module.prev().find(selector.text).length > 0
? $module.prev().find(selector.text)
: $module.prev();
$menu = $module.children(selector.menu);
$item = $menu.find(selector.item);
$divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
},
refreshData: function () {
module.verbose('Refreshing cached metadata');
$item
.removeData(metadata.text)
.removeData(metadata.value)
;
},
clearData: function () {
module.verbose('Clearing metadata');
$item
.removeData(metadata.text)
.removeData(metadata.value)
;
$module
.removeData(metadata.defaultText)
.removeData(metadata.defaultValue)
.removeData(metadata.placeholderText)
;
},
clearItems: function () {
$menu.empty();
module.refreshItems();
},
toggle: function () {
module.verbose('Toggling menu visibility');
if (!module.is.active()) {
module.show();
} else {
module.hide();
}
},
show: function (callback, preventFocus) {
callback = isFunction(callback)
? callback
: function () {};
if ((focused || iconClicked) && module.is.remote() && module.is.noApiCache()) {
module.clearItems();
}
if (!module.can.show() && module.is.remote()) {
module.debug('No API results retrieved, searching before show');
module.queryRemote(module.get.query(), module.show, [callback, preventFocus]);
}
if (module.can.show() && !module.is.active()) {
module.debug('Showing dropdown');
if (module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered())) {
module.remove.message();
}
if (module.is.allFiltered()) {
return true;
}
if (settings.onShow.call(element) !== false) {
module.remove.empty();
module.animate.show(function () {
module.bind.intent();
if (module.has.search() && !preventFocus) {
module.focusSearch();
}
module.set.visible();
callback.call(element);
});
}
}
},
hide: function (callback, preventBlur) {
callback = isFunction(callback)
? callback
: function () {};
if (module.is.active() && !module.is.animatingOutward()) {
module.debug('Hiding dropdown');
if (settings.onHide.call(element) !== false) {
module.animate.hide(function () {
module.remove.visible();
// hiding search focus
if (module.is.focusedOnSearch() && preventBlur !== true) {
$search.trigger('blur');
}
callback.call(element);
});
// Hide submenus explicitly. On some browsers (esp. mobile), they will not automatically receive a
// mouseleave event
var $subMenu = $module.find(selector.menu);
if ($subMenu.length > 0) {
module.verbose('Hiding sub-menu', $subMenu);
$subMenu.each(function () {
module.animate.hide(false, $(this));
});
}
}
} else {
module.unbind.intent();
}
iconClicked = false;
focused = false;
},
hideOthers: function () {
module.verbose('Finding other dropdowns to hide');
$allModules
.not($module)
.has(selector.menu + '.' + className.visible)
.dropdown('hide')
;
},
hideMenu: function () {
module.verbose('Hiding menu instantaneously');
module.remove.active();
module.remove.visible();
$menu.transition('destroy').transition('hide');
},
hideSubMenus: function () {
var
$subMenus = $menu.children(selector.item).find(selector.menu)
;
module.verbose('Hiding sub menus', $subMenus);
$subMenus.transition('hide');
},
bind: {
events: function () {
module.bind.keyboardEvents();
module.bind.inputEvents();
module.bind.mouseEvents();
},
keyboardEvents: function () {
module.verbose('Binding keyboard events');
$module
.on('keydown' + eventNamespace, module.event.keydown)
;
if (module.has.search()) {
$module
.on(module.get.inputEvent() + eventNamespace, selector.search, module.event.input)
;
}
if (module.is.multiple()) {
$document
.on('keydown' + elementNamespace, module.event.document.keydown)
;
}
},
inputEvents: function () {
module.verbose('Binding input change events');
$module
.on('change' + eventNamespace, selector.input, module.event.change)
;
if (module.is.multiple() && module.is.searchSelection()) {
$module
.on('paste' + eventNamespace, selector.search, module.event.paste)
;
}
},
mouseEvents: function () {
module.verbose('Binding mouse events');
if (module.is.multiple()) {
$module
.on('click' + eventNamespace, selector.label, module.event.label.click)
.on('click' + eventNamespace, selector.remove, module.event.remove.click)
;
}
if (module.is.searchSelection()) {
$module
.on('mousedown' + eventNamespace, module.event.mousedown)
.on('mouseup' + eventNamespace, module.event.mouseup)
.on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
.on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
.on('click' + eventNamespace, selector.icon, module.event.icon.click)
.on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
.on('focus' + eventNamespace, selector.search, module.event.search.focus)
.on('click' + eventNamespace, selector.search, module.event.search.focus)
.on('blur' + eventNamespace, selector.search, module.event.search.blur)
.on('click' + eventNamespace, selector.text, module.event.text.focus)
;
if (module.is.multiple()) {
$module
.on('click' + eventNamespace, module.event.click)
.on('click' + eventNamespace, module.event.search.focus)
;
}
} else {
if (settings.on === 'click') {
$module
.on('click' + eventNamespace, selector.icon, module.event.icon.click)
.on('click' + eventNamespace, module.event.test.toggle)
;
} else if (settings.on === 'hover') {
$module
.on('mouseenter' + eventNamespace, module.delay.show)
.on('mouseleave' + eventNamespace, module.delay.hide)
.on('touchstart' + eventNamespace, module.event.test.toggle)
.on('touchstart' + eventNamespace, selector.icon, module.event.icon.click)
;
} else {
$module
.on(settings.on + eventNamespace, module.toggle)
;
}
$module
.on('mousedown' + eventNamespace, module.event.mousedown)
.on('mouseup' + eventNamespace, module.event.mouseup)
.on('focus' + eventNamespace, module.event.focus)
.on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
;
if (module.has.menuSearch()) {
$module
.on('blur' + eventNamespace, selector.search, module.event.search.blur)
;
} else {
$module
.on('blur' + eventNamespace, module.event.blur)
;
}
}
$menu
.on('mouseenter' + eventNamespace, selector.item, module.event.item.mouseenter)
.on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
.on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
.on('click' + eventNamespace, selector.item, module.event.item.click)
;
},
intent: function () {
module.verbose('Binding hide intent event to document');
$document
.on('click' + elementNamespace, module.event.test.hide)
;
},
},
unbind: {
intent: function () {
module.verbose('Removing hide intent event from document');
$document
.off('click' + elementNamespace)
;
},
},
filter: function (query) {
var
searchTerm = query !== undefined
? query
: module.get.query(),
afterFiltered = function () {
if (module.is.multiple()) {
module.filterActive();
}
if (query || (!query && module.get.activeItem().length === 0)) {
module.select.firstUnfiltered();
}
if (module.has.allResultsFiltered()) {
if (settings.onNoResults.call(element, searchTerm)) {
if (settings.allowAdditions) {
if (settings.hideAdditions) {
module.verbose('User addition with no menu, setting empty style');
module.set.empty();
module.hideMenu();
}
} else {
module.verbose('All items filtered, showing message', searchTerm);
module.add.message(message.noResults);
}
} else {
module.verbose('All items filtered, hiding dropdown', searchTerm);
module.set.empty();
module.hideMenu();
}
} else {
module.remove.empty();
module.remove.message();
}
if (settings.allowAdditions) {
module.add.userSuggestion(module.escape.htmlEntities(query));
}
if (module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() && !module.is.empty()) {
module.show();
}
}
;
if (settings.useLabels && module.has.maxSelections()) {
return;
}
if (settings.apiSettings) {
if (module.can.useAPI()) {
module.queryRemote(searchTerm, function () {
if (settings.filterRemoteData) {
module.filterItems(searchTerm);
}
var preSelected = $input.val();
if (!Array.isArray(preSelected)) {
preSelected = preSelected && preSelected !== '' ? preSelected.split(settings.delimiter) : [];
}
if (module.is.multiple()) {
$.each(preSelected, function (index, value) {
$item.filter('[data-value="' + value + '"]')
.addClass(className.filtered)
;
});
}
module.focusSearch(true);
afterFiltered();
});
} else {
module.error(error.noAPI);
}
} else {
module.filterItems(searchTerm);
afterFiltered();
}
},
queryRemote: function (query, callback, callbackParameters) {
if (!Array.isArray(callbackParameters)) {
callbackParameters = [callbackParameters];
}
var
apiSettings = {
errorDuration: false,
cache: 'local',
throttle: settings.throttle,
urlData: {
query: query,
},
},
apiCallbacks = {
onError: function (errorMessage, $module, xhr) {
module.add.message(message.serverError);
iconClicked = false;
focused = false;
callback.apply(null, callbackParameters);
if (typeof settings.apiSettings.onError === 'function') {
settings.apiSettings.onError.call(this, errorMessage, $module, xhr);
}
},
onFailure: function (response, $module, xhr) {
module.add.message(message.serverError);
iconClicked = false;
focused = false;
callback.apply(null, callbackParameters);
if (typeof settings.apiSettings.onFailure === 'function') {
settings.apiSettings.onFailure.call(this, response, $module, xhr);
}
},
onSuccess: function (response, $module, xhr) {
var
values = response[fields.remoteValues]
;
if (!Array.isArray(values)) {
values = [];
}
module.remove.message();
var menuConfig = {};
menuConfig[fields.values] = values;
module.setup.menu(menuConfig);
if (values.length === 0 && !settings.allowAdditions) {
module.add.message(message.noResults);
} else {
var value = module.is.multiple() ? module.get.values() : module.get.value();
if (value !== '') {
module.verbose('Value(s) present after click icon, select value(s) in items');
module.set.selected(value, null, true, true);
}
}
iconClicked = false;
focused = false;
callback.apply(null, callbackParameters);
if (typeof settings.apiSettings.onSuccess === 'function') {
settings.apiSettings.onSuccess.call(this, response, $module, xhr);
}
},
}
;
if (!$module.api('get request')) {
module.setup.api();
}
apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings, apiCallbacks);
$module
.api('setting', apiSettings)
.api('query')
;
},
filterItems: function (query) {
var
searchTerm = module.remove.diacritics(
query !== undefined
? query
: module.get.query()
),
results = null,
escapedTerm = module.escape.string(searchTerm),
regExpFlags = (settings.ignoreSearchCase ? 'i' : '') + 'gm',
beginsWithRegExp = new RegExp('^' + escapedTerm, regExpFlags)
;
// avoid loop if we're matching nothing
if (module.has.query()) {
results = [];
module.verbose('Searching for matching values', searchTerm);
$item
.each(function () {
var
$choice = $(this),
text,
value
;
if ($choice.hasClass(className.unfilterable)) {
results.push(this);
return true;
}
if (settings.match === 'both' || settings.match === 'text') {
text = module.remove.diacritics(String(module.get.choiceText($choice, false)));
if (text.search(beginsWithRegExp) !== -1
|| (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text))
|| (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text))
) {
results.push(this);
return true;
}
}
if (settings.match === 'both' || settings.match === 'value') {
value = module.remove.diacritics(String(module.get.choiceValue($choice, text)));
if (value.search(beginsWithRegExp) !== -1
|| (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value))
|| (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value))
) {
results.push(this);
return true;
}
}
})
;
}
module.debug('Showing only matched items', searchTerm);
module.remove.filteredItem();
if (results) {
$item
.not(results)
.addClass(className.filtered)
;
}
if (!module.has.query()) {
$divider
.removeClass(className.hidden)
;
} else if (settings.hideDividers === true) {
$divider
.addClass(className.hidden)
;
} else if (settings.hideDividers === 'empty') {
$divider
.removeClass(className.hidden)
.filter(function () {
// First find the last divider in this divider group
// Dividers which are direct siblings are considered a group
var $lastDivider = $(this).nextUntil(selector.item);
return ($lastDivider.length > 0 ? $lastDivider : $(this))
// Count all non-filtered items until the next divider (or end of the dropdown)
.nextUntil(selector.divider)
.filter(selector.item + ':not(.' + className.filtered + ')')
// Hide divider if no items are found
.length === 0;
})
.addClass(className.hidden)
;
}
},
fuzzySearch: function (query, term) {
var
termLength = term.length,
queryLength = query.length
;
query = settings.ignoreSearchCase ? query.toLowerCase() : query;
term = settings.ignoreSearchCase ? term.toLowerCase() : term;
if (queryLength > termLength) {
return false;
}
if (queryLength === termLength) {
return query === term;
}
for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
var
continueSearch = false,
queryCharacter = query.charCodeAt(characterIndex)
;
while (nextCharacterIndex < termLength) {
if (term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
continueSearch = true;
break;
}
}
if (!continueSearch) {
return false;
}
}
return true;
},
exactSearch: function (query, term) {
query = settings.ignoreSearchCase ? query.toLowerCase() : query;
term = settings.ignoreSearchCase ? term.toLowerCase() : term;
return term.indexOf(query) > -1;
},
filterActive: function () {
if (settings.useLabels) {
$item.filter('.' + className.active)
.addClass(className.filtered)
;
}
},
focusSearch: function (skipHandler) {
if (module.has.search() && !module.is.focusedOnSearch()) {
if (skipHandler) {
$module.off('focus' + eventNamespace, selector.search);
$search.trigger('focus');
$module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
} else {
$search.trigger('focus');
}
}
},
blurSearch: function () {
if (module.has.search()) {
$search.trigger('blur');
}
},
forceSelection: function () {
var
$currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
$activeItem = $item.not(className.filtered).filter('.' + className.active).eq(0),
$selectedItem = $currentlySelected.length > 0
? $currentlySelected
: $activeItem,
hasSelected = $selectedItem.length > 0
;
if (settings.allowAdditions || (hasSelected && !module.is.multiple())) {
module.debug('Forcing partial selection to selected item', $selectedItem);
module.event.item.click.call($selectedItem, {}, true);
} else {
module.remove.searchTerm();
}
},
change: {
values: function (values) {
if (!settings.allowAdditions) {
module.clear();
}
module.debug('Creating dropdown with specified values', values);
var menuConfig = {};
menuConfig[fields.values] = values;
module.setup.menu(menuConfig);
$.each(values, function (index, item) {
if (item.selected === true) {
module.debug('Setting initial selection to', item[fields.value]);
module.set.selected(item[fields.value]);
if (!module.is.multiple()) {
return false;
}
}
});
if (module.has.selectInput()) {
module.disconnect.selectObserver();
$input.html('');
$input.append('');
$.each(values, function (index, item) {
var
value = settings.templates.deQuote(item[fields.value]),
name = settings.templates.escape(
item[fields.name] || '',
settings.preserveHTML
)
;
$input.append('');
});
module.observe.select();
}
},
},
event: {
paste: function (event) {
var
pasteValue = (event.originalEvent.clipboardData || window.clipboardData).getData('text'),
tokens = pasteValue.split(settings.delimiter),
notFoundTokens = []
;
tokens.forEach(function (value) {
if (module.set.selected(module.escape.htmlEntities(value.trim()), null, true, true) === false) {
notFoundTokens.push(value);
}
});
event.preventDefault();
if (notFoundTokens.length > 0) {
var searchEl = $search[0],
startPos = searchEl.selectionStart,
endPos = searchEl.selectionEnd,
orgText = searchEl.value,
pasteText = notFoundTokens.join(settings.delimiter),
newEndPos = startPos + pasteText.length
;
$search.val(orgText.slice(0, startPos) + pasteText + orgText.slice(endPos));
searchEl.selectionStart = newEndPos;
searchEl.selectionEnd = newEndPos;
module.event.input(event);
}
},
change: function () {
if (!internalChange) {
module.debug('Input changed, updating selection');
module.set.selected();
}
},
focus: function () {
if (settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
focused = true;
module.show();
}
},
blur: function (event) {
pageLostFocus = document.activeElement === this;
if (!activated && !pageLostFocus) {
module.remove.activeLabel();
module.hide();
}
},
mousedown: function () {
if (module.is.searchSelection(true)) {
// prevent menu hiding on immediate re-focus
willRefocus = true;
} else {
// prevents focus callback from occurring on mousedown
activated = true;
}
},
mouseup: function () {
if (module.is.searchSelection(true)) {
// prevent menu hiding on immediate re-focus
willRefocus = false;
} else {
activated = false;
}
},
click: function (event) {
var
$target = $(event.target)
;
// focus search
if ($target.is($module)) {
if (!module.is.focusedOnSearch()) {
module.focusSearch();
} else {
module.show();
}
}
},
search: {
focus: function (event) {
activated = true;
if (module.is.multiple()) {
module.remove.activeLabel();
}
if (!focused && !module.is.active() && (settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin')) && event.type !== 'touchstart') {
focused = true;
module.search();
}
},
blur: function (event) {
pageLostFocus = document.activeElement === this;
if (module.is.searchSelection(true) && !willRefocus) {
if (!itemActivated && !pageLostFocus) {
if (settings.forceSelection) {
module.forceSelection();
} else if (!settings.allowAdditions) {
module.remove.searchTerm();
}
module.hide();
}
}
willRefocus = false;
},
},
clearIcon: {
click: function (event) {
module.clear();
if (module.is.searchSelection()) {
module.remove.searchTerm();
}
module.hide();
event.stopPropagation();
},
},
icon: {
click: function (event) {
iconClicked = true;
if (module.has.search()) {
if (!module.is.active()) {
if (settings.showOnFocus) {
module.focusSearch();
} else {
module.toggle();
}
} else {
module.blurSearch();
}
} else {
module.toggle();
}
event.stopPropagation();
},
},
text: {
focus: function (event) {
activated = true;
module.focusSearch();
},
},
input: function (event) {
if (module.is.multiple() || module.is.searchSelection()) {
module.set.filtered();
}
clearTimeout(module.timer);
module.timer = setTimeout(module.search, settings.delay.search);
},
label: {
click: function (event) {
var
$label = $(this),
$labels = $module.find(selector.label),
$activeLabels = $labels.filter('.' + className.active),
$nextActive = $label.nextAll('.' + className.active),
$prevActive = $label.prevAll('.' + className.active),
$range = $nextActive.length > 0
? $label.nextUntil($nextActive).add($activeLabels).add($label)
: $label.prevUntil($prevActive).add($activeLabels).add($label)
;
if (event.shiftKey) {
$activeLabels.removeClass(className.active);
$range.addClass(className.active);
} else if (event.ctrlKey) {
$label.toggleClass(className.active);
} else {
$activeLabels.removeClass(className.active);
$label.addClass(className.active);
}
settings.onLabelSelect.apply(this, $labels.filter('.' + className.active));
event.stopPropagation();
},
},
remove: {
click: function (event) {
var
$label = $(this).parent()
;
if ($label.hasClass(className.active)) {
// remove all selected labels
module.remove.activeLabels();
} else {
// remove this label only
module.remove.activeLabels($label);
}
event.stopPropagation();
},
},
test: {
toggle: function (event) {
var
toggleBehavior = module.is.multiple()
? module.show
: module.toggle
;
if (module.is.bubbledLabelClick(event) || module.is.bubbledIconClick(event)) {
return;
}
if (!module.is.multiple() || (module.is.multiple() && !module.is.active())) {
focused = true;
}
if (module.determine.eventOnElement(event, toggleBehavior) && event.type !== 'touchstart') {
// do not preventDefault of touchstart; so emulated mouseenter is triggered on first touch and not later
// (when selecting an item). The double-showing of the dropdown through both events does not hurt.
event.preventDefault();
}
},
hide: function (event) {
if (module.determine.eventInModule(event, module.hide)) {
if (element.id && $(event.target).attr('for') === element.id) {
event.preventDefault();
}
}
},
},
class: {
mutation: function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.attributeName === 'class') {
module.check.disabled();
}
});
},
},
select: {
mutation: function (mutations) {
if (module.is.selectMutation(mutations)) {
module.debug('