bootstrap-select-dropdown
Version:
A jQuery plugin for Bootstrap 4 that converts <select> and <select multiselect> elements to dropdowns. Uses fuse.js for fuzzy search and Bootstrap's dropdown plugin.
1,677 lines (1,423 loc) • 54.1 kB
JavaScript
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 2);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = $;
/***/ }),
/* 1 */
/***/ (function(module, exports) {
module.exports = Fuse;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(3);
/***/ }),
/* 3 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: external "$"
var external_$_ = __webpack_require__(0);
var external_$_default = /*#__PURE__*/__webpack_require__.n(external_$_);
// CONCATENATED MODULE: ./node_modules/bootstrap/js/src/util.js
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.4.1): util.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Private TransitionEnd Helpers
* ------------------------------------------------------------------------
*/
const TRANSITION_END = 'transitionend'
const MAX_UID = 1000000
const MILLISECONDS_MULTIPLIER = 1000
// Shoutout AngusCroll (https://goo.gl/pxwQGp)
function toType(obj) {
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase()
}
function getSpecialTransitionEndEvent() {
return {
bindType: TRANSITION_END,
delegateType: TRANSITION_END,
handle(event) {
if (external_$_default()(event.target).is(this)) {
return event.handleObj.handler.apply(this, arguments) // eslint-disable-line prefer-rest-params
}
return undefined // eslint-disable-line no-undefined
}
}
}
function transitionEndEmulator(duration) {
let called = false
external_$_default()(this).one(Util.TRANSITION_END, () => {
called = true
})
setTimeout(() => {
if (!called) {
Util.triggerTransitionEnd(this)
}
}, duration)
return this
}
function setTransitionEndSupport() {
external_$_default.a.fn.emulateTransitionEnd = transitionEndEmulator
external_$_default.a.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent()
}
/**
* --------------------------------------------------------------------------
* Public Util Api
* --------------------------------------------------------------------------
*/
const Util = {
TRANSITION_END: 'bsTransitionEnd',
getUID(prefix) {
do {
// eslint-disable-next-line no-bitwise
prefix += ~~(Math.random() * MAX_UID) // "~~" acts like a faster Math.floor() here
} while (document.getElementById(prefix))
return prefix
},
getSelectorFromElement(element) {
let selector = element.getAttribute('data-target')
if (!selector || selector === '#') {
const hrefAttr = element.getAttribute('href')
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''
}
try {
return document.querySelector(selector) ? selector : null
} catch (err) {
return null
}
},
getTransitionDurationFromElement(element) {
if (!element) {
return 0
}
// Get transition-duration of the element
let transitionDuration = external_$_default()(element).css('transition-duration')
let transitionDelay = external_$_default()(element).css('transition-delay')
const floatTransitionDuration = parseFloat(transitionDuration)
const floatTransitionDelay = parseFloat(transitionDelay)
// Return 0 if element or transition duration is not found
if (!floatTransitionDuration && !floatTransitionDelay) {
return 0
}
// If multiple durations are defined, take the first
transitionDuration = transitionDuration.split(',')[0]
transitionDelay = transitionDelay.split(',')[0]
return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
},
reflow(element) {
return element.offsetHeight
},
triggerTransitionEnd(element) {
external_$_default()(element).trigger(TRANSITION_END)
},
// TODO: Remove in v5
supportsTransitionEnd() {
return Boolean(TRANSITION_END)
},
isElement(obj) {
return (obj[0] || obj).nodeType
},
typeCheckConfig(componentName, config, configTypes) {
for (const property in configTypes) {
if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
const expectedTypes = configTypes[property]
const value = config[property]
const valueType = value && Util.isElement(value)
? 'element' : toType(value)
if (!new RegExp(expectedTypes).test(valueType)) {
throw new Error(
`${componentName.toUpperCase()}: ` +
`Option "${property}" provided type "${valueType}" ` +
`but expected type "${expectedTypes}".`)
}
}
}
},
findShadowRoot(element) {
if (!document.documentElement.attachShadow) {
return null
}
// Can find the shadow root otherwise it'll return the document
if (typeof element.getRootNode === 'function') {
const root = element.getRootNode()
return root instanceof ShadowRoot ? root : null
}
if (element instanceof ShadowRoot) {
return element
}
// when we don't find a shadow root
if (!element.parentNode) {
return null
}
return Util.findShadowRoot(element.parentNode)
},
jQueryDetection() {
if (typeof external_$_default.a === 'undefined') {
throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.')
}
const version = external_$_default.a.fn.jquery.split(' ')[0].split('.')
const minMajor = 1
const ltMajor = 2
const minMinor = 9
const minPatch = 1
const maxMajor = 4
if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {
throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0')
}
}
}
Util.jQueryDetection()
setTransitionEndSupport()
/* harmony default export */ var util = (Util);
// EXTERNAL MODULE: external "Fuse"
var external_Fuse_ = __webpack_require__(1);
var external_Fuse_default = /*#__PURE__*/__webpack_require__.n(external_Fuse_);
// CONCATENATED MODULE: ./src/js/bootstrap-select-dropdown.js
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var SelectDropdownIndex = 1;
/**
* --------------------------------------------------------------------------
* Bootstrap Select Dropdown
* --------------------------------------------------------------------------
*/
var bootstrap_select_dropdown_SelectDropdown = function ($) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'selectDropdown';
var VERSION = '0.14.6';
var DATA_KEY = 'bs.selectDropdown';
var EVENT_KEY = ".".concat(DATA_KEY);
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $.fn[NAME];
var KEYUP_TIMEOUT = 300;
var ENTER_KEYCODE = 13;
var ESCAPE_KEYCODE = 27;
var ARROW_UP_KEYCODE = 38;
var ARROW_DOWN_KEYCODE = 40;
var Default = {
// Profile
profile: "default",
// Behaviour
hideSelect: true,
search: true,
maxHeight: '300px',
keyboard: true,
badges: true,
// Multiselect only
badgesDismissable: true,
// Multiselect only
maxListLength: 0,
// Multiselect only
// Text
textNoneSelected: "Select",
textMultipleSelected: "%count_selected% selected",
textNoResults: "No results",
// Controls
deselectAll: true,
// Multiselect only
selectAll: true,
// Multiselect only
showSelected: true,
// Multiselect only
// Buttons
selectButtons: false,
classBtnDeselectAll: "btn btn-outline-secondary",
// Multiselect only
classBtnSelectAll: "btn btn-outline-secondary",
// Multiselect only
// HTML
htmlClear: "Clear search",
htmlDeselectAll: "Deselect all",
// Multiselect only
htmlSelectAll: "Select all",
// Multiselect only
htmlBadgeRemove: "[X]",
// Badges only
// Classes
classBtnSelect: "btn btn-primary",
classBadge: "badge badge-dark mr-1 mb-1",
classBadgeLink: "text-white",
classBadgeContainer: "mt-2 mb-3",
// Callbacks
loaded: function loaded() {}
};
var DefaultType = {
maxListLength: 'number',
hideSelect: 'boolean',
search: 'boolean',
maxHeight: 'string',
keyboard: 'boolean',
badges: 'boolean',
badgesDismissable: 'boolean',
textNoneSelected: 'string',
textMultipleSelected: 'string',
textNoResults: 'string',
deselectAll: 'boolean',
selectAll: 'boolean',
selectButtons: 'boolean',
classBtnDeselectAll: 'string',
classBtnSelectAll: 'string',
htmlClear: 'string',
htmlDeselectAll: 'string',
htmlSelectAll: 'string',
htmlBadgeRemove: 'string',
classBtnSelect: 'string',
classBadge: 'string',
classBadgeLink: 'string',
classBadgeContainer: 'string',
loaded: 'function'
};
var Event = {
CLICK: "click".concat(EVENT_KEY),
KEYUP: "keyup".concat(EVENT_KEY),
KEYDOWN: "keydown".concat(EVENT_KEY),
FOCUS: "focus".concat(EVENT_KEY),
BLUR: "blur".concat(EVENT_KEY),
FOCUSIN: "focusin".concat(EVENT_KEY),
LOAD_DATA_API: "load".concat(EVENT_KEY).concat(DATA_API_KEY)
};
var ClassName = {
ACTIVE: 'active',
BG_TRANSPARENT: 'bg-transparent',
DISABLED: 'disabled',
DROPDOWN: 'dropdown',
MENU: 'dropdown-menu',
ITEM: 'dropdown-item',
BTN_GROUP: 'btn-group',
INPUT_GROUP: 'input-group',
INPUT_GROUP_APPEND: 'input-group-append',
HOVER: 'hover',
HOVER_BG: 'bg-light',
TEXT_MUTED: 'text-muted',
ALIGNMENT_RIGHT: 'dropdown-menu-right'
};
var Selector = {
DATA_ROLE: '[data-role="select-dropdown"]'
};
var Keyword = {
COUNT_SELECTED: '%count_selected%'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var SelectDropdown =
/*#__PURE__*/
function () {
function SelectDropdown(element, config) {
var _this = this;
_classCallCheck(this, SelectDropdown);
this._multiselect = this._isMultiselect(element);
this._config = this._getConfig(config);
this._element = element;
this._prefix = "bsd" + this._config.SelectDropdownIndex + "-" + Math.random().toString(36).substring(7) + "-";
this._indexes = [];
this._lastSearch = null;
this._resultsChanged = false;
this._hoverItem = $();
this._keyupTimeout = null;
this.ids = {};
this.ids.dropdownContainerId = this._prefix + 'container';
this.ids.dropdownButtonId = this._prefix + 'button';
this.ids.controlSearchId = this._prefix + 'search';
this.ids.dropdownItemDeselect = this._prefix + 'deselect';
this.ids.dropdownItemShowSelected = this._prefix + 'selected'; // Selectors.
this.selectors = {};
if (this._config.badges) {
this.selectors.badge = this._classListToSelector(this._config.classBadge);
} // Properties: Elements.
this.els = {};
this.els.btnSelect = this._buildBtnSelect();
if (this._config.search) {
this.els.controlSearch = this._buildControlSearch();
this.els.clear = this._buildControlClear();
}
if (this._config.deselectAll) {
this.els.deselectAll = this._buildDeselectAll();
}
if (this._config.selectAll) {
this.els.selectAll = this._buildSelectAll();
}
this.els.showSelected = this._buildShowSelected();
this.els.dropdown = this._buildDropdown();
this.els.dropdownMenu = this._buildDropdownMenu(); //This should be dropdown menu so we can build and refer to dropdown, the main container.
this.els.dropdownItemsContainer = this._buildDropdownItemsContainer();
this.els.dropdownItemNoResults = this._buildDropdownItemNoResults();
this.els.dropdownItems = this._buildDropdownItems();
this.els.dropdownOptions = this.els.dropdownItems.filter(function (index, element) {
return _this._isOption($(element));
});
if (this._config.badges) {
this.els.badgeContainer = this._buildBadgeContainer();
}
if (this._config.search) {
this._hideClear();
this._haystack = [];
this._fuseOptions = {
keys: ['text'],
id: 'index'
};
this.els.dropdownOptions.each(function (index, element) {
_this._haystack[index] = {
index: $(element).data('index'),
text: $(element).text()
};
});
}
this._addEventListeners();
this.init();
} // Getters
_createClass(SelectDropdown, [{
key: "toggle",
// Public
/**
* Select/Deselect a dropdown item, and update the corresponding option.
* @param {object} $dropdownItem jQuery object
* @return {undefined}
*/
value: function toggle($dropdownItem) {
var $el = $(this._element);
var itemIndex = $dropdownItem.data('option');
var $option = $el.find('option').eq(itemIndex);
if ($option.is(':selected')) {
$option.prop('selected', false);
$dropdownItem.removeClass(ClassName.ACTIVE);
} else {
if (!this._multiselect) {
this.els.dropdownOptions.removeClass(ClassName.ACTIVE);
}
$option.prop('selected', true);
$dropdownItem.removeClass(ClassName.HOVER_BG).addClass(ClassName.ACTIVE);
}
this._externalFeedback();
}
/**
* Deselect a dropdown item.
* @param {object} $dropdownItem jQuery
* @return {undefined}
*/
}, {
key: "deselect",
value: function deselect($dropdownItem) {
var $el = $(this._element);
var itemIndex = $dropdownItem.data('option');
var $option = $el.find('option').eq(itemIndex);
if ($option.is(':selected')) {
this.toggle($dropdownItem);
}
}
/**
* Select a dropdown item.
* @param {object} $dropdownItem jQuery
* @return {undefined}
*/
}, {
key: "select",
value: function select($dropdownItem) {
var $el = $(this._element);
var itemIndex = $dropdownItem.data('option');
var $option = $el.find('option').eq(itemIndex);
if (!$option.is(':selected')) {
this.toggle($dropdownItem);
}
}
/**
* Deselect all dropdown items.
* @return {undefined}
*/
}, {
key: "deselectAll",
value: function deselectAll() {
var $el = $(this._element);
$el.find('option').prop('selected', false);
this.els.dropdownOptions.removeClass(ClassName.ACTIVE);
this._externalFeedback();
this._refresh();
}
/**
* Select all dropdown items.
* @return {undefined}
*/
}, {
key: "selectAll",
value: function selectAll() {
var $el = $(this._element);
$el.find('option').prop('selected', true);
this.els.dropdownOptions.removeClass(ClassName.HOVER_BG).addClass(ClassName.ACTIVE);
this._externalFeedback();
this._refresh();
} // Private
}, {
key: "_getConfig",
value: function _getConfig(config) {
if (config.profile == 'minimal') {
if (_typeof(config.search) !== ( true ? "undefined" : undefined)) {
config.search = false;
}
if (_typeof(config.badges) !== ( true ? "undefined" : undefined)) {
config.badges = false;
}
if (_typeof(config.deselectAll) !== ( true ? "undefined" : undefined)) {
config.deselectAll = false;
}
if (_typeof(config.selectAll) !== ( true ? "undefined" : undefined)) {
config.selectAll = false;
}
if (_typeof(config.showSelected) !== ( true ? "undefined" : undefined)) {
config.showSelected = false;
}
}
config = _objectSpread({}, Default, {}, config);
util.typeCheckConfig(NAME, config, DefaultType);
if (!this._multiselect) {
config.deselectAll = false;
config.selectAll = false;
config.showSelected = false;
config.badges = false;
}
return config;
}
}, {
key: "_addEventListeners",
value: function _addEventListeners() {
var _this2 = this;
if (this._config.search) {
this.els.controlSearch.on(Event.KEYUP, function (event) {
if (_this2._config.keyboard) {
_this2._keyupNav(event);
}
clearTimeout(_this2._keyupTimeout);
_this2._keyupTimeout = setTimeout(function () {
var s = $(_this2.els.controlSearch).val();
_this2._search(s);
}, KEYUP_TIMEOUT);
});
this.els.controlSearch.on(Event.FOCUS, function (event) {
_this2._hoverSet();
if (_this2.els.btnSelect.attr('aria-expanded') == 'false') {
_this2.els.btnSelect.dropdown('toggle');
setTimeout(function () {
_this2._searchControlFocus();
}, 1);
}
});
this.els.controlSearch.on(Event.BLUR, function (event) {
_this2._hoverRemoveAll();
}); // Handle cut and paste.
this.els.controlSearch.bind({
paste: function paste() {
$(this).trigger(Event.KEYDOWN);
},
cut: function cut() {
$(this).trigger(Event.KEYDOWN);
}
});
}
this._assignClickHandlers();
}
}, {
key: "_keyupNav",
value: function _keyupNav(event) {
if (event.which == ENTER_KEYCODE) {
this.toggle(this.els.dropdown.find('.hover').first());
if (!this._multiselect) {
this.els.btnSelect.dropdown('toggle');
}
return;
} else if (event.which == ARROW_UP_KEYCODE) {
this._hoverUp();
} else if (event.which == ARROW_DOWN_KEYCODE) {
this._hoverDown();
}
if (!this._dropdownActive()) {
this.els.btnSelect.dropdown('toggle');
this._searchControlFocus();
}
}
}, {
key: "_assignClickHandlers",
value: function _assignClickHandlers() {
var _this3 = this;
// Select item.
this.els.dropdownOptions.on(Event.CLICK, function (event) {
event.preventDefault();
if (_this3._multiselect) {
_this3._preventDropdownHide();
}
_this3.toggle($(event.currentTarget));
}); // Deselect all.
if (this._config.deselectAll) {
this.els.deselectAll.on(Event.CLICK, function (event) {
event.preventDefault();
_this3._preventDropdownHide();
if (!$(event.currentTarget).hasClass('disabled')) {
_this3.deselectAll();
}
});
} // Select all.
if (this._config.selectAll) {
this.els.selectAll.on(Event.CLICK, function (event) {
event.preventDefault();
_this3._preventDropdownHide();
if (!$(event.currentTarget).hasClass('disabled')) {
_this3.selectAll();
}
});
} // Clear search.
if (this._config.search) {
this.els.clear.on(Event.CLICK, function (event) {
event.preventDefault();
_this3.els.controlSearch.val('');
_this3._preventDropdownHide();
_this3._refresh();
_this3._searchControlFocus();
});
} // Show selected.
this.els.showSelected.on(Event.CLICK, function (event) {
event.preventDefault();
_this3._preventDropdownHide();
if (!$(event.currentTarget).hasClass('disabled')) {
_this3._toggleShowSelected();
}
}); // No results.
this.els.dropdownItemNoResults.on(Event.CLICK, function (event) {
event.preventDefault();
_this3._preventDropdownHide();
}); // Badges.
if (this._config.badges) {
this.els.badgeContainer.on(Event.CLICK, 'a', function (event) {
event.preventDefault();
var $target = $(event.currentTarget);
_this3.deselect(_this3._dropdownItemByOption($target.data('option')));
$target.parent(_this3.selectors.badge).remove();
});
}
}
}, {
key: "init",
value: function init() {
// Build.
this._externalFeedback(); // Dropdown menu.
if (this._config.search) {
this.els.dropdownMenu.append(this.els.clear);
}
if (this._config.selectAll && !this._config.selectButtons) {
this.els.dropdownMenu.append(this.els.selectAll);
}
if (this._config.deselectAll && !this._config.selectButtons) {
this.els.dropdownMenu.append(this.els.deselectAll);
}
if (this._config.showSelected) {
this.els.dropdownMenu.append(this.els.showSelected);
} // Dropdown items.
this.els.dropdownItemsContainer.append(this.els.dropdownItems);
this.els.dropdownMenu.append(this.els.dropdownItemsContainer); // Dropdown.
this.els.dropdown.append(this.els.dropdownMenu); // Replace <select>.
var $el = $(this._element);
$el.after(this.els.dropdown);
if (this._config.hideSelect) {
$el.hide();
}
if (this._config.badges) {
this.els.dropdown.after(this.els.badgeContainer);
}
}
/**
* Check whether the supplied element has a `multiple` attribute,
* @param {Object} element
* @return {Boolean}
*/
}, {
key: "_isMultiselect",
value: function _isMultiselect(element) {
var attrMultiple = $(element).attr('multiple');
if (_typeof(attrMultiple) !== ( true ? "undefined" : undefined) && attrMultiple !== false) {
return true;
}
return false;
}
/**
* Search and take appropriate action.
*
* * If results haven't changed, do nothing (improves performance).
* * If results have changed, apply changes.
* @param {String} s Search term
* @return {undefined}
*/
}, {
key: "_search",
value: function _search(s) {
var results = null;
if ($.trim(s) == '') {
this._refresh();
if (this._lastSearch !== null) {
this._resultsChanged = true;
this._lastSearch = null;
this._hoverSet();
}
return;
} else {
var fuse = new external_Fuse_default.a(this._haystack, this._fuseOptions);
results = fuse.search(s);
}
this._resultsChanged = true;
if (results) {
if (typeof this._lastSearch !== null && this._arraysEqual(results, this._lastSearch)) {
this._resultsChanged = false;
}
} else {
this._refresh();
return;
}
if (this._resultsChanged) {
this._applySearch(results);
}
this._lastSearch = results;
}
/**
* Apply changes as per search results.
*
* * Remove showSelected active class if present.
* * Show clear control.
* * Set hover on the first element for keyboard navigation.
* * Hide non-results.
* * Reorder search results.
* * Reset scroll (scroll to top).
* @param {array} results Option index numbers.
* @return {undefined}
*/
}, {
key: "_applySearch",
value: function _applySearch(results) {
this._softDisableShowSelected();
this._showClear();
this._hoverSet(results[0]);
this._hide(results);
this._reorder(results);
this._resetScroll();
}
}, {
key: "_buildBtnSelect",
value: function _buildBtnSelect() {
return $('<button>', {
"class": this._config.classBtnSelect + ' dropdown-toggle',
type: 'button',
id: this.ids.dropdownButtonId,
'data-toggle': 'dropdown',
'data-target': '#' + this.ids.dropdownContainerId,
'aria-haspopup': 'true',
'aria-expanded': 'false'
}).text('Select');
}
/**
* Build HTML: Clear control
* @return {object} jQuery
*/
}, {
key: "_buildControlClear",
value: function _buildControlClear() {
return $('<a>', {
href: '#',
"class": ClassName.ITEM
}).html(this._config.htmlClear);
}
/**
* Build HTML: Deselect all element
* @return {object} jQuery
*/
}, {
key: "_buildDeselectAll",
value: function _buildDeselectAll() {
var element;
if (!this._config.selectButtons) {
element = $('<a>', {
href: '#',
"class": ClassName.ITEM
});
} else {
element = $('<button>', {
type: 'button',
"class": this._config.classBtnDeselectAll
});
}
return element.html(this._config.htmlDeselectAll).attr('title', 'Deselect all');
}
/**
* Build HTML: Select all element
* @return {object} jQuery
*/
}, {
key: "_buildSelectAll",
value: function _buildSelectAll() {
var element;
if (!this._config.selectButtons) {
element = $('<a>', {
href: '#',
"class": ClassName.ITEM
});
} else {
element = $('<button>', {
type: 'button',
"class": this._config.classBtnSelectAll
});
}
return element.html(this._config.htmlSelectAll).attr('title', 'Select all');
}
}, {
key: "_buildShowSelected",
value: function _buildShowSelected() {
var $showSelectedItem = $('<a>', {
href: '#',
"class": ClassName.ITEM,
text: 'Show selected'
});
return $showSelectedItem;
}
}, {
key: "_buildControlSearch",
value: function _buildControlSearch() {
return $('<input>', {
type: 'text',
"class": 'form-control',
placeholder: 'Search',
'aria-label': 'Search',
'aria-describedby': this.ids.controlSearchId
});
}
}, {
key: "_buildDropdown",
value: function _buildDropdown() {
var $dropdown = $('<div>', {
id: this.ids.dropdownContainerId,
"class": ClassName.DROPDOWN
}); // Build dropdown.
if (this._config.search) {
$dropdown.append(this._buildDropdownInputGroup());
} else if (this._config.selectButtons) {
$dropdown.append(this._buildDropdownBtnGroup());
} else {
$dropdown.append(this.els.btnSelect);
}
return $dropdown;
}
}, {
key: "_buildDropdownInputGroup",
value: function _buildDropdownInputGroup() {
var $inputGroup = $("<div>", {
"class": ClassName.INPUT_GROUP
});
$inputGroup.append(this.els.controlSearch);
if (this._config.selectButtons) {
if (this._config.deselectAll) {
$inputGroup.append($("<div>", {
"class": ClassName.INPUT_GROUP_APPEND
}).append(this.els.deselectAll));
}
if (this._config.selectAll) {
$inputGroup.append($("<div>", {
"class": ClassName.INPUT_GROUP_APPEND
}).append(this.els.selectAll));
}
}
$inputGroup.append($("<div>", {
"class": ClassName.INPUT_GROUP_APPEND
}).append(this.els.btnSelect));
return $inputGroup;
}
}, {
key: "_buildDropdownBtnGroup",
value: function _buildDropdownBtnGroup() {
var $btnGroup = $("<div>", {
"class": ClassName.BTN_GROUP
});
if (this._config.deselectAll) {
$btnGroup.append(this.els.deselectAll);
}
if (this._config.selectAll) {
$btnGroup.append(this.els.selectAll);
}
$btnGroup.append($("<div>", {
"class": ClassName.BTN_GROUP
}).append(this.els.btnSelect));
return $btnGroup;
}
}, {
key: "_buildDropdownMenu",
value: function _buildDropdownMenu() {
var $dropdownMenu = $('<div>', {
"class": ClassName.MENU,
'aria-labelledby': this.ids.dropdownButtonId
});
if (this._config.maxHeight) {
$dropdownMenu.css({
'height': 'auto',
'max-height': this._config.maxHeight,
'overflow-x': 'hidden'
});
}
if (this._config.search) {
$dropdownMenu.addClass(ClassName.ALIGNMENT_RIGHT);
}
return $dropdownMenu;
}
}, {
key: "_buildDropdownItemsContainer",
value: function _buildDropdownItemsContainer() {
return $('<div>');
}
}, {
key: "_buildDropdownItemNoResults",
value: function _buildDropdownItemNoResults() {
return $('<span>', {
"class": ClassName.ITEM + ' ' + ClassName.TEXT_MUTED + ' ' + ClassName.BG_TRANSPARENT,
text: this._config.textNoResults
}).hide();
}
}, {
key: "_buildDropdownItems",
value: function _buildDropdownItems() {
var _this4 = this;
var s = 0; // Sort index
var o = 0; // Option index
var $items = $();
var $optgroups = $(this._element).find('optgroup');
if ($optgroups.length) {
$optgroups.each(function (index, element) {
$items = $items.add(_this4._buildDropdownHeader($(element).attr('label')).data('index', s));
s = _this4._incrementIndex(s);
$(element).find('option').each(function (index, element) {
$(element).data('option', o);
$items = $items.add(_this4._buildDropdownItem($(element)).data('index', s).data('option', o));
s = _this4._incrementIndex(s);
o++;
});
});
} else {
$(this._element).find('option').each(function (index, element) {
$(element).data('option', o);
$items = $items.add(_this4._buildDropdownItem($(element)).data('index', s).data('option', o));
s = _this4._incrementIndex(s);
o++;
});
}
if (this._config.search) {
$items = $items.add(this.els.dropdownItemNoResults);
}
return $items;
}
}, {
key: "_incrementIndex",
value: function _incrementIndex(index) {
this._indexes.push(index.toString());
index++;
return index;
}
}, {
key: "_buildDropdownHeader",
value: function _buildDropdownHeader(text) {
return $('<h6>', {
"class": 'dropdown-header',
text: text
});
}
}, {
key: "_buildDropdownItem",
value: function _buildDropdownItem($option) {
var $dropdownItem = $('<a>', {
href: '#',
"class": ClassName.ITEM,
text: $option.text()
});
if ($option.is(':selected')) {
$dropdownItem.addClass('active');
}
return $dropdownItem;
}
}, {
key: "_buildBadgeContainer",
value: function _buildBadgeContainer() {
return $('<div>', {
'class': this._config.classBadgeContainer
});
}
/**
* Build badge.
* @param {Integer} option Option index number
* @param {String} text
* @return {Object} jQuery object
*/
}, {
key: "_buildBadge",
value: function _buildBadge(option, text) {
var badge = $('<span>', {
'class': this._config.classBadge
}).text(text);
if (this._config.badgesDismissable) {
badge.append(' ').append($('<a>', {
'href': '#',
'class': this._config.classBadgeLink
}).html(this._config.htmlBadgeRemove).data('option', option));
}
return badge;
}
/**
* Boolean: Bootstrap Dropdown visible.
* @return {boolean}
*/
}, {
key: "_dropdownActive",
value: function _dropdownActive() {
if (this.els.dropdownMenu.hasClass('show')) {
return true;
}
return false;
}
/**
* Boolean: Dropdown item is associated with a select option.
*
* e.g. Isn't an `<optgroup>` heading.
* @param {object} $item jQuery object.
* @return {Boolean}
*/
}, {
key: "_isOption",
value: function _isOption($item) {
var attr = $item.data('option');
if (_typeof(attr) !== ( true ? "undefined" : undefined) && attr !== false) {
return true;
}
return false;
}
}, {
key: "_externalFeedback",
value: function _externalFeedback() {
this._setButtonText();
if (this._config.badges) {
this._setBadges();
}
}
/**
* Set button text.
* @return {undefined}
*/
}, {
key: "_setButtonText",
value: function _setButtonText() {
var btnText;
var selected = $(this._element).val();
var noneSelected = false;
var allSelected = false;
if (!this._multiselect && selected.length > 0) {
btnText = $(this._element).find('option:selected').text();
} else if (selected.length < 1) {
btnText = this._config.textNoneSelected;
noneSelected = true;
} else if (selected.length <= this._config.maxListLength) {
btnText = this._getTextValues().join(", ");
} else {
btnText = this._config.textMultipleSelected;
btnText = btnText.replace(Keyword.COUNT_SELECTED, selected.length);
}
if (selected.length == this.els.dropdownOptions.length) {
allSelected = true;
}
this._refreshInitialControls(allSelected, noneSelected);
this.els.btnSelect.text(btnText);
}
}, {
key: "_setBadges",
value: function _setBadges(selected) {
var _this5 = this;
var badges = $();
var $selected = $(this._element).find('option:selected');
$selected.each(function (index, element) {
badges = badges.add(_this5._buildBadge($(element).data('option'), $(element).text()));
});
this.els.badgeContainer.html('').append(badges);
}
}, {
key: "_getText",
value: function _getText(value) {
return $(this._element).find("option[value='" + value + "']").first().text();
}
}, {
key: "_getTextValues",
value: function _getTextValues() {
return $(this._element).find('option:selected').map(function (i, element) {
return $(element).text();
}).get();
}
/**
* Restore initial dropdown state.
*
* * Remove hover.
* * Hide the 'no results' dropdown item.
* * Reset sort order.
* * Show initial controls.
* @return {undefined}
*/
}, {
key: "_refresh",
value: function _refresh() {
this._hideClear();
this.els.dropdownItemNoResults.hide();
this.els.dropdownOptions.show();
this._sortReset();
this._showInitialControls();
}
}, {
key: "_hide",
value: function _hide(results) {
var _this6 = this;
var notResults = $(this._indexes).not(results).get();
$.each(notResults, function (index, value) {
_this6._dropdownItemByIndex(value).hide();
});
$.each(results, function (index, value) {
_this6._dropdownItemByIndex(value).show();
});
this.els.btnSelect.dropdown('update');
}
}, {
key: "_dropdownItemByIndex",
value: function _dropdownItemByIndex(s) {
return this.els.dropdownItems.filter(function (index, element) {
return $(element).data('index') == s;
});
}
}, {
key: "_dropdownItemByOption",
value: function _dropdownItemByOption(o) {
return this.els.dropdownItems.filter(function (index, element) {
return $(element).data('option') == o;
});
}
}, {
key: "_hideInitialControls",
value: function _hideInitialControls() {
if (this._config.selectAll && !this._config.selectButtons) {
this.els.selectAll.hide();
}
if (this._config.deselectAll && !this._config.selectButtons) {
this.els.deselectAll.hide();
}
if (this._config.showSelected) {
this.els.showSelected.hide();
}
}
}, {
key: "_showInitialControls",
value: function _showInitialControls() {
if (this._config.selectAll && !this._config.selectButtons) {
this.els.selectAll.show();
}
if (this._config.deselectAll && !this._config.selectButtons) {
this.els.deselectAll.show();
}
if (this._config.showSelected) {
this.els.showSelected.show();
}
}
}, {
key: "_refreshInitialControls",
value: function _refreshInitialControls(allSelected, noneSelected) {
if (this._config.selectAll) {
this._disableEnable(this.els.selectAll, allSelected);
}
if (this._config.deselectAll) {
this._disableEnable(this.els.deselectAll, noneSelected);
}
if (this._config.showSelected) {
this._disableEnable(this.els.showSelected, noneSelected || allSelected);
}
}
}, {
key: "_showClear",
value: function _showClear() {
if (this._config.search) {
this.els.clear.show();
}
}
}, {
key: "_hideClear",
value: function _hideClear() {
if (this._config.search) {
this.els.clear.hide();
}
}
}, {
key: "_disableEnable",
value: function _disableEnable($element, condition) {
if (condition) {
this._disable($element);
} else {
this._enable($element);
}
}
}, {
key: "_enable",
value: function _enable($element) {
if ($element.is('button')) {
$element.prop('disabled', false);
}
$element.removeClass(ClassName.DISABLED);
if ($element.is('a')) {
$element.removeClass(ClassName.TEXT_MUTED);
}
}
}, {
key: "_disable",
value: function _disable($element) {
if ($element.is('button')) {
$element.prop('disabled', true);
}
$element.addClass(ClassName.DISABLED);
if ($element.is('a')) {
$element.addClass(ClassName.TEXT_MUTED);
}
}
/**
* Set hover class position.
*
* Move the hover class to a designated dropdown option. If the index points
* to a non-option, the next option will be modified.
* @param {integer} index Dropdown menu item index.
*/
}, {
key: "_hoverSet",
value: function _hoverSet(index) {
this._hoverRemoveAll();
if (_typeof(index) === ( true ? "undefined" : undefined)) {
var $item = this.els.dropdownOptions.first();
} else {
var $item = this._dropdownItemByIndex(index);
}
this._hoverItem = $item;
this._hoverAdd($item);
}
/**
* Move the hover class up.
*
* @return {undefined}
*/
}, {
key: "_hoverUp",
value: function _hoverUp() {
var current = this._hoverItem;
if (_typeof(current) !== ( true ? "undefined" : undefined) && current.length) {
var prev = current.prevAll('a:visible').first();
}
if (_typeof(prev) !== ( true ? "undefined" : undefined) && prev.length) {
this._hoverRemove(current);
this._hoverAdd(prev);
this._hoverItem = prev;
}
}
/**
* Move the hover class down.
*
* @return {undefined}
*/
}, {
key: "_hoverDown",
value: function _hoverDown() {
var current = this._hoverItem;
if (_typeof(current) !== ( true ? "undefined" : undefined) && current.length) {
var next = current.nextAll('a:visible').first();
}
if (_typeof(next) !== ( true ? "undefined" : undefined) && next.length) {
this._hoverRemove(current);
this._hoverAdd(next);
this._hoverItem = next;
}
}
}, {
key: "_hoverAdd",
value: function _hoverAdd($element) {
var className = ClassName.HOVER;
if (!$element.hasClass(ClassName.ACTIVE)) {
className = className + ' ' + ClassName.HOVER_BG;
}
$element.addClass(className);
}
}, {
key: "_hoverRemove",
value: function _hoverRemove($element) {
$element.removeClass(ClassName.HOVER + ' ' + ClassName.HOVER_BG);
}
/**
* Remove hover class from all dropdown options.
* @return {undefined}
*/
}, {
key: "_hoverRemoveAll",
value: function _hoverRemoveAll() {
this.els.dropdownOptions.removeClass(ClassName.HOVER + ' ' + ClassName.HOVER_BG);
}
/**
* Sort: Reset sort order.
* @return {undefined}
*/
}, {
key: "_sortReset",
value: function _sortReset() {
var i;
for (i = this.els.dropdownItems.length; i >= 0; i--) {
this._dropdownItemByIndex(i).prependTo(this.els.dropdownItemsContainer);
}
}
/**
* Sort: Order by array values.
*
* reorder according to an array of index values. The order of the index
* array is preserved, to make change detection easier elsewhere.
* @param {array} indexes Array of index values (strings).
* @return {undefined}
*/
}, {
key: "_reorder",
value: function _reorder(indexes) {
this.els.dropdownItemNoResults.hide();
if (_typeof(indexes) === ( true ? "undefined" : undefined) || indexes.length == 0) {
this.els.dropdownItemNoResults.show();
return;
}
var indexesReversed = indexes.slice(0); // Clone
indexesReversed = indexesReversed.reverse();
$.each(indexesReversed, function (index, value) {
this._dropdownItemByIndex(value).prependTo(this.els.dropdownItemsContainer);
});
this._hideInitialControls();
}
/**
* Sort: Move selected items to the top.
* @return {undefined}
*/
}, {
key: "_toggleShowSelected",
value: function _toggleShowSelected() {
if (this.els.showSelected.hasClass(ClassName.ACTIVE)) {
this.disableShowSelected();
} else {
this._enableShowSelected();
}
}
}, {
key: "_enableShowSelected",
value: function _enableShowSelected() {
var _this7 = this;
this.els.showSelected.addClass(ClassName.ACTIVE);
$(this.els.dropdownItemsContainer.find('.active').get().reverse()).each(function (index, element) {
$(element).prependTo(_this7.els.dropdownItemsContainer);
});
this._resetScroll();
}
}, {
key: "_disableShowSelected",
value: function _disableShowSelected() {
this._softDisableShowSelected();
this._sortReset();
}
}, {
ke