/*! selectize.js | https://github.com/brianreavis/selectize.js | Apache License (v2) */ (function (factory) { if (typeof exports === 'object') { factory(require('jquery')); } else if (typeof define === 'function' && define.amd) { define(['jquery'], factory); } else { factory(jQuery); } }(function ($) { "use strict"; // --- src/contrib/highlight.js --- /** * highlight v3 | MIT license | Johann Burkard * Highlights arbitrary terms in a node. * * - Modified by Marshal 2011-6-24 (added regex) * - Modified by Brian Reavis 2012-8-27 (cleanup) */ var highlight = function($element, pattern) { if (typeof pattern === 'string' && !pattern.length) return; var regex = (typeof pattern === 'string') ? new RegExp(pattern, 'i') : pattern; var highlight = function(node) { var skip = 0; if (node.nodeType === 3) { var pos = node.data.search(regex); if (pos >= 0 && node.data.length > 0) { var match = node.data.match(regex); var spannode = document.createElement('span'); spannode.className = 'highlight'; var middlebit = node.splitText(pos); var endbit = middlebit.splitText(match[0].length); var middleclone = middlebit.cloneNode(true); spannode.appendChild(middleclone); middlebit.parentNode.replaceChild(spannode, middlebit); skip = 1; } } else if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) { for (var i = 0; i < node.childNodes.length; ++i) { i += highlight(node.childNodes[i]); } } return skip; }; return $element.each(function() { highlight(this); }); }; var unhighlight = function($element) { return $element.find('span.highlight').each(function() { var parent = this.parentNode; parent.replaceChild(parent.firstChild, parent); parent.normalize(); }).end(); }; // --- src/constants.js --- /** * selectize - A highly customizable select control with autocomplete. * Copyright (c) 2013 Brian Reavis & contributors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at: * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF * ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. * * @author Brian Reavis */ var IS_MAC = /Mac/.test(navigator.userAgent); var KEY_COMMA = 188; var KEY_RETURN = 13; var KEY_ESC = 27; var KEY_LEFT = 37; var KEY_UP = 38; var KEY_RIGHT = 39; var KEY_DOWN = 40; var KEY_BACKSPACE = 8; var KEY_DELETE = 46; var KEY_SHIFT = 16; var KEY_CTRL = IS_MAC ? 18 : 17; var KEY_TAB = 9; var TAG_SELECT = 1; var TAG_INPUT = 2; var DIACRITICS = { 'a': '[aÀÁÂÃÄÅàáâãäå]', 'c': '[cÇç]', 'e': '[eÈÉÊËèéêë]', 'i': '[iÌÍÎÏìíîï]', 'n': '[nÑñ]', 'o': '[oÒÓÔÕÕÖØòóôõöø]', 's': '[sŠš]', 'u': '[uÙÚÛÜùúûü]', 'y': '[yŸÿý]', 'z': '[zŽž]' }; // --- src/selectize.jquery.js --- var defaults = { delimiter: ',', persist: true, diacritics: true, create: false, highlight: true, openOnFocus: true, maxOptions: 1000, maxItems: null, hideSelected: null, scrollDuration: 60, loadThrottle: 300, dataAttr: 'data-data', sortField: null, sortDirection: 'asc', valueField: 'value', labelField: 'text', searchField: ['text'], mode: null, theme: 'default', wrapperClass: 'selectize-control', inputClass: 'selectize-input', dropdownClass: 'selectize-dropdown', load : null, // function(query, callback) score : null, // function(search) onChange : null, // function(value) onItemAdd : null, // function(value, $item) { ... } onItemRemove : null, // function(value) { ... } onClear : null, // function() { ... } onOptionAdd : null, // function(value, data) { ... } onOptionRemove : null, // function(value) { ... } onDropdownOpen : null, // function($dropdown) { ... } onDropdownClose : null, // function($dropdown) { ... } onType : null, // function(str) { ... } render: { item: null, option: null, option_create: null } }; $.fn.selectize = function (settings) { var defaults = $.fn.selectize.defaults; settings = settings || {}; return this.each(function() { var instance, value, values, i, n, data, dataAttr, settings_element, tagName; var $options, $option, $input = $(this); tagName = $input[0].tagName.toLowerCase(); if (typeof settings === 'string') { instance = $input.data('selectize'); instance[settings].apply(instance, Array.prototype.splice.apply(arguments, 1)); } else { dataAttr = settings.dataAttr || defaults.dataAttr; settings_element = {}; settings_element.placeholder = $input.attr('placeholder'); settings_element.options = {}; settings_element.items = []; if (tagName === 'select') { settings_element.maxItems = !!$input.attr('multiple') ? null : 1; $options = $input.children(); for (i = 0, n = $options.length; i < n; i++) { $option = $($options[i]); value = $option.attr('value') || ''; if (!value.length) continue; data = (dataAttr && $option.attr(dataAttr)) || { 'text' : $option.html(), 'value' : value }; if (typeof data === 'string') data = JSON.parse(data); settings_element.options[value] = data; if ($option.is(':selected')) { settings_element.items.push(value); } } } else { value = $.trim($input.val() || ''); if (value.length) { values = value.split(settings.delimiter || defaults.delimiter); for (i = 0, n = values.length; i < n; i++) { settings_element.options[values[i]] = { 'text' : values[i], 'value' : values[i] }; } settings_element.items = values; } } instance = new Selectize($input, $.extend(true, {}, defaults, settings_element, settings)); $input.data('selectize', instance); $input.addClass('selectized'); } }); }; $.fn.selectize.defaults = defaults; // --- src/utils.js --- var isset = function(object) { return typeof object !== 'undefined'; }; var htmlEntities = function(str) { return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); }; var quoteRegExp = function(str) { return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); }; var once = function(fn) { var called = false; return function() { if (called) return; called = true; fn.apply(this, arguments); }; }; var debounce = function(fn, delay) { var timeout; return function() { var self = this; var args = arguments; window.clearTimeout(timeout); timeout = window.setTimeout(function() { fn.apply(self, args); }, delay); }; }; /** * A workaround for http://bugs.jquery.com/ticket/6696 * * @param {object} $parent - Parent element to listen on. * @param {string} event - Event name. * @param {string} selector - Descendant selector to filter by. * @param {function} fn - Event handler. */ var watchChildEvent = function($parent, event, selector, fn) { $parent.on(event, selector, function(e) { var child = e.target; while (child && child.parentNode !== $parent[0]) { child = child.parentNode; } e.currentTarget = child; return fn.apply(this, [e]); }); }; var getSelection = function(input) { var result = {}; if ('selectionStart' in input) { result.start = input.selectionStart; result.length = input.selectionEnd - result.start; } else if (document.selection) { input.focus(); var sel = document.selection.createRange(); var selLen = document.selection.createRange().text.length; sel.moveStart('character', -input.value.length); result.start = sel.text.length - selLen; result.length = selLen; } return result; }; var transferStyles = function($from, $to, properties) { var styles = {}; if (properties) { for (var i = 0; i < properties.length; i++) { styles[properties[i]] = $from.css(properties[i]); } } else { styles = $from.css(); } $to.css(styles); return $to; }; var measureString = function(str, $parent) { var $test = $('').css({ position: 'absolute', top: -99999, left: -99999, width: 'auto', padding: 0, whiteSpace: 'nowrap' }).text(str).appendTo('body'); transferStyles($parent, $test, [ 'letterSpacing', 'fontSize', 'fontFamily', 'fontWeight', 'textTransform' ]); var width = $test.width(); $test.remove(); return width; }; var autoGrow = function($input) { var update = function(e) { var value, keyCode, printable, placeholder, width; var shift, character; e = e || window.event; value = $input.val(); if (e.type && e.type.toLowerCase() === 'keydown') { keyCode = e.keyCode; printable = ( (keyCode >= 97 && keyCode <= 122) || // a-z (keyCode >= 65 && keyCode <= 90) || // A-Z (keyCode >= 48 && keyCode <= 57) || // 0-9 keyCode == 32 // space ); if (printable) { shift = e.shiftKey; character = String.fromCharCode(e.keyCode); if (shift) character = character.toUpperCase(); else character = character.toLowerCase(); value += character; } } placeholder = $input.attr('placeholder') || ''; if (!value.length && placeholder.length) { value = placeholder; } width = measureString(value, $input) + 4; if (width !== $input.width()) { $input.width(width); $input.triggerHandler('resize'); } }; $input.on('keydown keyup update blur', update); update({}); }; // --- src/selectize.js --- /** * selectize.js * Copyright (c) 2013 Brian Reavis & contributors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at: * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF * ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. * * @author Brian Reavis */ var Selectize = function($input, settings) { $input[0].selectize = this; this.$input = $input; this.tagType = $input[0].tagName.toLowerCase() === 'select' ? TAG_SELECT : TAG_INPUT; this.settings = settings; this.highlightedValue = null; this.isOpen = false; this.isLocked = false; this.isFocused = false; this.isInputFocused = false; this.isSetup = false; this.isShiftDown = false; this.isCtrlDown = false; this.ignoreFocus = false; this.hasOptions = false; this.currentResults = null; this.lastValue = ''; this.caretPos = 0; this.loading = 0; this.loadedSearches = {}; this.$activeOption = null; this.$activeItems = []; this.options = {}; this.userOptions = {}; this.items = []; this.renderCache = {}; this.onSearchChange = debounce(this.onSearchChange, this.settings.loadThrottle); if ($.isArray(settings.options)) { var key = settings.valueField; for (var i = 0; i < settings.options.length; i++) { if (settings.options[i].hasOwnProperty(key)) { this.options[settings.options[i][key]] = settings.options[i]; } } } else if (typeof settings.options === 'object') { $.extend(this.options, settings.options); delete this.settings.options; } // option-dependent defaults this.settings.mode = this.settings.mode || (this.settings.maxItems === 1 ? 'single' : 'multi'); if (typeof this.settings.hideSelected !== 'boolean') { this.settings.hideSelected = this.settings.mode === 'multi'; } this.setup(); }; /** * Creates all elements and sets up event bindings. */ Selectize.prototype.setup = function() { var self = this; var $wrapper; var $control; var $control_input; var $dropdown; var inputMode; var displayMode; var timeout_blur; var timeout_focus; $wrapper = $('
').addClass(this.settings.theme).addClass(this.settings.wrapperClass); $control = $('
').addClass(this.settings.inputClass).addClass('items').toggleClass('has-options', !$.isEmptyObject(this.options)).appendTo($wrapper); $control_input = $('').appendTo($control); $dropdown = $('
').addClass(this.settings.dropdownClass).hide().appendTo($wrapper); displayMode = this.$input.css('display'); $wrapper.css({ width: this.$input[0].style.width, display: displayMode }); inputMode = this.settings.mode; $wrapper.toggleClass('single', inputMode === 'single'); $wrapper.toggleClass('multi', inputMode === 'multi'); if ((this.settings.maxItems === null || this.settings.maxItems > 1) && this.tagType === TAG_SELECT) { this.$input.attr('multiple', 'multiple'); } if (this.settings.placeholder) { $control_input.attr('placeholder', this.settings.placeholder); } this.$wrapper = $wrapper; this.$control = $control; this.$control_input = $control_input; this.$dropdown = $dropdown; $control.on('mousedown', function(e) { if (e.currentTarget === self.$control[0]) { $control_input.trigger('focus'); } else { self.focus(true); } e.preventDefault(); }); watchChildEvent($dropdown, 'mouseenter', '*', function() { return self.onOptionHover.apply(self, arguments); }); watchChildEvent($dropdown, 'mousedown', '*', function() { return self.onOptionSelect.apply(self, arguments); }); watchChildEvent($control, 'mousedown', '*:not(input)', function() { return self.onItemSelect.apply(self, arguments); }); autoGrow($control_input); $control_input.on({ mousedown : function(e) { e.stopPropagation(); }, keydown : function() { return self.onKeyDown.apply(self, arguments); }, keyup : function() { return self.onKeyUp.apply(self, arguments); }, keypress : function() { return self.onKeyPress.apply(self, arguments); }, resize : function() { self.positionDropdown.apply(self, []); }, blur : function() { return self.onBlur.apply(self, arguments); }, focus : function() { return self.onFocus.apply(self, arguments); } }); $(document).on({ keydown: function(e) { self.isCtrlDown = e[IS_MAC ? 'altKey' : 'ctrlKey']; self.isShiftDown = e.shiftKey; if (self.isFocused && !self.isLocked) { var tagName = (e.target.tagName || '').toLowerCase(); if (tagName === 'input' || tagName === 'textarea') return; if ([KEY_SHIFT, KEY_BACKSPACE, KEY_DELETE, KEY_ESC, KEY_LEFT, KEY_RIGHT, KEY_TAB].indexOf(e.keyCode) !== -1) { return self.onKeyDown.apply(self, arguments); } } }, keyup: function(e) { if (e.keyCode === KEY_CTRL) self.isCtrlDown = false; else if (e.keyCode === KEY_SHIFT) self.isShiftDown = false; }, mousedown: function(e) { if (self.isFocused && !self.isLocked) { // prevent events on the dropdown scrollbar from causing the control to blur if (e.target === self.$dropdown[0]) { var ignoreFocus = self.ignoreFocus; self.ignoreFocus = true; window.setTimeout(function() { self.ignoreFocus = ignoreFocus; self.focus(false); }, 0); return; } // blur on click outside if (!self.$control.has(e.target).length && e.target !== self.$control[0]) { self.blur(); } } } }); $(window).on({ resize: function() { if (self.isOpen) { self.positionDropdown.apply(self, arguments); } } }); this.$input.hide().after(this.$wrapper); if ($.isArray(this.settings.items)) { this.setValue(this.settings.items); delete this.settings.items; } this.updateOriginalInput(); this.refreshItems(); this.updatePlaceholder(); this.isSetup = true; }; /** * Triggers a callback defined in the user-provided settings. * Events: onItemAdd, onOptionAdd, etc * * @param {string} event */ Selectize.prototype.trigger = function(event) { var args; if (typeof this.settings[event] === 'function') { args = Array.prototype.slice.apply(arguments, [1]); this.settings.event.apply(this, args); } }; /** * Triggered on keypress. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onKeyPress = function(e) { if (this.isLocked) return; var character = String.fromCharCode(e.keyCode || e.which); if (this.settings.create && character === this.settings.delimiter) { this.createItem(); e.preventDefault(); return false; } }; /** * Triggered on keydown. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onKeyDown = function(e) { if (this.isLocked) return; var isInput = e.target === this.$control_input[0]; switch (e.keyCode || e.which) { case KEY_ESC: this.blur(); return; case KEY_DOWN: if (!this.isOpen && this.hasOptions && this.isInputFocused) { this.open(); } else if (this.$activeOption) { var $next = this.$activeOption.next(); if ($next.length) this.setActiveOption($next, true, true); } e.preventDefault(); break; case KEY_UP: if (this.$activeOption) { var $prev = this.$activeOption.prev(); if ($prev.length) this.setActiveOption($prev, true, true); } e.preventDefault(); break; case KEY_RETURN: if (this.$activeOption) { this.onOptionSelect({currentTarget: this.$activeOption}); } e.preventDefault(); break; case KEY_LEFT: this.advanceSelection(-1, e); break; case KEY_RIGHT: this.advanceSelection(1, e); break; case KEY_TAB: if (this.settings.create && $.trim(this.$control_input.val()).length) { this.createItem(); e.preventDefault(); } break; case KEY_BACKSPACE: case KEY_DELETE: this.deleteSelection(e); break; default: if (this.isFull()) { e.preventDefault(); return; } } if (!this.isFull()) { this.focus(true); } }; /** * Triggered on keyup. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onKeyUp = function(e) { if (this.isLocked) return; var value = this.$control_input.val() || ''; if (this.lastValue !== value) { this.lastValue = value; this.onSearchChange(value); this.refreshOptions(); this.trigger('onType', value); } }; /** * Invokes the user-provide option provider / loader. * * Note: this function is debounced in the Selectize * constructor (by `settings.loadDelay` milliseconds) * * @param {string} value */ Selectize.prototype.onSearchChange = function(value) { if (!this.settings.load) return; if (this.loadedSearches.hasOwnProperty(value)) return; var self = this; var $wrapper = this.$wrapper.addClass('loading'); this.loading++; this.loadedSearches[value] = true; this.settings.load.apply(this, [value, function(results) { self.loading = Math.max(self.loading - 1, 0); if (results && results.length) { self.addOption(results); self.refreshOptions(false); if (self.isInputFocused) self.open(); } if (!self.loading) { $wrapper.removeClass('loading'); } }]); }; /** * Triggered on focus. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onFocus = function(e) { this.showInput(); this.isInputFocused = true; this.isFocused = true; if (this.ignoreFocus) return; this.setActiveItem(null); this.$control.addClass('focus'); this.refreshOptions(!!this.settings.openOnFocus); }; /** * Triggered on blur. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onBlur = function(e) { this.isInputFocused = false; if (this.ignoreFocus) return; this.close(); this.setTextboxValue(''); this.setActiveOption(null); this.setCaret(this.items.length, false); if (!this.$activeItems.length) { this.$control.removeClass('focus'); this.isFocused = false; } }; /** * Triggered when the user rolls over * an option in the autocomplete dropdown menu. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onOptionHover = function(e) { this.setActiveOption(e.currentTarget, false); }; /** * Triggered when the user clicks on an option * in the autocomplete dropdown menu. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onOptionSelect = function(e) { var $target = $(e.currentTarget); if ($target.hasClass('create')) { this.createItem(); } else { var value = $target.attr('data-value'); if (value) { this.addItem(value); this.setTextboxValue(''); } } }; /** * Triggered when the user clicks on an item * that has been selected. * * @param {object} e * @returns {boolean} */ Selectize.prototype.onItemSelect = function(e) { if (this.settings.mode === 'multi') { this.$control_input.trigger('blur'); this.setActiveItem(e.currentTarget, e); e.stopPropagation(); } }; /** * Sets the input field of the control to the specified value. * * @param {string} value */ Selectize.prototype.setTextboxValue = function(value) { this.$control_input.val(value); this.lastValue = value; }; /** * Returns the value of the control. If multiple items * can be selected (e.g. or * element to reflect the current state. */ Selectize.prototype.updateOriginalInput = function() { var i, n, options; if (this.$input[0].tagName.toLowerCase() === 'select') { options = []; for (i = 0, n = this.items.length; i < n; i++) { options.push(''); } if (!options.length && !this.$input.attr('multiple')) { options.push(''); } this.$input.html(options.join('')); } else { this.$input.val(this.getValue()); } this.$input.trigger('change'); if (this.isSetup) { this.trigger('onChange', this.$input.val()); } }; /** * Shows/hide the input placeholder depending * on if there items in the list already. */ Selectize.prototype.updatePlaceholder = function() { if (!this.settings.placeholder) return; var $input = this.$control_input; if (this.items.length) { $input.removeAttr('placeholder'); } else { $input.attr('placeholder', this.settings.placeholder); } $input.triggerHandler('update'); }; /** * Shows the autocomplete dropdown containing * the available options. */ Selectize.prototype.open = function() { if (this.isOpen || (this.settings.mode === 'multi' && this.isFull())) return; this.isOpen = true; this.positionDropdown(); this.$control.addClass('dropdown-active'); this.$dropdown.show(); this.trigger('onDropdownOpen', this.$dropdown); }; /** * Closes the autocomplete dropdown menu. */ Selectize.prototype.close = function() { if (!this.isOpen) return; this.$dropdown.hide(); this.$control.removeClass('dropdown-active'); this.isOpen = false; this.trigger('onDropdownClose', this.$dropdown); }; /** * Calculates and applies the appropriate * position of the dropdown. */ Selectize.prototype.positionDropdown = function() { var $control = this.$control; var offset = $control.position(); offset.top += $control.outerHeight(true); this.$dropdown.css({ width : $control.outerWidth(), top : offset.top, left : offset.left }); }; /** * Resets / clears all selected items * from the control. */ Selectize.prototype.clear = function() { if (!this.items.length) return; this.$control.removeClass('has-items'); this.$control.children(':not(input)').remove(); this.items = []; this.setCaret(0); this.updatePlaceholder(); this.updateOriginalInput(); this.trigger('onClear'); }; /** * A helper method for inserting an element * at the current caret position. * * @param {object} $el */ Selectize.prototype.insertAtCaret = function($el) { var caret = Math.min(this.caretPos, this.items.length); if (caret === 0) { this.$control.prepend($el); } else { $(this.$control[0].childNodes[caret]).before($el); } this.setCaret(caret + 1); }; /** * Removes the current selected item(s). * * @param {object} e (optional) */ Selectize.prototype.deleteSelection = function(e) { var i, n, direction, selection, values, caret, $tail; direction = (e.keyCode === KEY_BACKSPACE) ? -1 : 1; selection = getSelection(this.$control_input[0]); if (this.$activeItems.length) { $tail = this.$control.children('.active:' + (direction > 0 ? 'last' : 'first')); caret = Array.prototype.indexOf.apply(this.$control[0].childNodes, [$tail[0]]); if (this.$activeItems.length > 1 && direction > 0) { caret--; } values = []; for (i = 0, n = this.$activeItems.length; i < n; i++) { values.push($(this.$activeItems[i]).attr('data-value')); } while (values.length) { this.removeItem(values.pop()); } this.setCaret(caret); e.preventDefault(); e.stopPropagation(); } else if ((this.isInputFocused || this.settings.mode === 'single') && this.items.length) { if (direction < 0 && selection.start === 0 && selection.length === 0) { this.removeItem(this.items[this.caretPos - 1]); } else if (direction > 0 && selection.start === this.$control_input.val().length) { this.removeItem(this.items[this.caretPos]); } } }; /** * Selects the previous / next item (depending * on the `direction` argument). * * > 0 - right * < 0 - left * * @param {int} direction * @param {object} e (optional) */ Selectize.prototype.advanceSelection = function(direction, e) { if (direction === 0) return; var tail = direction > 0 ? 'last' : 'first'; var selection = getSelection(this.$control_input[0]); if (this.isInputFocused) { var valueLength = this.$control_input.val().length; var cursorAtEdge = direction < 0 ? selection.start === 0 && selection.length === 0 : selection.start === valueLength; if (cursorAtEdge && !valueLength) { this.advanceCaret(direction, e); } } else { var $tail = this.$control.children('.active:' + tail); if ($tail.length) { var idx = Array.prototype.indexOf.apply(this.$control[0].childNodes, [$tail[0]]); this.setCaret(direction > 0 ? idx + 1 : idx); } } }; /** * Moves the caret left / right. * * @param {int} direction * @param {object} e (optional) */ Selectize.prototype.advanceCaret = function(direction, e) { if (direction === 0) return; var fn = direction > 0 ? 'next' : 'prev'; if (this.isShiftDown) { var $adj = this.$control_input[fn](); if ($adj.length) { this.blur(); this.setActiveItem($adj); e && e.preventDefault(); } } else { this.setCaret(this.caretPos + direction); } }; /** * Moves the caret to the specified index. * * @param {int} i * @param {boolean} focus */ Selectize.prototype.setCaret = function(i, focus) { if (this.settings.mode === 'single' || this.isFull()) { i = this.items.length; } else { i = Math.max(0, Math.min(this.items.length, i)); } this.ignoreFocus = true; this.$control_input.detach(); if (i === this.items.length) { this.$control.append(this.$control_input); } else { this.$control_input.insertBefore(this.$control.children(':not(input)')[i]); } this.ignoreFocus = false; if (focus && this.isSetup) { this.focus(true); } this.caretPos = i; }; /** * Disables user input on the control. Used while * items are being asynchronously created. */ Selectize.prototype.lock = function() { this.isLocked = true; this.$control.addClass('locked'); }; /** * Re-enables user input on the control. */ Selectize.prototype.unlock = function() { this.isLocked = false; this.$control.removeClass('locked'); }; /** * A helper method for rendering "item" and * "option" templates, given the data. * * @param {string} templateName * @param {object} data * @returns {string} */ Selectize.prototype.render = function(templateName, data) { cache = isset(cache) ? cache : true; var value, label; var html = ''; var cache = false; if (['option', 'item'].indexOf(templateName) !== -1) { value = data[this.settings.valueField]; cache = isset(value); } if (cache) { if (!isset(this.renderCache[templateName])) { this.renderCache[templateName] = {}; } if (this.renderCache[templateName].hasOwnProperty(value)) { return this.renderCache[templateName][value]; } } if (this.settings.render && typeof this.settings.render[templateName] === 'function') { html = this.settings.render[templateName].apply(this, [data]); } else { label = data[this.settings.labelField]; switch (templateName) { case 'option': html = '
' + label + '
'; break; case 'item': html = '
' + label + '
'; break; case 'option_create': html = '
Create ' + htmlEntities(data.input) + '
'; break; } } if (isset(value)) { html = html.replace(/^[\ ]*<([a-z][a-z0-9\-_]*(?:\:[a-z][a-z0-9\-_]*)?)/i, '<$1 data-value="' + value + '"'); } if (cache) { this.renderCache[templateName][value] = html; } return html; }; return Selectize; }));