| !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.selectivity=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ |
| _dereq_(5);_dereq_(6);_dereq_(7);_dereq_(9);_dereq_(10);_dereq_(11);_dereq_(12);_dereq_(13);_dereq_(14);_dereq_(15);_dereq_(16);_dereq_(17);_dereq_(18);_dereq_(19);module.exports=_dereq_(8); |
| },{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"5":5,"6":6,"7":7,"8":8,"9":9}],2:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| /** |
| * Event Delegator Constructor. |
| */ |
| function EventDelegator() { |
| |
| this._events = []; |
| |
| this.delegateEvents(); |
| } |
| |
| /** |
| * Methods. |
| */ |
| $.extend(EventDelegator.prototype, { |
| |
| /** |
| * Attaches all listeners from the events map to the instance's element. |
| * |
| * Normally, you should not have to call this method yourself as it's called automatically in |
| * the constructor. |
| */ |
| delegateEvents: function() { |
| |
| this.undelegateEvents(); |
| |
| $.each(this.events, function(event, listener) { |
| var selector, index = event.indexOf(' '); |
| if (index > -1) { |
| selector = event.slice(index + 1); |
| event = event.slice(0, index); |
| } |
| |
| if ($.type(listener) === 'string') { |
| listener = this[listener]; |
| } |
| |
| listener = listener.bind(this); |
| |
| if (selector) { |
| this.$el.on(event, selector, listener); |
| } else { |
| this.$el.on(event, listener); |
| } |
| |
| this._events.push({ event: event, selector: selector, listener: listener }); |
| }.bind(this)); |
| }, |
| |
| /** |
| * Detaches all listeners from the events map from the instance's element. |
| */ |
| undelegateEvents: function() { |
| |
| this._events.forEach(function(event) { |
| if (event.selector) { |
| this.$el.off(event.event, event.selector, event.listener); |
| } else { |
| this.$el.off(event.event, event.listener); |
| } |
| }, this); |
| |
| this._events = []; |
| } |
| |
| }); |
| |
| module.exports = EventDelegator; |
| |
| },{"jquery":"jquery"}],3:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| /** |
| * @license |
| * lodash 3.3.1 (Custom Build) <https://lodash.com/> |
| * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/> |
| * Based on Underscore.js 1.8.2 <http://underscorejs.org/LICENSE> |
| * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors |
| * Available under MIT license <https://lodash.com/license> |
| */ |
| |
| /** |
| * Gets the number of milliseconds that have elapsed since the Unix epoch |
| * (1 January 1970 00:00:00 UTC). |
| * |
| * @static |
| * @memberOf _ |
| * @category Date |
| * @example |
| * |
| * _.defer(function(stamp) { |
| * console.log(_.now() - stamp); |
| * }, _.now()); |
| * // => logs the number of milliseconds it took for the deferred function to be invoked |
| */ |
| var now = Date.now; |
| |
| /** |
| * Creates a function that delays invoking `func` until after `wait` milliseconds |
| * have elapsed since the last time it was invoked. |
| * |
| * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) |
| * for details over the differences between `_.debounce` and `_.throttle`. |
| * |
| * @static |
| * @memberOf _ |
| * @category Function |
| * @param {Function} func The function to debounce. |
| * @param {number} [wait=0] The number of milliseconds to delay. |
| * @returns {Function} Returns the new debounced function. |
| * @example |
| * |
| * // avoid costly calculations while the window size is in flux |
| * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); |
| */ |
| function debounce(func, wait) { |
| var args, |
| result, |
| stamp, |
| timeoutId, |
| trailingCall, |
| lastCalled = 0; |
| |
| wait = wait < 0 ? 0 : (+wait || 0); |
| |
| function delayed() { |
| var remaining = wait - (now() - stamp); |
| if (remaining <= 0 || remaining > wait) { |
| var isCalled = trailingCall; |
| timeoutId = trailingCall = undefined; |
| if (isCalled) { |
| lastCalled = now(); |
| result = func.apply(null, args); |
| if (!timeoutId) { |
| args = null; |
| } |
| } |
| } else { |
| timeoutId = setTimeout(delayed, remaining); |
| } |
| } |
| |
| function debounced() { |
| args = arguments; |
| stamp = now(); |
| trailingCall = true; |
| |
| if (!timeoutId) { |
| timeoutId = setTimeout(delayed, wait); |
| } |
| return result; |
| } |
| return debounced; |
| } |
| |
| module.exports = debounce; |
| |
| },{}],4:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| /** |
| * @license |
| * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/> |
| * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/> |
| * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE> |
| * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors |
| * Available under MIT license <http://lodash.com/license> |
| */ |
| |
| var htmlEscapes = { |
| '&': '&', |
| '<': '<', |
| '>': '>', |
| '"': '"', |
| "'": ''' |
| }; |
| |
| /** |
| * Used by `escape` to convert characters to HTML entities. |
| * |
| * @private |
| * @param {string} match The matched character to escape. |
| * @returns {string} Returns the escaped character. |
| */ |
| function escapeHtmlChar(match) { |
| return htmlEscapes[match]; |
| } |
| |
| var reUnescapedHtml = new RegExp('[' + Object.keys(htmlEscapes).join('') + ']', 'g'); |
| |
| /** |
| * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their |
| * corresponding HTML entities. |
| * |
| * @static |
| * @memberOf _ |
| * @category Utilities |
| * @param {string} string The string to escape. |
| * @returns {string} Returns the escaped string. |
| * @example |
| * |
| * _.escape('Fred, Wilma, & Pebbles'); |
| * // => 'Fred, Wilma, & Pebbles' |
| */ |
| function escape(string) { |
| return string ? String(string).replace(reUnescapedHtml, escapeHtmlChar) : ''; |
| } |
| |
| module.exports = escape; |
| |
| },{}],5:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var debounce = _dereq_(3); |
| |
| var Selectivity = _dereq_(8); |
| |
| _dereq_(13); |
| |
| /** |
| * Option listener that implements a convenience query function for performing AJAX requests. |
| */ |
| Selectivity.OptionListeners.unshift(function(selectivity, options) { |
| |
| var ajax = options.ajax; |
| if (ajax && ajax.url) { |
| var formatError = ajax.formatError || Selectivity.Locale.ajaxError; |
| var minimumInputLength = ajax.minimumInputLength || 0; |
| var params = ajax.params; |
| var processItem = ajax.processItem || function(item) { return item; }; |
| var quietMillis = ajax.quietMillis || 0; |
| var resultsCb = ajax.results || function(data) { return { results: data, more: false }; }; |
| var transport = ajax.transport || $.ajax; |
| |
| if (quietMillis) { |
| transport = debounce(transport, quietMillis); |
| } |
| |
| options.query = function(queryOptions) { |
| var offset = queryOptions.offset; |
| var term = queryOptions.term; |
| if (term.length < minimumInputLength) { |
| queryOptions.error( |
| Selectivity.Locale.needMoreCharacters(minimumInputLength - term.length) |
| ); |
| } else { |
| selectivity.dropdown.showLoading(); |
| |
| var url = (ajax.url instanceof Function ? ajax.url() : ajax.url); |
| if (params) { |
| url += (url.indexOf('?') > -1 ? '&' : '?') + $.param(params(term, offset)); |
| } |
| |
| var success = ajax.success; |
| var error = ajax.error; |
| |
| transport($.extend({}, ajax, { |
| url: url, |
| success: function(data, textStatus, jqXHR) { |
| if (success) { |
| success(data, textStatus, jqXHR); |
| } |
| |
| var results = resultsCb(data, offset); |
| results.results = results.results.map(processItem); |
| queryOptions.callback(results); |
| }, |
| error: function(jqXHR, textStatus, errorThrown) { |
| if (error) { |
| error(jqXHR, textStatus, errorThrown); |
| } |
| |
| queryOptions.error( |
| formatError(term, jqXHR, textStatus, errorThrown), |
| { escape: false } |
| ); |
| } |
| })); |
| } |
| }; |
| } |
| }); |
| |
| },{"13":13,"3":3,"8":8,"jquery":"jquery"}],6:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var Selectivity = _dereq_(8); |
| |
| var latestQueryNum = 0; |
| |
| /** |
| * Option listener that will discard any callbacks from the query function if another query has |
| * been called afterwards. This prevents responses from remote sources arriving out-of-order. |
| */ |
| Selectivity.OptionListeners.push(function(selectivity, options) { |
| |
| var query = options.query; |
| if (query && !query._async) { |
| options.query = function(queryOptions) { |
| latestQueryNum++; |
| var queryNum = latestQueryNum; |
| |
| var callback = queryOptions.callback; |
| var error = queryOptions.error; |
| queryOptions.callback = function() { |
| if (queryNum === latestQueryNum) { |
| callback.apply(null, arguments); |
| } |
| }; |
| queryOptions.error = function() { |
| if (queryNum === latestQueryNum) { |
| error.apply(null, arguments); |
| } |
| }; |
| query(queryOptions); |
| }; |
| options.query._async = true; |
| } |
| }); |
| |
| },{"8":8}],7:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var SelectivityDropdown = _dereq_(10); |
| |
| /** |
| * Methods. |
| */ |
| $.extend(SelectivityDropdown.prototype, { |
| |
| /** |
| * @inherit |
| */ |
| removeCloseHandler: function() { |
| |
| if (this._$backdrop && !this.parentMenu) { |
| this._$backdrop.remove(); |
| this._$backdrop = null; |
| } |
| }, |
| |
| /** |
| * @inherit |
| */ |
| setupCloseHandler: function() { |
| |
| var $backdrop; |
| if (this.parentMenu) { |
| $backdrop = this.parentMenu._$backdrop; |
| } else { |
| $backdrop = $('<div>').addClass('selectivity-backdrop'); |
| |
| $('body').append($backdrop); |
| } |
| |
| $backdrop.on('click', this.close.bind(this)); |
| |
| this._$backdrop = $backdrop; |
| } |
| |
| }); |
| |
| },{"10":10,"jquery":"jquery"}],8:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var EventDelegator = _dereq_(2); |
| |
| /** |
| * Create a new Selectivity instance or invoke a method on an instance. |
| * |
| * @param methodName Optional name of a method to call. If omitted, a Selectivity instance is |
| * created for each element in the set of matched elements. If an element in the |
| * set already has a Selectivity instance, the result is the same as if the |
| * setOptions() method is called. |
| * @param options Optional options object to pass to the given method or the constructor. See the |
| * documentation for the respective methods to see which options they accept. In case |
| * a new instance is being created, the following property is used: |
| * inputType - The input type to use. Default input types include 'Multiple' and |
| * 'Single', but you can add custom input types to the InputTypes map or |
| * just specify one here as a function. The default value is 'Single', |
| * unless multiple is true in which case it is 'Multiple'. |
| * multiple - Boolean determining whether multiple items may be selected |
| * (default: false). If true, a MultipleSelectivity instance is created, |
| * otherwise a SingleSelectivity instance is created. |
| * |
| * @return If the given method returns a value, this method returns the value of that method |
| * executed on the first element in the set of matched elements. |
| */ |
| function selectivity(methodName, options) { |
| /* jshint validthis: true */ |
| |
| var result; |
| |
| this.each(function() { |
| var instance = this.selectivity; |
| |
| if (instance) { |
| if ($.type(methodName) !== 'string') { |
| options = methodName; |
| methodName = 'setOptions'; |
| } |
| |
| if ($.type(instance[methodName]) === 'function') { |
| if (result === undefined) { |
| result = instance[methodName].call(instance, options); |
| } |
| } else { |
| throw new Error('Unknown method: ' + methodName); |
| } |
| } else { |
| if ($.type(methodName) === 'string') { |
| if (methodName !== 'destroy') { |
| throw new Error('Cannot call method on element without Selectivity instance'); |
| } |
| } else { |
| options = $.extend({}, methodName, { element: this }); |
| |
| // this is a one-time hack to facilitate the selectivity-traditional module, because |
| // the module is not able to hook this early into creation of the instance |
| var $this = $(this); |
| if ($this.is('select') && $this.prop('multiple')) { |
| options.multiple = true; |
| } |
| |
| var InputTypes = Selectivity.InputTypes; |
| var InputType = (options.inputType || (options.multiple ? 'Multiple' : 'Single')); |
| if ($.type(InputType) !== 'function') { |
| if (InputTypes[InputType]) { |
| InputType = InputTypes[InputType]; |
| } else { |
| throw new Error('Unknown Selectivity input type: ' + InputType); |
| } |
| } |
| |
| this.selectivity = new InputType(options); |
| } |
| } |
| }); |
| |
| return (result === undefined ? this : result); |
| } |
| |
| /** |
| * Selectivity Base Constructor. |
| * |
| * You will never use this constructor directly. Instead, you use $(selector).selectivity(options) |
| * to create an instance of either MultipleSelectivity or SingleSelectivity. This class defines all |
| * functionality that is common between both. |
| * |
| * @param options Options object. Accepts the same options as the setOptions method(), in addition |
| * to the following ones: |
| * data - Initial selection data to set. This should be an array of objects with 'id' |
| * and 'text' properties. This option is mutually exclusive with 'value'. |
| * element - The DOM element to which to attach the Selectivity instance. This |
| * property is set automatically by the $.fn.selectivity() function. |
| * value - Initial value to set. This should be an array of IDs. This property is |
| * mutually exclusive with 'data'. |
| */ |
| function Selectivity(options) { |
| |
| if (!(this instanceof Selectivity)) { |
| return selectivity.apply(this, arguments); |
| } |
| |
| /** |
| * jQuery container for the element to which this instance is attached. |
| */ |
| this.$el = $(options.element); |
| |
| /** |
| * jQuery container for the search input. |
| * |
| * May be null as long as there is no visible search input. It is set by initSearchInput(). |
| */ |
| this.$searchInput = null; |
| |
| /** |
| * Reference to the currently open dropdown. |
| */ |
| this.dropdown = null; |
| |
| /** |
| * Whether the input is enabled. |
| * |
| * This is false when the option readOnly is false or the option removeOnly is false. |
| */ |
| this.enabled = true; |
| |
| /** |
| * Boolean whether the browser has touch input. |
| */ |
| this.hasTouch = (typeof window !== 'undefined' && 'ontouchstart' in window); |
| |
| /** |
| * Boolean whether the browser has a physical keyboard attached to it. |
| * |
| * Given that there is no way for JavaScript to reliably detect this yet, we just assume it's |
| * the opposite of hasTouch for now. |
| */ |
| this.hasKeyboard = !this.hasTouch; |
| |
| /** |
| * Array of items from which to select. If set, this will be an array of objects with 'id' and |
| * 'text' properties. |
| * |
| * If given, all items are expected to be available locally and all selection operations operate |
| * on this local array only. If null, items are not available locally, and a query function |
| * should be provided to fetch remote data. |
| */ |
| this.items = null; |
| |
| /** |
| * The function to be used for matching search results. |
| */ |
| this.matcher = Selectivity.matcher; |
| |
| /** |
| * Options passed to the Selectivity instance or set through setOptions(). |
| */ |
| this.options = {}; |
| |
| /** |
| * Results from a search query. |
| */ |
| this.results = []; |
| |
| /** |
| * Array of search input listeners. |
| * |
| * Custom listeners can be specified in the options object. |
| */ |
| this.searchInputListeners = Selectivity.SearchInputListeners; |
| |
| /** |
| * Mapping of templates. |
| * |
| * Custom templates can be specified in the options object. |
| */ |
| this.templates = $.extend({}, Selectivity.Templates); |
| |
| /** |
| * The last used search term. |
| */ |
| this.term = ''; |
| |
| this.setOptions(options); |
| |
| if (options.value) { |
| this.value(options.value, { triggerChange: false }); |
| } else { |
| this.data(options.data || null, { triggerChange: false }); |
| } |
| |
| this._$searchInputs = []; |
| |
| this.$el.on('selectivity-close', this._closed.bind(this)); |
| |
| EventDelegator.call(this); |
| } |
| |
| /** |
| * Methods. |
| */ |
| $.extend(Selectivity.prototype, EventDelegator.prototype, { |
| |
| /** |
| * Convenience shortcut for this.$el.find(selector). |
| */ |
| $: function(selector) { |
| |
| return this.$el.find(selector); |
| }, |
| |
| /** |
| * Closes the dropdown. |
| */ |
| close: function() { |
| |
| if (this.dropdown) { |
| this.dropdown.close(); |
| } |
| }, |
| |
| /** |
| * Sets or gets the selection data. |
| * |
| * The selection data contains both IDs and text labels. If you only want to set or get the IDs, |
| * you should use the value() method. |
| * |
| * @param newData Optional new data to set. For a MultipleSelectivity instance the data must be |
| * an array of objects with 'id' and 'text' properties, for a SingleSelectivity |
| * instance the data must be a single such object or null to indicate no item is |
| * selected. |
| * @param options Optional options object. May contain the following property: |
| * triggerChange - Set to false to suppress the "change" event being triggered. |
| * |
| * @return If newData is omitted, this method returns the current data. |
| */ |
| data: function(newData, options) { |
| |
| options = options || {}; |
| |
| if (newData === undefined) { |
| return this._data; |
| } else { |
| newData = this.validateData(newData); |
| |
| this._data = newData; |
| this._value = this.getValueForData(newData); |
| |
| if (options.triggerChange !== false) { |
| this.triggerChange(); |
| } |
| } |
| }, |
| |
| /** |
| * Destroys the Selectivity instance. |
| */ |
| destroy: function() { |
| |
| this.undelegateEvents(); |
| |
| var $el = this.$el; |
| $el.children().remove(); |
| $el[0].selectivity = null; |
| $el = null; |
| }, |
| |
| /** |
| * Filters the results to be displayed in the dropdown. |
| * |
| * The default implementation simply returns the results unfiltered, but the MultipleSelectivity |
| * class overrides this method to filter out any items that have already been selected. |
| * |
| * @param results Array of items with 'id' and 'text' properties. |
| * |
| * @return The filtered array. |
| */ |
| filterResults: function(results) { |
| |
| return results; |
| }, |
| |
| /** |
| * Applies focus to the input. |
| */ |
| focus: function() { |
| |
| if (this.$searchInput) { |
| this.$searchInput.focus(); |
| } |
| }, |
| |
| /** |
| * Returns the correct item for a given ID. |
| * |
| * @param id The ID to get the item for. |
| * |
| * @return The corresponding item. Will be an object with 'id' and 'text' properties or null if |
| * the item cannot be found. Note that if no items are defined, this method assumes the |
| * text labels will be equal to the IDs. |
| */ |
| getItemForId: function(id) { |
| |
| var items = this.items; |
| if (items) { |
| return Selectivity.findNestedById(items, id); |
| } else { |
| return { id: id, text: '' + id }; |
| } |
| }, |
| |
| /** |
| * Initializes the search input element. |
| * |
| * Sets the $searchInput property, invokes all search input listeners and attaches the default |
| * action of searching when something is typed. |
| * |
| * @param $input jQuery container for the input element. |
| * @param options Optional options object. May contain the following property: |
| * noSearch - If false, no event handlers are setup to initiate searching when |
| * the user types in the input field. This is useful if you want to |
| * use the input only to handle keyboard support. |
| */ |
| initSearchInput: function($input, options) { |
| |
| this._$searchInputs.push($input); |
| this.$searchInput = $input; |
| |
| this.searchInputListeners.forEach(function(listener) { |
| listener(this, $input); |
| }.bind(this)); |
| |
| if (!options || options.noSearch !== false) { |
| $input.on('keyup', function(event) { |
| if (!event.isDefaultPrevented()) { |
| this.search(); |
| } |
| }.bind(this)); |
| } |
| }, |
| |
| /** |
| * Loads a follow-up page with results after a search. |
| * |
| * This method should only be called after a call to search() when the callback has indicated |
| * more results are available. |
| */ |
| loadMore: function() { |
| |
| this.options.query({ |
| callback: function(response) { |
| if (response && response.results) { |
| this._addResults( |
| Selectivity.processItems(response.results), |
| { hasMore: !!response.more } |
| ); |
| } else { |
| throw new Error('callback must be passed a response object'); |
| } |
| }.bind(this), |
| error: this._addResults.bind(this, []), |
| offset: this.results.length, |
| selectivity: this, |
| term: this.term |
| }); |
| }, |
| |
| /** |
| * Opens the dropdown. |
| * |
| * @param options Optional options object. May contain the following property: |
| * showSearchInput - Boolean whether a search input should be shown in the |
| * dropdown. Default is false. |
| */ |
| open: function(options) { |
| |
| options = options || {}; |
| |
| if (!this.dropdown) { |
| if (this.triggerEvent('selectivity-opening')) { |
| var Dropdown = this.options.dropdown || Selectivity.Dropdown; |
| if (Dropdown) { |
| this.dropdown = new Dropdown({ |
| position: this.options.positionDropdown, |
| selectivity: this, |
| showSearchInput: options.showSearchInput |
| }); |
| } |
| |
| this.search(''); |
| } |
| } |
| }, |
| |
| /** |
| * (Re-)positions the dropdown. |
| */ |
| positionDropdown: function() { |
| |
| if (this.dropdown) { |
| this.dropdown.position(); |
| } |
| }, |
| |
| /** |
| * Removes the search input last initialized with initSearchInput(). |
| */ |
| removeSearchInput: function() { |
| |
| this._$searchInputs.pop(); |
| |
| this.$searchInput = this._$searchInputs[this._$searchInputs.length - 1] || null; |
| }, |
| |
| /** |
| * Searches for results based on the term entered in the search input. |
| * |
| * If an items array has been passed with the options to the Selectivity instance, a local |
| * search will be performed among those items. Otherwise, the query function specified in the |
| * options will be used to perform the search. If neither is defined, nothing happens. |
| * |
| * @param term Optional term to search for. If ommitted, the value of the search input element |
| * is used as term. |
| */ |
| search: function(term) { |
| |
| var self = this; |
| function setResults(results, resultOptions) { |
| self._setResults(results, $.extend({ term: term }, resultOptions)); |
| } |
| |
| if (term === undefined) { |
| if (!self.$searchInput) { |
| return; |
| } |
| |
| term = self.$searchInput.val(); |
| } |
| |
| if (self.items) { |
| term = Selectivity.transformText(term); |
| var matcher = self.matcher; |
| setResults(self.items.map(function(item) { |
| return matcher(item, term); |
| }).filter(function(item) { |
| return !!item; |
| })); |
| } else if (self.options.query) { |
| self.options.query({ |
| callback: function(response) { |
| if (response && response.results) { |
| setResults( |
| Selectivity.processItems(response.results), |
| { hasMore: !!response.more } |
| ); |
| } else { |
| throw new Error('callback must be passed a response object'); |
| } |
| }, |
| error: self._showError.bind(self), |
| offset: 0, |
| selectivity: self, |
| term: term |
| }); |
| } |
| |
| self.term = term; |
| }, |
| |
| /** |
| * Sets one or more options on this Selectivity instance. |
| * |
| * @param options Options object. May contain one or more of the following properties: |
| * closeOnSelect - Set to false to keep the dropdown open after the user has |
| * selected an item. This is useful if you want to allow the user |
| * to quickly select multiple items. The default value is true. |
| * dropdown - Custom dropdown implementation to use for this instance. |
| * initSelection - Function to map values by ID to selection data. This function |
| * receives two arguments, 'value' and 'callback'. The value is |
| * the current value of the selection, which is an ID or an array |
| * of IDs depending on the input type. The callback should be |
| * invoked with an object or array of objects, respectively, |
| * containing 'id' and 'text' properties. |
| * items - Array of items from which to select. Should be an array of objects |
| * with 'id' and 'text' properties. As convenience, you may also pass an |
| * array of strings, in which case the same string is used for both the |
| * 'id' and 'text' properties. If items are given, all items are expected |
| * to be available locally and all selection operations operate on this |
| * local array only. If null, items are not available locally, and a |
| * query function should be provided to fetch remote data. |
| * matcher - Function to determine whether text matches a given search term. Note |
| * this function is only used if you have specified an array of items. |
| * Receives two arguments: |
| * item - The item that should match the search term. |
| * term - The search term. Note that for performance reasons, the term |
| * has always been already processed using |
| * Selectivity.transformText(). |
| * The method should return the item if it matches, and null otherwise. |
| * If the item has a children array, the matcher is expected to filter |
| * those itself (be sure to only return the filtered array of children |
| * in the returned item and not to modify the children of the item |
| * argument). |
| * placeholder - Placeholder text to display when the element has no focus and |
| * no selected items. |
| * positionDropdown - Function to position the dropdown. Receives two arguments: |
| * $dropdownEl - The element to be positioned. |
| * $selectEl - The element of the Selectivity instance, that |
| * you can position the dropdown to. |
| * The default implementation positions the dropdown element |
| * under the Selectivity's element and gives it the same |
| * width. |
| * query - Function to use for querying items. Receives a single object as |
| * argument with the following properties: |
| * callback - Callback to invoke when the results are available. This |
| * callback should be passed a single object as argument with |
| * the following properties: |
| * more - Boolean that can be set to true to indicate there |
| * are more results available. Additional results may |
| * be fetched by the user through pagination. |
| * results - Array of result items. The format for the result |
| * items is the same as for passing local items. |
| * offset - This property is only used for pagination and indicates how |
| * many results should be skipped when returning more results. |
| * selectivity - The Selectivity instance the query function is used on. |
| * term - The search term the user is searching for. Unlike with the |
| * matcher function, the term has not been processed using |
| * Selectivity.transformText(). |
| * readOnly - If true, disables any modification of the input. |
| * removeOnly - If true, disables any modification of the input except removing |
| * of selected items. |
| * searchInputListeners - Array of search input listeners. By default, the global |
| * array Selectivity.SearchInputListeners is used. |
| * showDropdown - Set to false if you don't want to use any dropdown (you can |
| * still open it programmatically using open()). |
| * templates - Object with instance-specific templates to override the global |
| * templates assigned to Selectivity.Templates. |
| */ |
| setOptions: function(options) { |
| |
| options = options || {}; |
| |
| Selectivity.OptionListeners.forEach(function(listener) { |
| listener(this, options); |
| }.bind(this)); |
| |
| $.extend(this.options, options); |
| |
| var allowedTypes = $.extend({ |
| closeOnSelect: 'boolean', |
| dropdown: 'function|null', |
| initSelection: 'function|null', |
| matcher: 'function|null', |
| placeholder: 'string', |
| positionDropdown: 'function|null', |
| query: 'function|null', |
| readOnly: 'boolean', |
| removeOnly: 'boolean', |
| searchInputListeners: 'array' |
| }, options.allowedTypes); |
| |
| $.each(options, function(key, value) { |
| var type = allowedTypes[key]; |
| if (type && !type.split('|').some(function(type) { return $.type(value) === type; })) { |
| throw new Error(key + ' must be of type ' + type); |
| } |
| |
| switch (key) { |
| case 'items': |
| this.items = (value === null ? value : Selectivity.processItems(value)); |
| break; |
| |
| case 'matcher': |
| this.matcher = value; |
| break; |
| |
| case 'searchInputListeners': |
| this.searchInputListeners = value; |
| break; |
| |
| case 'templates': |
| $.extend(this.templates, value); |
| break; |
| } |
| }.bind(this)); |
| |
| this.enabled = (!this.options.readOnly && !this.options.removeOnly); |
| }, |
| |
| /** |
| * Returns the result of the given template. |
| * |
| * @param templateName Name of the template to process. |
| * @param options Options to pass to the template. |
| * |
| * @return String containing HTML. |
| */ |
| template: function(templateName, options) { |
| |
| var template = this.templates[templateName]; |
| if (template) { |
| if ($.type(template) === 'function') { |
| return template(options); |
| } else if (template.render) { |
| return template.render(options); |
| } else { |
| return template.toString(); |
| } |
| } else { |
| throw new Error('Unknown template: ' + templateName); |
| } |
| }, |
| |
| /** |
| * Triggers the change event. |
| * |
| * The event object at least contains the following property: |
| * value - The new value of the Selectivity instance. |
| * |
| * @param Optional additional options added to the event object. |
| */ |
| triggerChange: function(options) { |
| |
| this.triggerEvent('change', $.extend({ value: this._value }, options)); |
| }, |
| |
| /** |
| * Triggers an event on the instance's element. |
| * |
| * @param Optional event data to be added to the event object. |
| * |
| * @return Whether the default action of the event may be executed, ie. returns false if |
| * preventDefault() has been called. |
| */ |
| triggerEvent: function(eventName, data) { |
| |
| var event = $.Event(eventName, data || {}); |
| this.$el.trigger(event); |
| return !event.isDefaultPrevented(); |
| }, |
| |
| /** |
| * Shorthand for value(). |
| */ |
| val: function(newValue) { |
| |
| return this.value(newValue); |
| }, |
| |
| /** |
| * Validates a single item. Throws an exception if the item is invalid. |
| * |
| * @param item The item to validate. |
| * |
| * @return The validated item. May differ from the input item. |
| */ |
| validateItem: function(item) { |
| |
| if (item && Selectivity.isValidId(item.id) && $.type(item.text) === 'string') { |
| return item; |
| } else { |
| throw new Error('Item should have id (number or string) and text (string) properties'); |
| } |
| }, |
| |
| /** |
| * Sets or gets the value of the selection. |
| * |
| * The value of the selection only concerns the IDs of the selection items. If you are |
| * interested in the IDs and the text labels, you should use the data() method. |
| * |
| * Note that if neither the items option nor the initSelection option have been set, Selectivity |
| * will have no way to determine what text labels should be used with the given IDs in which |
| * case it will assume the text is equal to the ID. This is useful if you're working with tags, |
| * or selecting e-mail addresses for instance, but may not always be what you want. |
| * |
| * @param newValue Optional new value to set. For a MultipleSelectivity instance the value must be |
| * an array of IDs, for a SingleSelectivity instance the value must be a single ID |
| * (a string or a number) or null to indicate no item is selected. |
| * @param options Optional options object. May contain the following property: |
| * triggerChange - Set to false to suppress the "change" event being triggered. |
| * |
| * @return If newValue is omitted, this method returns the current value. |
| */ |
| value: function(newValue, options) { |
| |
| options = options || {}; |
| |
| if (newValue === undefined) { |
| return this._value; |
| } else { |
| newValue = this.validateValue(newValue); |
| |
| this._value = newValue; |
| |
| if (this.options.initSelection) { |
| this.options.initSelection(newValue, function(data) { |
| if (this._value === newValue) { |
| this._data = this.validateData(data); |
| |
| if (options.triggerChange !== false) { |
| this.triggerChange(); |
| } |
| } |
| }.bind(this)); |
| } else { |
| this._data = this.getDataForValue(newValue); |
| |
| if (options.triggerChange !== false) { |
| this.triggerChange(); |
| } |
| } |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _addResults: function(results, options) { |
| |
| this.results = this.results.concat(results); |
| |
| if (this.dropdown) { |
| this.dropdown.showResults( |
| this.filterResults(results), |
| $.extend({ add: true }, options) |
| ); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _closed: function() { |
| |
| this.dropdown = null; |
| }, |
| |
| /** |
| * @private |
| */ |
| _getItemId: function(elementOrEvent) { |
| |
| // returns the item ID related to an element or event target. |
| // IDs can be either numbers or strings, but attribute values are always strings, so we |
| // will have to find out whether the item ID ought to be a number or string ourselves. |
| // $.fn.data() is a bit overzealous for our case, because it returns a number whenever the |
| // attribute value can be parsed as a number. however, it is possible an item had an ID |
| // which is a string but which is parseable as number, in which case we verify if the ID |
| // as number is actually found among the data or results. if it isn't, we assume it was |
| // supposed to be a string after all... |
| |
| var $element; |
| if (elementOrEvent.target) { |
| $element = $(elementOrEvent.target).closest('[data-item-id]'); |
| } else if (elementOrEvent.length) { |
| $element = elementOrEvent; |
| } else { |
| $element = $(elementOrEvent); |
| } |
| |
| var id = $element.data('item-id'); |
| if ($.type(id) === 'string') { |
| return id; |
| } else { |
| if (Selectivity.findById(this._data || [], id) || |
| Selectivity.findNestedById(this.results, id)) { |
| return id; |
| } else { |
| return '' + id; |
| } |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _setResults: function(results, options) { |
| |
| this.results = results; |
| |
| if (this.dropdown) { |
| this.dropdown.showResults(this.filterResults(results), options || {}); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _showError: function(error, options) { |
| |
| this.results = []; |
| |
| if (this.dropdown) { |
| this.dropdown.showError(error, options); |
| } |
| } |
| |
| }); |
| |
| /** |
| * Dropdown class to use for displaying dropdowns. |
| * |
| * The default implementation of a dropdown is defined in the selectivity-dropdown module. |
| */ |
| Selectivity.Dropdown = null; |
| |
| /** |
| * Mapping of input types. |
| */ |
| Selectivity.InputTypes = {}; |
| |
| /** |
| * Array of option listeners. |
| * |
| * Option listeners are invoked when setOptions() is called. Every listener receives two arguments: |
| * |
| * selectivity - The Selectivity instance. |
| * options - The options that are about to be set. The listener may modify this options object. |
| * |
| * An example of an option listener is the selectivity-traditional module. |
| */ |
| Selectivity.OptionListeners = []; |
| |
| /** |
| * Array of search input listeners. |
| * |
| * Search input listeners are invoked when initSearchInput() is called (typically right after the |
| * search input is created). Every listener receives two arguments: |
| * |
| * selectivity - The Selectivity instance. |
| * $input - jQuery container with the search input. |
| * |
| * An example of a search input listener is the selectivity-keyboard module. |
| */ |
| Selectivity.SearchInputListeners = []; |
| |
| /** |
| * Mapping with templates to use for rendering select boxes and dropdowns. See |
| * selectivity-templates.js for a useful set of default templates, as well as for documentation of |
| * the individual templates. |
| */ |
| Selectivity.Templates = {}; |
| |
| /** |
| * Finds an item in the given array with the specified ID. |
| * |
| * @param array Array to search in. |
| * @param id ID to search for. |
| * |
| * @return The item in the array with the given ID, or null if the item was not found. |
| */ |
| Selectivity.findById = function(array, id) { |
| |
| var index = Selectivity.findIndexById(array, id); |
| return (index > -1 ? array[index] : null); |
| }; |
| |
| /** |
| * Finds the index of an item in the given array with the specified ID. |
| * |
| * @param array Array to search in. |
| * @param id ID to search for. |
| * |
| * @return The index of the item in the array with the given ID, or -1 if the item was not found. |
| */ |
| Selectivity.findIndexById = function(array, id) { |
| |
| for (var i = 0, length = array.length; i < length; i++) { |
| if (array[i].id === id) { |
| return i; |
| } |
| } |
| return -1; |
| }; |
| |
| /** |
| * Finds an item in the given array with the specified ID. Items in the array may contain 'children' |
| * properties which in turn will be searched for the item. |
| * |
| * @param array Array to search in. |
| * @param id ID to search for. |
| * |
| * @return The item in the array with the given ID, or null if the item was not found. |
| */ |
| Selectivity.findNestedById = null && function(array, id) { |
| |
| for (var i = 0, length = array.length; i < length; i++) { |
| var item = array[i]; |
| if (item.id === id) { |
| return item; |
| } else if (item.children) { |
| var result = Selectivity.findNestedById(item.children, id); |
| if (result) { |
| return result; |
| } |
| } |
| } |
| return null; |
| }; |
| |
| /** |
| * Utility method for inheriting another class. |
| * |
| * @param SubClass Constructor function of the subclass. |
| * @param SuperClass Optional constructor function of the superclass. If omitted, Selectivity is |
| * used as superclass. |
| * @param prototype Object with methods you want to add to the subclass prototype. |
| * |
| * @return A utility function for calling the methods of the superclass. This function receives two |
| * arguments: The this object on which you want to execute the method and the name of the |
| * method. Any arguments past those are passed to the superclass method. |
| */ |
| Selectivity.inherits = function(SubClass, SuperClass, prototype) { |
| |
| if (arguments.length === 2) { |
| prototype = SuperClass; |
| SuperClass = Selectivity; |
| } |
| |
| SubClass.prototype = $.extend( |
| Object.create(SuperClass.prototype), |
| { constructor: SubClass }, |
| prototype |
| ); |
| |
| return function(self, methodName) { |
| SuperClass.prototype[methodName].apply(self, Array.prototype.slice.call(arguments, 2)); |
| }; |
| }; |
| |
| /** |
| * Checks whether a value can be used as a valid ID for selection items. Only numbers and strings |
| * are accepted to be used as IDs. |
| * |
| * @param id The value to check whether it is a valid ID. |
| * |
| * @return true if the value is a valid ID, false otherwise. |
| */ |
| Selectivity.isValidId = function(id) { |
| |
| var type = $.type(id); |
| return type === 'number' || type === 'string'; |
| }; |
| |
| /** |
| * Decides whether a given item matches a search term. The default implementation simply |
| * checks whether the term is contained within the item's text, after transforming them using |
| * transformText(). |
| * |
| * @param item The item that should match the search term. |
| * @param term The search term. Note that for performance reasons, the term has always been already |
| * processed using transformText(). |
| * |
| * @return true if the text matches the term, false otherwise. |
| */ |
| Selectivity.matcher = function(item, term) { |
| |
| var result = null; |
| if (Selectivity.transformText(item.text).indexOf(term) > -1) { |
| result = item; |
| } else if (item.children) { |
| var matchingChildren = item.children.map(function(child) { |
| return Selectivity.matcher(child, term); |
| }).filter(function(child) { |
| return !!child; |
| }); |
| if (matchingChildren.length) { |
| result = { id: item.id, text: item.text, children: matchingChildren }; |
| } |
| } |
| return result; |
| }; |
| |
| /** |
| * Helper function for processing items. |
| * |
| * @param item The item to process, either as object containing 'id' and 'text' properties or just |
| * as ID. The 'id' property of an item is optional if it has a 'children' property |
| * containing an array of items. |
| * |
| * @return Object containing 'id' and 'text' properties. |
| */ |
| Selectivity.processItem = function(item) { |
| |
| if (Selectivity.isValidId(item)) { |
| return { id: item, text: '' + item }; |
| } else if (item && |
| (Selectivity.isValidId(item.id) || item.children) && |
| $.type(item.text) === 'string') { |
| if (item.children) { |
| item.children = Selectivity.processItems(item.children); |
| } |
| |
| return item; |
| } else { |
| throw new Error('invalid item'); |
| } |
| }; |
| |
| /** |
| * Helper function for processing an array of items. |
| * |
| * @param items Array of items to process. See processItem() for details about a single item. |
| * |
| * @return Array with items. |
| */ |
| Selectivity.processItems = function(items) { |
| |
| if ($.type(items) === 'array') { |
| return items.map(Selectivity.processItem); |
| } else { |
| throw new Error('invalid items'); |
| } |
| }; |
| |
| /** |
| * Quotes a string so it can be used in a CSS attribute selector. It adds double quotes to the |
| * string and escapes all occurrences of the quote character inside the string. |
| * |
| * @param string The string to quote. |
| * |
| * @return The quoted string. |
| */ |
| Selectivity.quoteCssAttr = function(string) { |
| |
| return '"' + ('' + string).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'; |
| }; |
| |
| /** |
| * Transforms text in order to find matches. The default implementation casts all strings to |
| * lower-case so that any matches found will be case-insensitive. |
| * |
| * @param string The string to transform. |
| * |
| * @return The transformed string. |
| */ |
| Selectivity.transformText = function(string) { |
| |
| return string.toLowerCase(); |
| }; |
| |
| module.exports = $.fn.selectivity = Selectivity; |
| |
| },{"2":2,"jquery":"jquery"}],9:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var DIACRITICS = { |
| '\u24B6': 'A', |
| '\uFF21': 'A', |
| '\u00C0': 'A', |
| '\u00C1': 'A', |
| '\u00C2': 'A', |
| '\u1EA6': 'A', |
| '\u1EA4': 'A', |
| '\u1EAA': 'A', |
| '\u1EA8': 'A', |
| '\u00C3': 'A', |
| '\u0100': 'A', |
| '\u0102': 'A', |
| '\u1EB0': 'A', |
| '\u1EAE': 'A', |
| '\u1EB4': 'A', |
| '\u1EB2': 'A', |
| '\u0226': 'A', |
| '\u01E0': 'A', |
| '\u00C4': 'A', |
| '\u01DE': 'A', |
| '\u1EA2': 'A', |
| '\u00C5': 'A', |
| '\u01FA': 'A', |
| '\u01CD': 'A', |
| '\u0200': 'A', |
| '\u0202': 'A', |
| '\u1EA0': 'A', |
| '\u1EAC': 'A', |
| '\u1EB6': 'A', |
| '\u1E00': 'A', |
| '\u0104': 'A', |
| '\u023A': 'A', |
| '\u2C6F': 'A', |
| '\uA732': 'AA', |
| '\u00C6': 'AE', |
| '\u01FC': 'AE', |
| '\u01E2': 'AE', |
| '\uA734': 'AO', |
| '\uA736': 'AU', |
| '\uA738': 'AV', |
| '\uA73A': 'AV', |
| '\uA73C': 'AY', |
| '\u24B7': 'B', |
| '\uFF22': 'B', |
| '\u1E02': 'B', |
| '\u1E04': 'B', |
| '\u1E06': 'B', |
| '\u0243': 'B', |
| '\u0182': 'B', |
| '\u0181': 'B', |
| '\u24B8': 'C', |
| '\uFF23': 'C', |
| '\u0106': 'C', |
| '\u0108': 'C', |
| '\u010A': 'C', |
| '\u010C': 'C', |
| '\u00C7': 'C', |
| '\u1E08': 'C', |
| '\u0187': 'C', |
| '\u023B': 'C', |
| '\uA73E': 'C', |
| '\u24B9': 'D', |
| '\uFF24': 'D', |
| '\u1E0A': 'D', |
| '\u010E': 'D', |
| '\u1E0C': 'D', |
| '\u1E10': 'D', |
| '\u1E12': 'D', |
| '\u1E0E': 'D', |
| '\u0110': 'D', |
| '\u018B': 'D', |
| '\u018A': 'D', |
| '\u0189': 'D', |
| '\uA779': 'D', |
| '\u01F1': 'DZ', |
| '\u01C4': 'DZ', |
| '\u01F2': 'Dz', |
| '\u01C5': 'Dz', |
| '\u24BA': 'E', |
| '\uFF25': 'E', |
| '\u00C8': 'E', |
| '\u00C9': 'E', |
| '\u00CA': 'E', |
| '\u1EC0': 'E', |
| '\u1EBE': 'E', |
| '\u1EC4': 'E', |
| '\u1EC2': 'E', |
| '\u1EBC': 'E', |
| '\u0112': 'E', |
| '\u1E14': 'E', |
| '\u1E16': 'E', |
| '\u0114': 'E', |
| '\u0116': 'E', |
| '\u00CB': 'E', |
| '\u1EBA': 'E', |
| '\u011A': 'E', |
| '\u0204': 'E', |
| '\u0206': 'E', |
| '\u1EB8': 'E', |
| '\u1EC6': 'E', |
| '\u0228': 'E', |
| '\u1E1C': 'E', |
| '\u0118': 'E', |
| '\u1E18': 'E', |
| '\u1E1A': 'E', |
| '\u0190': 'E', |
| '\u018E': 'E', |
| '\u24BB': 'F', |
| '\uFF26': 'F', |
| '\u1E1E': 'F', |
| '\u0191': 'F', |
| '\uA77B': 'F', |
| '\u24BC': 'G', |
| '\uFF27': 'G', |
| '\u01F4': 'G', |
| '\u011C': 'G', |
| '\u1E20': 'G', |
| '\u011E': 'G', |
| '\u0120': 'G', |
| '\u01E6': 'G', |
| '\u0122': 'G', |
| '\u01E4': 'G', |
| '\u0193': 'G', |
| '\uA7A0': 'G', |
| '\uA77D': 'G', |
| '\uA77E': 'G', |
| '\u24BD': 'H', |
| '\uFF28': 'H', |
| '\u0124': 'H', |
| '\u1E22': 'H', |
| '\u1E26': 'H', |
| '\u021E': 'H', |
| '\u1E24': 'H', |
| '\u1E28': 'H', |
| '\u1E2A': 'H', |
| '\u0126': 'H', |
| '\u2C67': 'H', |
| '\u2C75': 'H', |
| '\uA78D': 'H', |
| '\u24BE': 'I', |
| '\uFF29': 'I', |
| '\u00CC': 'I', |
| '\u00CD': 'I', |
| '\u00CE': 'I', |
| '\u0128': 'I', |
| '\u012A': 'I', |
| '\u012C': 'I', |
| '\u0130': 'I', |
| '\u00CF': 'I', |
| '\u1E2E': 'I', |
| '\u1EC8': 'I', |
| '\u01CF': 'I', |
| '\u0208': 'I', |
| '\u020A': 'I', |
| '\u1ECA': 'I', |
| '\u012E': 'I', |
| '\u1E2C': 'I', |
| '\u0197': 'I', |
| '\u24BF': 'J', |
| '\uFF2A': 'J', |
| '\u0134': 'J', |
| '\u0248': 'J', |
| '\u24C0': 'K', |
| '\uFF2B': 'K', |
| '\u1E30': 'K', |
| '\u01E8': 'K', |
| '\u1E32': 'K', |
| '\u0136': 'K', |
| '\u1E34': 'K', |
| '\u0198': 'K', |
| '\u2C69': 'K', |
| '\uA740': 'K', |
| '\uA742': 'K', |
| '\uA744': 'K', |
| '\uA7A2': 'K', |
| '\u24C1': 'L', |
| '\uFF2C': 'L', |
| '\u013F': 'L', |
| '\u0139': 'L', |
| '\u013D': 'L', |
| '\u1E36': 'L', |
| '\u1E38': 'L', |
| '\u013B': 'L', |
| '\u1E3C': 'L', |
| '\u1E3A': 'L', |
| '\u0141': 'L', |
| '\u023D': 'L', |
| '\u2C62': 'L', |
| '\u2C60': 'L', |
| '\uA748': 'L', |
| '\uA746': 'L', |
| '\uA780': 'L', |
| '\u01C7': 'LJ', |
| '\u01C8': 'Lj', |
| '\u24C2': 'M', |
| '\uFF2D': 'M', |
| '\u1E3E': 'M', |
| '\u1E40': 'M', |
| '\u1E42': 'M', |
| '\u2C6E': 'M', |
| '\u019C': 'M', |
| '\u24C3': 'N', |
| '\uFF2E': 'N', |
| '\u01F8': 'N', |
| '\u0143': 'N', |
| '\u00D1': 'N', |
| '\u1E44': 'N', |
| '\u0147': 'N', |
| '\u1E46': 'N', |
| '\u0145': 'N', |
| '\u1E4A': 'N', |
| '\u1E48': 'N', |
| '\u0220': 'N', |
| '\u019D': 'N', |
| '\uA790': 'N', |
| '\uA7A4': 'N', |
| '\u01CA': 'NJ', |
| '\u01CB': 'Nj', |
| '\u24C4': 'O', |
| '\uFF2F': 'O', |
| '\u00D2': 'O', |
| '\u00D3': 'O', |
| '\u00D4': 'O', |
| '\u1ED2': 'O', |
| '\u1ED0': 'O', |
| '\u1ED6': 'O', |
| '\u1ED4': 'O', |
| '\u00D5': 'O', |
| '\u1E4C': 'O', |
| '\u022C': 'O', |
| '\u1E4E': 'O', |
| '\u014C': 'O', |
| '\u1E50': 'O', |
| '\u1E52': 'O', |
| '\u014E': 'O', |
| '\u022E': 'O', |
| '\u0230': 'O', |
| '\u00D6': 'O', |
| '\u022A': 'O', |
| '\u1ECE': 'O', |
| '\u0150': 'O', |
| '\u01D1': 'O', |
| '\u020C': 'O', |
| '\u020E': 'O', |
| '\u01A0': 'O', |
| '\u1EDC': 'O', |
| '\u1EDA': 'O', |
| '\u1EE0': 'O', |
| '\u1EDE': 'O', |
| '\u1EE2': 'O', |
| '\u1ECC': 'O', |
| '\u1ED8': 'O', |
| '\u01EA': 'O', |
| '\u01EC': 'O', |
| '\u00D8': 'O', |
| '\u01FE': 'O', |
| '\u0186': 'O', |
| '\u019F': 'O', |
| '\uA74A': 'O', |
| '\uA74C': 'O', |
| '\u01A2': 'OI', |
| '\uA74E': 'OO', |
| '\u0222': 'OU', |
| '\u24C5': 'P', |
| '\uFF30': 'P', |
| '\u1E54': 'P', |
| '\u1E56': 'P', |
| '\u01A4': 'P', |
| '\u2C63': 'P', |
| '\uA750': 'P', |
| '\uA752': 'P', |
| '\uA754': 'P', |
| '\u24C6': 'Q', |
| '\uFF31': 'Q', |
| '\uA756': 'Q', |
| '\uA758': 'Q', |
| '\u024A': 'Q', |
| '\u24C7': 'R', |
| '\uFF32': 'R', |
| '\u0154': 'R', |
| '\u1E58': 'R', |
| '\u0158': 'R', |
| '\u0210': 'R', |
| '\u0212': 'R', |
| '\u1E5A': 'R', |
| '\u1E5C': 'R', |
| '\u0156': 'R', |
| '\u1E5E': 'R', |
| '\u024C': 'R', |
| '\u2C64': 'R', |
| '\uA75A': 'R', |
| '\uA7A6': 'R', |
| '\uA782': 'R', |
| '\u24C8': 'S', |
| '\uFF33': 'S', |
| '\u1E9E': 'S', |
| '\u015A': 'S', |
| '\u1E64': 'S', |
| '\u015C': 'S', |
| '\u1E60': 'S', |
| '\u0160': 'S', |
| '\u1E66': 'S', |
| '\u1E62': 'S', |
| '\u1E68': 'S', |
| '\u0218': 'S', |
| '\u015E': 'S', |
| '\u2C7E': 'S', |
| '\uA7A8': 'S', |
| '\uA784': 'S', |
| '\u24C9': 'T', |
| '\uFF34': 'T', |
| '\u1E6A': 'T', |
| '\u0164': 'T', |
| '\u1E6C': 'T', |
| '\u021A': 'T', |
| '\u0162': 'T', |
| '\u1E70': 'T', |
| '\u1E6E': 'T', |
| '\u0166': 'T', |
| '\u01AC': 'T', |
| '\u01AE': 'T', |
| '\u023E': 'T', |
| '\uA786': 'T', |
| '\uA728': 'TZ', |
| '\u24CA': 'U', |
| '\uFF35': 'U', |
| '\u00D9': 'U', |
| '\u00DA': 'U', |
| '\u00DB': 'U', |
| '\u0168': 'U', |
| '\u1E78': 'U', |
| '\u016A': 'U', |
| '\u1E7A': 'U', |
| '\u016C': 'U', |
| '\u00DC': 'U', |
| '\u01DB': 'U', |
| '\u01D7': 'U', |
| '\u01D5': 'U', |
| '\u01D9': 'U', |
| '\u1EE6': 'U', |
| '\u016E': 'U', |
| '\u0170': 'U', |
| '\u01D3': 'U', |
| '\u0214': 'U', |
| '\u0216': 'U', |
| '\u01AF': 'U', |
| '\u1EEA': 'U', |
| '\u1EE8': 'U', |
| '\u1EEE': 'U', |
| '\u1EEC': 'U', |
| '\u1EF0': 'U', |
| '\u1EE4': 'U', |
| '\u1E72': 'U', |
| '\u0172': 'U', |
| '\u1E76': 'U', |
| '\u1E74': 'U', |
| '\u0244': 'U', |
| '\u24CB': 'V', |
| '\uFF36': 'V', |
| '\u1E7C': 'V', |
| '\u1E7E': 'V', |
| '\u01B2': 'V', |
| '\uA75E': 'V', |
| '\u0245': 'V', |
| '\uA760': 'VY', |
| '\u24CC': 'W', |
| '\uFF37': 'W', |
| '\u1E80': 'W', |
| '\u1E82': 'W', |
| '\u0174': 'W', |
| '\u1E86': 'W', |
| '\u1E84': 'W', |
| '\u1E88': 'W', |
| '\u2C72': 'W', |
| '\u24CD': 'X', |
| '\uFF38': 'X', |
| '\u1E8A': 'X', |
| '\u1E8C': 'X', |
| '\u24CE': 'Y', |
| '\uFF39': 'Y', |
| '\u1EF2': 'Y', |
| '\u00DD': 'Y', |
| '\u0176': 'Y', |
| '\u1EF8': 'Y', |
| '\u0232': 'Y', |
| '\u1E8E': 'Y', |
| '\u0178': 'Y', |
| '\u1EF6': 'Y', |
| '\u1EF4': 'Y', |
| '\u01B3': 'Y', |
| '\u024E': 'Y', |
| '\u1EFE': 'Y', |
| '\u24CF': 'Z', |
| '\uFF3A': 'Z', |
| '\u0179': 'Z', |
| '\u1E90': 'Z', |
| '\u017B': 'Z', |
| '\u017D': 'Z', |
| '\u1E92': 'Z', |
| '\u1E94': 'Z', |
| '\u01B5': 'Z', |
| '\u0224': 'Z', |
| '\u2C7F': 'Z', |
| '\u2C6B': 'Z', |
| '\uA762': 'Z', |
| '\u24D0': 'a', |
| '\uFF41': 'a', |
| '\u1E9A': 'a', |
| '\u00E0': 'a', |
| '\u00E1': 'a', |
| '\u00E2': 'a', |
| '\u1EA7': 'a', |
| '\u1EA5': 'a', |
| '\u1EAB': 'a', |
| '\u1EA9': 'a', |
| '\u00E3': 'a', |
| '\u0101': 'a', |
| '\u0103': 'a', |
| '\u1EB1': 'a', |
| '\u1EAF': 'a', |
| '\u1EB5': 'a', |
| '\u1EB3': 'a', |
| '\u0227': 'a', |
| '\u01E1': 'a', |
| '\u00E4': 'a', |
| '\u01DF': 'a', |
| '\u1EA3': 'a', |
| '\u00E5': 'a', |
| '\u01FB': 'a', |
| '\u01CE': 'a', |
| '\u0201': 'a', |
| '\u0203': 'a', |
| '\u1EA1': 'a', |
| '\u1EAD': 'a', |
| '\u1EB7': 'a', |
| '\u1E01': 'a', |
| '\u0105': 'a', |
| '\u2C65': 'a', |
| '\u0250': 'a', |
| '\uA733': 'aa', |
| '\u00E6': 'ae', |
| '\u01FD': 'ae', |
| '\u01E3': 'ae', |
| '\uA735': 'ao', |
| '\uA737': 'au', |
| '\uA739': 'av', |
| '\uA73B': 'av', |
| '\uA73D': 'ay', |
| '\u24D1': 'b', |
| '\uFF42': 'b', |
| '\u1E03': 'b', |
| '\u1E05': 'b', |
| '\u1E07': 'b', |
| '\u0180': 'b', |
| '\u0183': 'b', |
| '\u0253': 'b', |
| '\u24D2': 'c', |
| '\uFF43': 'c', |
| '\u0107': 'c', |
| '\u0109': 'c', |
| '\u010B': 'c', |
| '\u010D': 'c', |
| '\u00E7': 'c', |
| '\u1E09': 'c', |
| '\u0188': 'c', |
| '\u023C': 'c', |
| '\uA73F': 'c', |
| '\u2184': 'c', |
| '\u24D3': 'd', |
| '\uFF44': 'd', |
| '\u1E0B': 'd', |
| '\u010F': 'd', |
| '\u1E0D': 'd', |
| '\u1E11': 'd', |
| '\u1E13': 'd', |
| '\u1E0F': 'd', |
| '\u0111': 'd', |
| '\u018C': 'd', |
| '\u0256': 'd', |
| '\u0257': 'd', |
| '\uA77A': 'd', |
| '\u01F3': 'dz', |
| '\u01C6': 'dz', |
| '\u24D4': 'e', |
| '\uFF45': 'e', |
| '\u00E8': 'e', |
| '\u00E9': 'e', |
| '\u00EA': 'e', |
| '\u1EC1': 'e', |
| '\u1EBF': 'e', |
| '\u1EC5': 'e', |
| '\u1EC3': 'e', |
| '\u1EBD': 'e', |
| '\u0113': 'e', |
| '\u1E15': 'e', |
| '\u1E17': 'e', |
| '\u0115': 'e', |
| '\u0117': 'e', |
| '\u00EB': 'e', |
| '\u1EBB': 'e', |
| '\u011B': 'e', |
| '\u0205': 'e', |
| '\u0207': 'e', |
| '\u1EB9': 'e', |
| '\u1EC7': 'e', |
| '\u0229': 'e', |
| '\u1E1D': 'e', |
| '\u0119': 'e', |
| '\u1E19': 'e', |
| '\u1E1B': 'e', |
| '\u0247': 'e', |
| '\u025B': 'e', |
| '\u01DD': 'e', |
| '\u24D5': 'f', |
| '\uFF46': 'f', |
| '\u1E1F': 'f', |
| '\u0192': 'f', |
| '\uA77C': 'f', |
| '\u24D6': 'g', |
| '\uFF47': 'g', |
| '\u01F5': 'g', |
| '\u011D': 'g', |
| '\u1E21': 'g', |
| '\u011F': 'g', |
| '\u0121': 'g', |
| '\u01E7': 'g', |
| '\u0123': 'g', |
| '\u01E5': 'g', |
| '\u0260': 'g', |
| '\uA7A1': 'g', |
| '\u1D79': 'g', |
| '\uA77F': 'g', |
| '\u24D7': 'h', |
| '\uFF48': 'h', |
| '\u0125': 'h', |
| '\u1E23': 'h', |
| '\u1E27': 'h', |
| '\u021F': 'h', |
| '\u1E25': 'h', |
| '\u1E29': 'h', |
| '\u1E2B': 'h', |
| '\u1E96': 'h', |
| '\u0127': 'h', |
| '\u2C68': 'h', |
| '\u2C76': 'h', |
| '\u0265': 'h', |
| '\u0195': 'hv', |
| '\u24D8': 'i', |
| '\uFF49': 'i', |
| '\u00EC': 'i', |
| '\u00ED': 'i', |
| '\u00EE': 'i', |
| '\u0129': 'i', |
| '\u012B': 'i', |
| '\u012D': 'i', |
| '\u00EF': 'i', |
| '\u1E2F': 'i', |
| '\u1EC9': 'i', |
| '\u01D0': 'i', |
| '\u0209': 'i', |
| '\u020B': 'i', |
| '\u1ECB': 'i', |
| '\u012F': 'i', |
| '\u1E2D': 'i', |
| '\u0268': 'i', |
| '\u0131': 'i', |
| '\u24D9': 'j', |
| '\uFF4A': 'j', |
| '\u0135': 'j', |
| '\u01F0': 'j', |
| '\u0249': 'j', |
| '\u24DA': 'k', |
| '\uFF4B': 'k', |
| '\u1E31': 'k', |
| '\u01E9': 'k', |
| '\u1E33': 'k', |
| '\u0137': 'k', |
| '\u1E35': 'k', |
| '\u0199': 'k', |
| '\u2C6A': 'k', |
| '\uA741': 'k', |
| '\uA743': 'k', |
| '\uA745': 'k', |
| '\uA7A3': 'k', |
| '\u24DB': 'l', |
| '\uFF4C': 'l', |
| '\u0140': 'l', |
| '\u013A': 'l', |
| '\u013E': 'l', |
| '\u1E37': 'l', |
| '\u1E39': 'l', |
| '\u013C': 'l', |
| '\u1E3D': 'l', |
| '\u1E3B': 'l', |
| '\u017F': 'l', |
| '\u0142': 'l', |
| '\u019A': 'l', |
| '\u026B': 'l', |
| '\u2C61': 'l', |
| '\uA749': 'l', |
| '\uA781': 'l', |
| '\uA747': 'l', |
| '\u01C9': 'lj', |
| '\u24DC': 'm', |
| '\uFF4D': 'm', |
| '\u1E3F': 'm', |
| '\u1E41': 'm', |
| '\u1E43': 'm', |
| '\u0271': 'm', |
| '\u026F': 'm', |
| '\u24DD': 'n', |
| '\uFF4E': 'n', |
| '\u01F9': 'n', |
| '\u0144': 'n', |
| '\u00F1': 'n', |
| '\u1E45': 'n', |
| '\u0148': 'n', |
| '\u1E47': 'n', |
| '\u0146': 'n', |
| '\u1E4B': 'n', |
| '\u1E49': 'n', |
| '\u019E': 'n', |
| '\u0272': 'n', |
| '\u0149': 'n', |
| '\uA791': 'n', |
| '\uA7A5': 'n', |
| '\u01CC': 'nj', |
| '\u24DE': 'o', |
| '\uFF4F': 'o', |
| '\u00F2': 'o', |
| '\u00F3': 'o', |
| '\u00F4': 'o', |
| '\u1ED3': 'o', |
| '\u1ED1': 'o', |
| '\u1ED7': 'o', |
| '\u1ED5': 'o', |
| '\u00F5': 'o', |
| '\u1E4D': 'o', |
| '\u022D': 'o', |
| '\u1E4F': 'o', |
| '\u014D': 'o', |
| '\u1E51': 'o', |
| '\u1E53': 'o', |
| '\u014F': 'o', |
| '\u022F': 'o', |
| '\u0231': 'o', |
| '\u00F6': 'o', |
| '\u022B': 'o', |
| '\u1ECF': 'o', |
| '\u0151': 'o', |
| '\u01D2': 'o', |
| '\u020D': 'o', |
| '\u020F': 'o', |
| '\u01A1': 'o', |
| '\u1EDD': 'o', |
| '\u1EDB': 'o', |
| '\u1EE1': 'o', |
| '\u1EDF': 'o', |
| '\u1EE3': 'o', |
| '\u1ECD': 'o', |
| '\u1ED9': 'o', |
| '\u01EB': 'o', |
| '\u01ED': 'o', |
| '\u00F8': 'o', |
| '\u01FF': 'o', |
| '\u0254': 'o', |
| '\uA74B': 'o', |
| '\uA74D': 'o', |
| '\u0275': 'o', |
| '\u01A3': 'oi', |
| '\u0223': 'ou', |
| '\uA74F': 'oo', |
| '\u24DF': 'p', |
| '\uFF50': 'p', |
| '\u1E55': 'p', |
| '\u1E57': 'p', |
| '\u01A5': 'p', |
| '\u1D7D': 'p', |
| '\uA751': 'p', |
| '\uA753': 'p', |
| '\uA755': 'p', |
| '\u24E0': 'q', |
| '\uFF51': 'q', |
| '\u024B': 'q', |
| '\uA757': 'q', |
| '\uA759': 'q', |
| '\u24E1': 'r', |
| '\uFF52': 'r', |
| '\u0155': 'r', |
| '\u1E59': 'r', |
| '\u0159': 'r', |
| '\u0211': 'r', |
| '\u0213': 'r', |
| '\u1E5B': 'r', |
| '\u1E5D': 'r', |
| '\u0157': 'r', |
| '\u1E5F': 'r', |
| '\u024D': 'r', |
| '\u027D': 'r', |
| '\uA75B': 'r', |
| '\uA7A7': 'r', |
| '\uA783': 'r', |
| '\u24E2': 's', |
| '\uFF53': 's', |
| '\u00DF': 's', |
| '\u015B': 's', |
| '\u1E65': 's', |
| '\u015D': 's', |
| '\u1E61': 's', |
| '\u0161': 's', |
| '\u1E67': 's', |
| '\u1E63': 's', |
| '\u1E69': 's', |
| '\u0219': 's', |
| '\u015F': 's', |
| '\u023F': 's', |
| '\uA7A9': 's', |
| '\uA785': 's', |
| '\u1E9B': 's', |
| '\u24E3': 't', |
| '\uFF54': 't', |
| '\u1E6B': 't', |
| '\u1E97': 't', |
| '\u0165': 't', |
| '\u1E6D': 't', |
| '\u021B': 't', |
| '\u0163': 't', |
| '\u1E71': 't', |
| '\u1E6F': 't', |
| '\u0167': 't', |
| '\u01AD': 't', |
| '\u0288': 't', |
| '\u2C66': 't', |
| '\uA787': 't', |
| '\uA729': 'tz', |
| '\u24E4': 'u', |
| '\uFF55': 'u', |
| '\u00F9': 'u', |
| '\u00FA': 'u', |
| '\u00FB': 'u', |
| '\u0169': 'u', |
| '\u1E79': 'u', |
| '\u016B': 'u', |
| '\u1E7B': 'u', |
| '\u016D': 'u', |
| '\u00FC': 'u', |
| '\u01DC': 'u', |
| '\u01D8': 'u', |
| '\u01D6': 'u', |
| '\u01DA': 'u', |
| '\u1EE7': 'u', |
| '\u016F': 'u', |
| '\u0171': 'u', |
| '\u01D4': 'u', |
| '\u0215': 'u', |
| '\u0217': 'u', |
| '\u01B0': 'u', |
| '\u1EEB': 'u', |
| '\u1EE9': 'u', |
| '\u1EEF': 'u', |
| '\u1EED': 'u', |
| '\u1EF1': 'u', |
| '\u1EE5': 'u', |
| '\u1E73': 'u', |
| '\u0173': 'u', |
| '\u1E77': 'u', |
| '\u1E75': 'u', |
| '\u0289': 'u', |
| '\u24E5': 'v', |
| '\uFF56': 'v', |
| '\u1E7D': 'v', |
| '\u1E7F': 'v', |
| '\u028B': 'v', |
| '\uA75F': 'v', |
| '\u028C': 'v', |
| '\uA761': 'vy', |
| '\u24E6': 'w', |
| '\uFF57': 'w', |
| '\u1E81': 'w', |
| '\u1E83': 'w', |
| '\u0175': 'w', |
| '\u1E87': 'w', |
| '\u1E85': 'w', |
| '\u1E98': 'w', |
| '\u1E89': 'w', |
| '\u2C73': 'w', |
| '\u24E7': 'x', |
| '\uFF58': 'x', |
| '\u1E8B': 'x', |
| '\u1E8D': 'x', |
| '\u24E8': 'y', |
| '\uFF59': 'y', |
| '\u1EF3': 'y', |
| '\u00FD': 'y', |
| '\u0177': 'y', |
| '\u1EF9': 'y', |
| '\u0233': 'y', |
| '\u1E8F': 'y', |
| '\u00FF': 'y', |
| '\u1EF7': 'y', |
| '\u1E99': 'y', |
| '\u1EF5': 'y', |
| '\u01B4': 'y', |
| '\u024F': 'y', |
| '\u1EFF': 'y', |
| '\u24E9': 'z', |
| '\uFF5A': 'z', |
| '\u017A': 'z', |
| '\u1E91': 'z', |
| '\u017C': 'z', |
| '\u017E': 'z', |
| '\u1E93': 'z', |
| '\u1E95': 'z', |
| '\u01B6': 'z', |
| '\u0225': 'z', |
| '\u0240': 'z', |
| '\u2C6C': 'z', |
| '\uA763': 'z', |
| '\u0386': '\u0391', |
| '\u0388': '\u0395', |
| '\u0389': '\u0397', |
| '\u038A': '\u0399', |
| '\u03AA': '\u0399', |
| '\u038C': '\u039F', |
| '\u038E': '\u03A5', |
| '\u03AB': '\u03A5', |
| '\u038F': '\u03A9', |
| '\u03AC': '\u03B1', |
| '\u03AD': '\u03B5', |
| '\u03AE': '\u03B7', |
| '\u03AF': '\u03B9', |
| '\u03CA': '\u03B9', |
| '\u0390': '\u03B9', |
| '\u03CC': '\u03BF', |
| '\u03CD': '\u03C5', |
| '\u03CB': '\u03C5', |
| '\u03B0': '\u03C5', |
| '\u03C9': '\u03C9', |
| '\u03C2': '\u03C3' |
| }; |
| |
| var Selectivity = _dereq_(8); |
| var previousTransform = Selectivity.transformText; |
| |
| /** |
| * Extended version of the transformText() function that simplifies diacritics to their latin1 |
| * counterparts. |
| * |
| * Note that if all query functions fetch their results from a remote server, you may not need this |
| * function, because it makes sense to remove diacritics server-side in such cases. |
| */ |
| Selectivity.transformText = function(string) { |
| var result = ''; |
| for (var i = 0, length = string.length; i < length; i++) { |
| var character = string[i]; |
| result += DIACRITICS[character] || character; |
| } |
| return previousTransform(result); |
| }; |
| |
| },{"8":8}],10:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var debounce = _dereq_(3); |
| |
| var EventDelegator = _dereq_(2); |
| |
| var Selectivity = _dereq_(8); |
| |
| /** |
| * selectivity Dropdown Constructor. |
| * |
| * @param options Options object. Should have the following properties: |
| * selectivity - Selectivity instance to show the dropdown for. |
| * showSearchInput - Boolean whether a search input should be shown. |
| */ |
| function SelectivityDropdown(options) { |
| |
| var selectivity = options.selectivity; |
| |
| this.$el = $(selectivity.template('dropdown', { |
| dropdownCssClass: selectivity.options.dropdownCssClass, |
| searchInputPlaceholder: selectivity.options.searchInputPlaceholder, |
| showSearchInput: options.showSearchInput |
| })); |
| |
| /** |
| * jQuery container to add the results to. |
| */ |
| this.$results = this.$('.selectivity-results-container'); |
| |
| /** |
| * Boolean indicating whether more results are available than currently displayed in the |
| * dropdown. |
| */ |
| this.hasMore = false; |
| |
| /** |
| * The currently highlighted result item. |
| */ |
| this.highlightedResult = null; |
| |
| /** |
| * Boolean whether the load more link is currently highlighted. |
| */ |
| this.loadMoreHighlighted = false; |
| |
| /** |
| * Options passed to the dropdown constructor. |
| */ |
| this.options = options; |
| |
| /** |
| * The results displayed in the dropdown. |
| */ |
| this.results = []; |
| |
| /** |
| * Selectivity instance. |
| */ |
| this.selectivity = selectivity; |
| |
| this._closed = false; |
| |
| this._closeProxy = this.close.bind(this); |
| if (selectivity.options.closeOnSelect !== false) { |
| selectivity.$el.on('selectivity-selecting', this._closeProxy); |
| } |
| |
| this._lastMousePosition = {}; |
| |
| this.addToDom(); |
| this.position(); |
| this.setupCloseHandler(); |
| |
| this._suppressMouseWheel(); |
| |
| if (options.showSearchInput) { |
| selectivity.initSearchInput(this.$('.selectivity-search-input')); |
| selectivity.focus(); |
| } |
| |
| EventDelegator.call(this); |
| |
| this.$results.on('scroll touchmove touchend', debounce(this._scrolled.bind(this), 50)); |
| |
| this.showLoading(); |
| |
| setTimeout(this.triggerOpen.bind(this), 1); |
| } |
| |
| /** |
| * Methods. |
| */ |
| $.extend(SelectivityDropdown.prototype, EventDelegator.prototype, { |
| |
| /** |
| * Convenience shortcut for this.$el.find(selector). |
| */ |
| $: function(selector) { |
| |
| return this.$el.find(selector); |
| }, |
| |
| /** |
| * Adds the dropdown to the DOM. |
| */ |
| addToDom: function() { |
| |
| var $next; |
| var $anchor = this.selectivity.$el; |
| while (($next = $anchor.next('.selectivity-dropdown')).length) { |
| $anchor = $next; |
| } |
| this.$el.insertAfter($anchor); |
| }, |
| |
| /** |
| * Closes the dropdown. |
| */ |
| close: function() { |
| |
| if (!this._closed) { |
| this._closed = true; |
| |
| if (this.options.showSearchInput) { |
| this.selectivity.removeSearchInput(); |
| } |
| |
| this.$el.remove(); |
| |
| this.removeCloseHandler(); |
| |
| this.selectivity.$el.off('selectivity-selecting', this._closeProxy); |
| |
| this.triggerClose(); |
| } |
| }, |
| |
| /** |
| * Events map. |
| * |
| * Follows the same format as Backbone: http://backbonejs.org/#View-delegateEvents |
| */ |
| events: { |
| 'click .selectivity-load-more': '_loadMoreClicked', |
| 'click .selectivity-result-item': '_resultClicked', |
| 'mouseenter .selectivity-load-more': '_loadMoreHovered', |
| 'mouseenter .selectivity-result-item': '_resultHovered' |
| }, |
| |
| /** |
| * Highlights a result item. |
| * |
| * @param item The item to highlight. |
| */ |
| highlight: function(item) { |
| |
| if (this.loadMoreHighlighted) { |
| this.$('.selectivity-load-more').removeClass('highlight'); |
| } |
| |
| this.$('.selectivity-result-item').removeClass('highlight') |
| .filter('[data-item-id=' + Selectivity.quoteCssAttr(item.id) + ']') |
| .addClass('highlight'); |
| |
| this.highlightedResult = item; |
| this.loadMoreHighlighted = false; |
| |
| this.selectivity.triggerEvent('selectivity-highlight', { item: item, id: item.id }); |
| }, |
| |
| /** |
| * Highlights the load more link. |
| * |
| * @param item The item to highlight. |
| */ |
| highlightLoadMore: function() { |
| |
| this.$('.selectivity-result-item').removeClass('highlight'); |
| |
| this.$('.selectivity-load-more').addClass('highlight'); |
| |
| this.highlightedResult = null; |
| this.loadMoreHighlighted = true; |
| }, |
| |
| /** |
| * Positions the dropdown inside the DOM. |
| */ |
| position: function() { |
| |
| var position = this.options.position; |
| if (position) { |
| position(this.$el, this.selectivity.$el); |
| } |
| |
| this._scrolled(); |
| }, |
| |
| /** |
| * Removes the event handler to close the dropdown. |
| */ |
| removeCloseHandler: function() { |
| |
| $('body').off('click', this._closeProxy); |
| }, |
| |
| /** |
| * Renders an array of result items. |
| * |
| * @param items Array of result items. |
| * |
| * @return HTML-formatted string to display the result items. |
| */ |
| renderItems: function(items) { |
| |
| var selectivity = this.selectivity; |
| return items.map(function(item) { |
| var result = selectivity.template(item.id ? 'resultItem' : 'resultLabel', item); |
| if (item.children) { |
| result += selectivity.template('resultChildren', { |
| childrenHtml: this.renderItems(item.children) |
| }); |
| } |
| return result; |
| }, this).join(''); |
| }, |
| |
| /** |
| * Selects the highlighted item. |
| */ |
| selectHighlight: function() { |
| |
| if (this.highlightedResult) { |
| this.selectItem(this.highlightedResult.id); |
| } else if (this.loadMoreHighlighted) { |
| this._loadMoreClicked(); |
| } |
| }, |
| |
| /** |
| * Selects the item with the given ID. |
| * |
| * @param id ID of the item to select. |
| */ |
| selectItem: function(id) { |
| |
| var selectivity = this.selectivity; |
| var item = Selectivity.findNestedById(selectivity.results, id); |
| if (item) { |
| var options = { id: id, item: item }; |
| if (selectivity.triggerEvent('selectivity-selecting', options)) { |
| selectivity.triggerEvent('selectivity-selected', options); |
| } |
| } |
| }, |
| |
| /** |
| * Sets up an event handler that will close the dropdown when the Selectivity control loses |
| * focus. |
| */ |
| setupCloseHandler: function() { |
| |
| $('body').on('click', this._closeProxy); |
| }, |
| |
| /** |
| * Shows an error message. |
| * |
| * @param message Error message to display. |
| * @param options Options object. May contain the following property: |
| * escape - Set to false to disable HTML-escaping of the message. Useful if you |
| * want to set raw HTML as the message, but may open you up to XSS |
| * attacks if you're not careful with escaping user input. |
| */ |
| showError: function(message, options) { |
| |
| options = options || {}; |
| |
| this.$results.html(this.selectivity.template('error', { |
| escape: options.escape !== false, |
| message: message |
| })); |
| |
| this.hasMore = false; |
| this.results = []; |
| |
| this.highlightedResult = null; |
| this.loadMoreHighlighted = false; |
| |
| this.position(); |
| }, |
| |
| /** |
| * Shows a loading indicator in the dropdown. |
| */ |
| showLoading: function() { |
| |
| this.$results.html(this.selectivity.template('loading')); |
| |
| this.hasMore = false; |
| this.results = []; |
| |
| this.highlightedResult = null; |
| this.loadMoreHighlighted = false; |
| |
| this.position(); |
| }, |
| |
| /** |
| * Shows the results from a search query. |
| * |
| * @param results Array of result items. |
| * @param options Options object. May contain the following properties: |
| * add - True if the results should be added to any already shown results. |
| * hasMore - Boolean whether more results can be fetched using the query() |
| * function. |
| * term - The search term for which the results are displayed. |
| */ |
| showResults: function(results, options) { |
| |
| var resultsHtml = this.renderItems(results); |
| if (options.hasMore) { |
| resultsHtml += this.selectivity.template('loadMore'); |
| } else { |
| if (!resultsHtml && !options.add) { |
| resultsHtml = this.selectivity.template('noResults', { term: options.term }); |
| } |
| } |
| |
| if (options.add) { |
| this.$('.selectivity-loading').replaceWith(resultsHtml); |
| |
| this.results = this.results.concat(results); |
| } else { |
| this.$results.html(resultsHtml); |
| |
| this.results = results; |
| } |
| |
| this.hasMore = options.hasMore; |
| |
| if (!options.add || this.loadMoreHighlighted) { |
| this._highlightFirstItem(results); |
| } |
| |
| this.position(); |
| }, |
| |
| /** |
| * Triggers the 'selectivity-close' event. |
| */ |
| triggerClose: function() { |
| |
| this.selectivity.$el.trigger('selectivity-close'); |
| }, |
| |
| /** |
| * Triggers the 'selectivity-open' event. |
| */ |
| triggerOpen: function() { |
| |
| this.selectivity.$el.trigger('selectivity-open'); |
| }, |
| |
| /** |
| * @private |
| */ |
| _highlightFirstItem: function(results) { |
| |
| function findFirstItem(results) { |
| for (var i = 0, length = results.length; i < length; i++) { |
| var result = results[i]; |
| if (result.id) { |
| return result; |
| } else if (result.children) { |
| var item = findFirstItem(result.children); |
| if (item) { |
| return item; |
| } |
| } |
| } |
| } |
| |
| var firstItem = findFirstItem(results); |
| if (firstItem) { |
| this.highlight(firstItem); |
| } else { |
| this.highlightedResult = null; |
| this.loadMoreHighlighted = false; |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _loadMoreClicked: function() { |
| |
| this.$('.selectivity-load-more').replaceWith(this.selectivity.template('loading')); |
| |
| this.selectivity.loadMore(); |
| |
| this.selectivity.focus(); |
| |
| return false; |
| }, |
| |
| /** |
| * @private |
| */ |
| _loadMoreHovered: function(event) { |
| |
| if (event.screenX === undefined || event.screenX !== this._lastMousePosition.x || |
| event.screenY === undefined || event.screenY !== this._lastMousePosition.y) { |
| this.highlightLoadMore(); |
| |
| this._recordMousePosition(event); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _recordMousePosition: function(event) { |
| |
| this._lastMousePosition = { x: event.screenX, y: event.screenY }; |
| }, |
| |
| /** |
| * @private |
| */ |
| _resultClicked: function(event) { |
| |
| this.selectItem(this.selectivity._getItemId(event)); |
| |
| return false; |
| }, |
| |
| /** |
| * @private |
| */ |
| _resultHovered: function(event) { |
| |
| if (event.screenX === undefined || event.screenX !== this._lastMousePosition.x || |
| event.screenY === undefined || event.screenY !== this._lastMousePosition.y) { |
| var id = this.selectivity._getItemId(event); |
| var item = Selectivity.findNestedById(this.results, id); |
| if (item) { |
| this.highlight(item); |
| } |
| |
| this._recordMousePosition(event); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _scrolled: function() { |
| |
| var $loadMore = this.$('.selectivity-load-more'); |
| if ($loadMore.length) { |
| if ($loadMore[0].offsetTop - this.$results[0].scrollTop < this.$el.height()) { |
| this._loadMoreClicked(); |
| } |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _suppressMouseWheel: function() { |
| |
| var suppressMouseWheelSelector = this.selectivity.options.suppressMouseWheelSelector; |
| if (suppressMouseWheelSelector === null) { |
| return; |
| } |
| |
| var selector = suppressMouseWheelSelector || '.selectivity-results-container'; |
| this.$el.on('DOMMouseScroll mousewheel', selector, function(event) { |
| |
| // Thanks to Troy Alford: |
| // http://stackoverflow.com/questions/5802467/prevent-scrolling-of-parent-element |
| |
| var $el = $(this), |
| scrollTop = this.scrollTop, |
| scrollHeight = this.scrollHeight, |
| height = $el.height(), |
| originalEvent = event.originalEvent, |
| delta = (event.type === 'DOMMouseScroll' ? originalEvent.detail * -40 |
| : originalEvent.wheelDelta), |
| up = delta > 0; |
| |
| function prevent() { |
| event.stopPropagation(); |
| event.preventDefault(); |
| event.returnValue = false; |
| return false; |
| } |
| |
| if (scrollHeight > height) { |
| if (!up && -delta > scrollHeight - height - scrollTop) { |
| // Scrolling down, but this will take us past the bottom. |
| $el.scrollTop(scrollHeight); |
| return prevent(); |
| } else if (up && delta > scrollTop) { |
| // Scrolling up, but this will take us past the top. |
| $el.scrollTop(0); |
| return prevent(); |
| } |
| } |
| }); |
| } |
| |
| }); |
| |
| module.exports = Selectivity.Dropdown = SelectivityDropdown; |
| |
| },{"2":2,"3":3,"8":8,"jquery":"jquery"}],11:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var Selectivity = _dereq_(8); |
| var MultipleSelectivity = _dereq_(14); |
| |
| function isValidEmail(email) { |
| |
| var atIndex = email.indexOf('@'); |
| var dotIndex = email.lastIndexOf('.'); |
| var spaceIndex = email.indexOf(' '); |
| return (atIndex > 0 && dotIndex > atIndex + 1 && |
| dotIndex < email.length - 2 && spaceIndex === -1); |
| } |
| |
| function lastWord(token, length) { |
| |
| length = (length === undefined ? token.length : length); |
| for (var i = length - 1; i >= 0; i--) { |
| if ((/\s/).test(token[i])) { |
| return token.slice(i + 1, length); |
| } |
| } |
| return token.slice(0, length); |
| } |
| |
| function stripEnclosure(token, enclosure) { |
| |
| if (token.slice(0, 1) === enclosure[0] && token.slice(-1) === enclosure[1]) { |
| return token.slice(1, -1).trim(); |
| } else { |
| return token.trim(); |
| } |
| } |
| |
| function createEmailItem(token) { |
| |
| var email = lastWord(token); |
| var name = token.slice(0, -email.length).trim(); |
| if (isValidEmail(email)) { |
| email = stripEnclosure(stripEnclosure(email, '()'), '<>'); |
| name = stripEnclosure(name, '""').trim() || email; |
| return { id: email, text: name }; |
| } else { |
| return (token.trim() ? { id: token, text: token } : null); |
| } |
| } |
| |
| function emailTokenizer(input, selection, createToken) { |
| |
| function hasToken(input) { |
| if (input) { |
| for (var i = 0, length = input.length; i < length; i++) { |
| switch (input[i]) { |
| case ';': |
| case ',': |
| case '\n': |
| return true; |
| case ' ': |
| case '\t': |
| if (isValidEmail(lastWord(input, i))) { |
| return true; |
| } |
| break; |
| case '"': |
| do { i++; } while(i < length && input[i] !== '"'); |
| break; |
| default: |
| continue; |
| } |
| } |
| } |
| return false; |
| } |
| |
| function takeToken(input) { |
| for (var i = 0, length = input.length; i < length; i++) { |
| switch (input[i]) { |
| case ';': |
| case ',': |
| case '\n': |
| return { term: input.slice(0, i), input: input.slice(i + 1) }; |
| case ' ': |
| case '\t': |
| if (isValidEmail(lastWord(input, i))) { |
| return { term: input.slice(0, i), input: input.slice(i + 1) }; |
| } |
| break; |
| case '"': |
| do { i++; } while(i < length && input[i] !== '"'); |
| break; |
| default: |
| continue; |
| } |
| } |
| return {}; |
| } |
| |
| while (hasToken(input)) { |
| var token = takeToken(input); |
| if (token.term) { |
| var item = createEmailItem(token.term); |
| if (item && !(item.id && Selectivity.findById(selection, item.id))) { |
| createToken(item); |
| } |
| } |
| input = token.input; |
| } |
| |
| return input; |
| } |
| |
| /** |
| * Emailselectivity Constructor. |
| * |
| * @param options Options object. Accepts all options from the MultipleSelectivity Constructor. |
| */ |
| function Emailselectivity(options) { |
| |
| MultipleSelectivity.call(this, options); |
| } |
| |
| /** |
| * Methods. |
| */ |
| var callSuper = Selectivity.inherits(Emailselectivity, MultipleSelectivity, { |
| |
| /** |
| * @inherit |
| */ |
| initSearchInput: function($input) { |
| |
| callSuper(this, 'initSearchInput', $input); |
| |
| $input.on('blur', function() { |
| var term = $input.val(); |
| if (isValidEmail(lastWord(term))) { |
| this.add(createEmailItem(term)); |
| } |
| }.bind(this)); |
| }, |
| |
| /** |
| * @inherit |
| * |
| * Note that for the Email input type the option showDropdown is set to false and the tokenizer |
| * option is set to a tokenizer specialized for email addresses. |
| */ |
| setOptions: function(options) { |
| |
| options = $.extend({ |
| createTokenItem: createEmailItem, |
| showDropdown: false, |
| tokenizer: emailTokenizer |
| }, options); |
| |
| callSuper(this, 'setOptions', options); |
| } |
| |
| }); |
| |
| module.exports = Selectivity.InputTypes.Email = Emailselectivity; |
| |
| },{"14":14,"8":8,"jquery":"jquery"}],12:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var Selectivity = _dereq_(8); |
| |
| var KEY_BACKSPACE = 8; |
| var KEY_DOWN_ARROW = 40; |
| var KEY_ENTER = 13; |
| var KEY_ESCAPE = 27; |
| var KEY_TAB = 9; |
| var KEY_UP_ARROW = 38; |
| |
| /** |
| * Search input listener providing keyboard support for navigating the dropdown. |
| */ |
| function listener(selectivity, $input) { |
| |
| var keydownCanceled = false; |
| var closeSubmenu = null; |
| |
| /** |
| * Moves a dropdown's highlight to the next or previous result item. |
| * |
| * @param delta Either 1 to move to the next item, or -1 to move to the previous item. |
| */ |
| function moveHighlight(dropdown, delta) { |
| |
| function findElementIndex($elements, selector) { |
| for (var i = 0, length = $elements.length; i < length; i++) { |
| if ($elements.eq(i).is(selector)) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| function scrollToHighlight() { |
| var $el; |
| if (dropdown.highlightedResult) { |
| var quotedId = Selectivity.quoteCssAttr(dropdown.highlightedResult.id); |
| $el = dropdown.$('.selectivity-result-item[data-item-id=' + quotedId + ']'); |
| } else if (dropdown.loadMoreHighlighted) { |
| $el = dropdown.$('.selectivity-load-more'); |
| } else { |
| return; // no highlight to scroll to |
| } |
| |
| var position = $el.position(); |
| if (!position) { |
| return; |
| } |
| |
| var top = position.top; |
| var resultsHeight = dropdown.$results.height(); |
| var elHeight = ($el.outerHeight ? $el.outerHeight() : $el.height()); |
| if (top < 0 || top > resultsHeight - elHeight) { |
| top += dropdown.$results.scrollTop(); |
| dropdown.$results.scrollTop(delta < 0 ? top : top - resultsHeight + elHeight); |
| } |
| } |
| |
| if (dropdown.submenu) { |
| moveHighlight(dropdown.submenu, delta); |
| return; |
| } |
| |
| var results = dropdown.results; |
| if (results.length) { |
| var $results = dropdown.$('.selectivity-result-item'); |
| var defaultIndex = (delta > 0 ? 0 : $results.length - 1); |
| var index = defaultIndex; |
| var highlightedResult = dropdown.highlightedResult; |
| if (highlightedResult) { |
| var quotedId = Selectivity.quoteCssAttr(highlightedResult.id); |
| index = findElementIndex($results, '[data-item-id=' + quotedId + ']') + delta; |
| if (delta > 0 ? index >= $results.length : index < 0) { |
| if (dropdown.hasMore) { |
| dropdown.highlightLoadMore(); |
| scrollToHighlight(); |
| return; |
| } else { |
| index = defaultIndex; |
| } |
| } |
| } |
| |
| var result = Selectivity.findNestedById(results, |
| selectivity._getItemId($results[index])); |
| if (result) { |
| dropdown.highlight(result, { delay: !!result.submenu }); |
| scrollToHighlight(); |
| } |
| } |
| } |
| |
| function keyHeld(event) { |
| |
| var dropdown = selectivity.dropdown; |
| if (dropdown) { |
| if (event.keyCode === KEY_BACKSPACE) { |
| if (!$input.val()) { |
| if (dropdown.submenu) { |
| var submenu = dropdown.submenu; |
| while (submenu.submenu) { |
| submenu = submenu.submenu; |
| } |
| closeSubmenu = submenu; |
| } |
| |
| event.preventDefault(); |
| keydownCanceled = true; |
| } |
| } else if (event.keyCode === KEY_DOWN_ARROW) { |
| moveHighlight(dropdown, 1); |
| } else if (event.keyCode === KEY_UP_ARROW) { |
| moveHighlight(dropdown, -1); |
| } else if (event.keyCode === KEY_TAB) { |
| setTimeout(function() { |
| selectivity.close({ keepFocus: false }); |
| }, 1); |
| } |
| } |
| } |
| |
| function keyReleased(event) { |
| |
| function open() { |
| if (selectivity.options.showDropdown !== false) { |
| selectivity.open(); |
| } |
| } |
| |
| var dropdown = selectivity.dropdown; |
| if (keydownCanceled) { |
| event.preventDefault(); |
| keydownCanceled = false; |
| |
| if (closeSubmenu) { |
| closeSubmenu.close(); |
| selectivity.focus(); |
| closeSubmenu = null; |
| } |
| } else if (event.keyCode === KEY_BACKSPACE) { |
| if (!dropdown && selectivity.options.allowClear) { |
| selectivity.clear(); |
| } |
| } else if (event.keyCode === KEY_ENTER && !event.ctrlKey) { |
| if (dropdown) { |
| dropdown.selectHighlight(); |
| } else if (selectivity.options.showDropdown !== false) { |
| open(); |
| } |
| |
| event.preventDefault(); |
| } else if (event.keyCode === KEY_ESCAPE) { |
| selectivity.close(); |
| |
| event.preventDefault(); |
| } else if (event.keyCode === KEY_DOWN_ARROW || event.keyCode === KEY_UP_ARROW) { |
| // handled in keyHeld() because the response feels faster and it works with repeated |
| // events if the user holds the key for a longer period |
| // still, we issue an open() call here in case the dropdown was not yet open... |
| open(); |
| |
| event.preventDefault(); |
| } else { |
| open(); |
| } |
| } |
| |
| $input.on('keydown', keyHeld).on('keyup', keyReleased); |
| } |
| |
| Selectivity.SearchInputListeners.push(listener); |
| |
| },{"8":8}],13:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var escape = _dereq_(4); |
| var Selectivity = _dereq_(8); |
| |
| /** |
| * Localizable elements of the Selectivity Templates. |
| * |
| * Be aware that these strings are added straight to the HTML output of the templates, so any |
| * non-safe strings should be escaped. |
| */ |
| Selectivity.Locale = { |
| |
| ajaxError: function(term) { return 'Failed to fetch results for <b>' + escape(term) + '</b>'; }, |
| loading: 'Loading...', |
| loadMore: 'Load more...', |
| needMoreCharacters: function(numCharacters) { |
| return 'Enter ' + numCharacters + ' more characters to search'; |
| }, |
| noResults: 'No results found', |
| noResultsForTerm: function(term) { return 'No results for <b>' + escape(term) + '</b>'; } |
| |
| }; |
| |
| },{"4":4,"8":8}],14:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var Selectivity = _dereq_(8); |
| |
| var KEY_BACKSPACE = 8; |
| var KEY_DELETE = 46; |
| var KEY_ENTER = 13; |
| |
| /** |
| * MultipleSelectivity Constructor. |
| * |
| * @param options Options object. Accepts all options from the Selectivity Base Constructor in |
| * addition to those accepted by MultipleSelectivity.setOptions(). |
| */ |
| function MultipleSelectivity(options) { |
| |
| Selectivity.call(this, options); |
| |
| this.$el.html(this.template('multipleSelectInput', { enabled: this.enabled })) |
| .trigger('selectivity-init', 'multiple'); |
| |
| this._highlightedItemId = null; |
| |
| this.initSearchInput(this.$('.selectivity-multiple-input:not(.selectivity-width-detector)')); |
| |
| this._rerenderSelection(); |
| |
| if (!options.positionDropdown) { |
| // dropdowns for multiple-value inputs should open below the select box, |
| // unless there is not enough space below, but there is space enough above, then it should |
| // open upwards |
| this.options.positionDropdown = function($el, $selectEl) { |
| var position = $selectEl.position(), |
| dropdownHeight = $el.height(), |
| selectHeight = $selectEl.height(), |
| top = $selectEl[0].getBoundingClientRect().top, |
| bottom = top + selectHeight + dropdownHeight, |
| openUpwards = (typeof window !== 'undefined' && bottom > $(window).height() && |
| top - dropdownHeight > 0); |
| |
| var width = $selectEl.outerWidth ? $selectEl.outerWidth() : $selectEl.width(); |
| $el.css({ |
| left: position.left + 'px', |
| top: position.top + (openUpwards ? -dropdownHeight : selectHeight) + 'px' |
| }).width(width); |
| }; |
| } |
| } |
| |
| /** |
| * Methods. |
| */ |
| var callSuper = Selectivity.inherits(MultipleSelectivity, { |
| |
| /** |
| * Adds an item to the selection, if it's not selected yet. |
| * |
| * @param item The item to add. May be an item with 'id' and 'text' properties or just an ID. |
| */ |
| add: function(item) { |
| |
| var itemIsId = Selectivity.isValidId(item); |
| var id = (itemIsId ? item : this.validateItem(item) && item.id); |
| |
| if (this._value.indexOf(id) === -1) { |
| this._value.push(id); |
| |
| if (itemIsId && this.options.initSelection) { |
| this.options.initSelection([id], function(data) { |
| if (this._value.indexOf(id) > -1) { |
| item = this.validateItem(data[0]); |
| this._data.push(item); |
| |
| this.triggerChange({ added: item }); |
| } |
| }.bind(this)); |
| } else { |
| if (itemIsId) { |
| item = this.getItemForId(id); |
| } |
| this._data.push(item); |
| |
| this.triggerChange({ added: item }); |
| } |
| } |
| |
| this.$searchInput.val(''); |
| }, |
| |
| /** |
| * Clears the data and value. |
| */ |
| clear: function() { |
| |
| this.data([]); |
| }, |
| |
| /** |
| * Events map. |
| * |
| * Follows the same format as Backbone: http://backbonejs.org/#View-delegateEvents |
| */ |
| events: { |
| 'change': '_rerenderSelection', |
| 'change .selectivity-multiple-input': function() { return false; }, |
| 'click': '_clicked', |
| 'click .selectivity-multiple-selected-item': '_itemClicked', |
| 'keydown .selectivity-multiple-input': '_keyHeld', |
| 'keyup .selectivity-multiple-input': '_keyReleased', |
| 'paste .selectivity-multiple-input': '_onPaste', |
| 'selectivity-selected': '_resultSelected' |
| }, |
| |
| /** |
| * @inherit |
| */ |
| filterResults: function(results) { |
| |
| return results.filter(function(item) { |
| return !Selectivity.findById(this._data, item.id); |
| }, this); |
| }, |
| |
| /** |
| * Returns the correct data for a given value. |
| * |
| * @param value The value to get the data for. Should be an array of IDs. |
| * |
| * @return The corresponding data. Will be an array of objects with 'id' and 'text' properties. |
| * Note that if no items are defined, this method assumes the text labels will be equal |
| * to the IDs. |
| */ |
| getDataForValue: function(value) { |
| |
| return value.map(this.getItemForId.bind(this)).filter(function(item) { return !!item; }); |
| }, |
| |
| /** |
| * Returns the correct value for the given data. |
| * |
| * @param data The data to get the value for. Should be an array of objects with 'id' and 'text' |
| * properties. |
| * |
| * @return The corresponding value. Will be an array of IDs. |
| */ |
| getValueForData: function(data) { |
| |
| return data.map(function(item) { return item.id; }); |
| }, |
| |
| /** |
| * Removes an item from the selection, if it is selected. |
| * |
| * @param item The item to remove. May be an item with 'id' and 'text' properties or just an ID. |
| */ |
| remove: function(item) { |
| |
| var id = ($.type(item) === 'object' ? item.id : item); |
| |
| var removedItem; |
| var index = Selectivity.findIndexById(this._data, id); |
| if (index > -1) { |
| removedItem = this._data[index]; |
| this._data.splice(index, 1); |
| } |
| |
| if (this._value[index] !== id) { |
| index = this._value.indexOf(id); |
| } |
| if (index > -1) { |
| this._value.splice(index, 1); |
| } |
| |
| if (removedItem) { |
| this.triggerChange({ removed: removedItem }); |
| } |
| |
| if (id === this._highlightedItemId) { |
| this._highlightedItemId = null; |
| } |
| }, |
| |
| /** |
| * @inherit |
| */ |
| search: function() { |
| |
| var term = this.$searchInput.val(); |
| |
| if (this.options.tokenizer) { |
| term = this.options.tokenizer(term, this._data, this.add.bind(this), this.options); |
| |
| if ($.type(term) === 'string') { |
| this.$searchInput.val(term); |
| } else { |
| term = ''; |
| } |
| } |
| |
| if (this.dropdown) { |
| callSuper(this, 'search'); |
| } |
| }, |
| |
| /** |
| * @inherit |
| * |
| * @param options Options object. In addition to the options supported in the base |
| * implementation, this may contain the following properties: |
| * backspaceHighlightsBeforeDelete - If set to true, when the user enters a |
| * backspace while there is no text in the |
| * search field but there are selected items, |
| * the last selected item will be highlighted |
| * and when a second backspace is entered the |
| * item is deleted. If false, the item gets |
| * deleted on the first backspace. The default |
| * value is true on devices that have touch |
| * input and false on devices that don't. |
| * createTokenItem - Function to create a new item from a user's search term. |
| * This is used to turn the term into an item when dropdowns |
| * are disabled and the user presses Enter. It is also used by |
| * the default tokenizer to create items for individual tokens. |
| * The function receives a 'token' parameter which is the |
| * search term (or part of a search term) to create an item for |
| * and must return an item object with 'id' and 'text' |
| * properties or null if no token can be created from the term. |
| * The default is a function that returns an item where the id |
| * and text both match the token for any non-empty string and |
| * which returns null otherwise. |
| * tokenizer - Function for tokenizing search terms. Will receive the following |
| * parameters: |
| * input - The input string to tokenize. |
| * selection - The current selection data. |
| * createToken - Callback to create a token from the search terms. |
| * Should be passed an item object with 'id' and 'text' |
| * properties. |
| * options - The options set on the Selectivity instance. |
| * Any string returned by the tokenizer function is treated as the |
| * remainder of untokenized input. |
| */ |
| setOptions: function(options) { |
| |
| options = options || {}; |
| |
| var backspaceHighlightsBeforeDelete = 'backspaceHighlightsBeforeDelete'; |
| if (options[backspaceHighlightsBeforeDelete] === undefined) { |
| options[backspaceHighlightsBeforeDelete] = this.hasTouch; |
| } |
| |
| options.allowedTypes = options.allowedTypes || {}; |
| options.allowedTypes[backspaceHighlightsBeforeDelete] = 'boolean'; |
| |
| callSuper(this, 'setOptions', options); |
| }, |
| |
| /** |
| * Validates data to set. Throws an exception if the data is invalid. |
| * |
| * @param data The data to validate. Should be an array of objects with 'id' and 'text' |
| * properties. |
| * |
| * @return The validated data. This may differ from the input data. |
| */ |
| validateData: function(data) { |
| |
| if (data === null) { |
| return []; |
| } else if ($.type(data) === 'array') { |
| return data.map(this.validateItem.bind(this)); |
| } else { |
| throw new Error('Data for MultiSelectivity instance should be array'); |
| } |
| }, |
| |
| /** |
| * Validates a value to set. Throws an exception if the value is invalid. |
| * |
| * @param value The value to validate. Should be an array of IDs. |
| * |
| * @return The validated value. This may differ from the input value. |
| */ |
| validateValue: function(value) { |
| |
| if (value === null) { |
| return []; |
| } else if ($.type(value) === 'array') { |
| if (value.every(Selectivity.isValidId)) { |
| return value; |
| } else { |
| throw new Error('Value contains invalid IDs'); |
| } |
| } else { |
| throw new Error('Value for MultiSelectivity instance should be an array'); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _backspacePressed: function() { |
| |
| if (this.options.backspaceHighlightsBeforeDelete) { |
| if (this._highlightedItemId) { |
| this._deletePressed(); |
| } else if (this._value.length) { |
| this._highlightItem(this._value.slice(-1)[0]); |
| } |
| } else if (this._value.length) { |
| this.remove(this._value.slice(-1)[0]); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _clicked: function() { |
| |
| if (this.enabled) { |
| this.focus(); |
| |
| this._open(); |
| |
| return false; |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _createToken: function() { |
| |
| var term = this.$searchInput.val(); |
| var createTokenItem = this.options.createTokenItem; |
| |
| if (term && createTokenItem) { |
| var item = createTokenItem(term); |
| if (item) { |
| this.add(item); |
| } |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _deletePressed: function() { |
| |
| if (this._highlightedItemId) { |
| this.remove(this._highlightedItemId); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _highlightItem: function(id) { |
| |
| this._highlightedItemId = id; |
| this.$('.selectivity-multiple-selected-item').removeClass('highlighted') |
| .filter('[data-item-id=' + Selectivity.quoteCssAttr(id) + ']').addClass('highlighted'); |
| |
| if (this.hasKeyboard) { |
| this.focus(); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _itemClicked: function(event) { |
| |
| if (this.enabled) { |
| this._highlightItem(this._getItemId(event)); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _itemRemoveClicked: function(event) { |
| |
| this.remove(this._getItemId(event)); |
| |
| this._updateInputWidth(); |
| |
| return false; |
| }, |
| |
| /** |
| * @private |
| */ |
| _keyHeld: function(event) { |
| |
| this._originalValue = this.$searchInput.val(); |
| |
| if (event.keyCode === KEY_ENTER && !event.ctrlKey) { |
| event.preventDefault(); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _keyReleased: function(event) { |
| |
| var inputHadText = !!this._originalValue; |
| |
| if (event.keyCode === KEY_ENTER && !event.ctrlKey) { |
| if (this.options.createTokenItem) { |
| this._createToken(); |
| } |
| } else if (event.keyCode === KEY_BACKSPACE && !inputHadText) { |
| this._backspacePressed(); |
| } else if (event.keyCode === KEY_DELETE && !inputHadText) { |
| this._deletePressed(); |
| } |
| |
| this._updateInputWidth(); |
| }, |
| |
| /** |
| * @private |
| */ |
| _onPaste: function() { |
| |
| setTimeout(function() { |
| this.search(); |
| |
| if (this.options.createTokenItem) { |
| this._createToken(); |
| } |
| }.bind(this), 10); |
| }, |
| |
| /** |
| * @private |
| */ |
| _open: function() { |
| |
| if (this.options.showDropdown !== false) { |
| this.open(); |
| } |
| }, |
| |
| _renderSelectedItem: function(item) { |
| |
| this.$searchInput.before(this.template('multipleSelectedItem', $.extend({ |
| highlighted: (item.id === this._highlightedItemId), |
| removable: !this.options.readOnly |
| }, item))); |
| |
| var quotedId = Selectivity.quoteCssAttr(item.id); |
| this.$('.selectivity-multiple-selected-item[data-item-id=' + quotedId + ']') |
| .find('.selectivity-multiple-selected-item-remove') |
| .on('click', this._itemRemoveClicked.bind(this)); |
| }, |
| |
| /** |
| * @private |
| */ |
| _rerenderSelection: function(event) { |
| |
| event = event || {}; |
| |
| if (event.added) { |
| this._renderSelectedItem(event.added); |
| |
| this._scrollToBottom(); |
| } else if (event.removed) { |
| var quotedId = Selectivity.quoteCssAttr(event.removed.id); |
| this.$('.selectivity-multiple-selected-item[data-item-id=' + quotedId + ']').remove(); |
| } else { |
| this.$('.selectivity-multiple-selected-item').remove(); |
| |
| this._data.forEach(this._renderSelectedItem, this); |
| |
| this._updateInputWidth(); |
| } |
| |
| if (event.added || event.removed) { |
| if (this.dropdown) { |
| this.dropdown.showResults(this.filterResults(this.results), { |
| hasMore: this.dropdown.hasMore |
| }); |
| } |
| |
| if (this.hasKeyboard) { |
| this.focus(); |
| } |
| } |
| |
| this.positionDropdown(); |
| |
| this._updatePlaceholder(); |
| }, |
| |
| /** |
| * @private |
| */ |
| _resultSelected: function(event) { |
| |
| if (this._value.indexOf(event.id) === -1) { |
| this.add(event.item); |
| } else { |
| this.remove(event.item); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _scrollToBottom: function() { |
| |
| var $inputContainer = this.$('.selectivity-multiple-input-container'); |
| $inputContainer.scrollTop($inputContainer.height()); |
| }, |
| |
| /** |
| * @private |
| */ |
| _updateInputWidth: function() { |
| |
| if (this.enabled) { |
| var $input = this.$searchInput, $widthDetector = this.$('.selectivity-width-detector'); |
| $widthDetector.text($input.val() || |
| !this._data.length && this.options.placeholder || |
| ''); |
| $input.width($widthDetector.width() + 20); |
| |
| this.positionDropdown(); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _updatePlaceholder: function() { |
| |
| var placeholder = this._data.length ? '' : this.options.placeholder; |
| if (this.enabled) { |
| this.$searchInput.attr('placeholder', placeholder); |
| } else { |
| this.$('.selectivity-placeholder').text(placeholder); |
| } |
| } |
| |
| }); |
| |
| module.exports = Selectivity.InputTypes.Multiple = MultipleSelectivity; |
| |
| },{"8":8,"jquery":"jquery"}],15:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var Selectivity = _dereq_(8); |
| |
| /** |
| * SingleSelectivity Constructor. |
| * |
| * @param options Options object. Accepts all options from the Selectivity Base Constructor in |
| * addition to those accepted by SingleSelectivity.setOptions(). |
| */ |
| function SingleSelectivity(options) { |
| |
| Selectivity.call(this, options); |
| |
| this.$el.html(this.template('singleSelectInput', this.options)) |
| .trigger('selectivity-init', 'single'); |
| |
| this._rerenderSelection(); |
| |
| if (!options.positionDropdown) { |
| // dropdowns for single-value inputs should open below the select box, |
| // unless there is not enough space below, in which case the dropdown should be moved up |
| // just enough so it fits in the window, but never so much that it reaches above the top |
| this.options.positionDropdown = function($el, $selectEl) { |
| var position = $selectEl.position(), |
| dropdownHeight = $el.height(), |
| selectHeight = $selectEl.height(), |
| top = $selectEl[0].getBoundingClientRect().top, |
| bottom = top + selectHeight + dropdownHeight, |
| deltaUp = 0; |
| |
| if (typeof window !== 'undefined') { |
| deltaUp = Math.min(Math.max(bottom - $(window).height(), 0), top + selectHeight); |
| } |
| |
| var width = $selectEl.outerWidth ? $selectEl.outerWidth() : $selectEl.width(); |
| $el.css({ |
| left: position.left + 'px', |
| top: (position.top + selectHeight - deltaUp) + 'px' |
| }).width(width); |
| }; |
| } |
| |
| if (options.showSearchInputInDropdown === false) { |
| this.initSearchInput(this.$('.selectivity-single-select-input'), { noSearch: true }); |
| } |
| } |
| |
| /** |
| * Methods. |
| */ |
| var callSuper = Selectivity.inherits(SingleSelectivity, { |
| |
| /** |
| * Events map. |
| * |
| * Follows the same format as Backbone: http://backbonejs.org/#View-delegateEvents |
| */ |
| events: { |
| 'change': '_rerenderSelection', |
| 'click': '_clicked', |
| 'focus .selectivity-single-select-input': '_focused', |
| 'selectivity-selected': '_resultSelected' |
| }, |
| |
| /** |
| * Clears the data and value. |
| */ |
| clear: function() { |
| |
| this.data(null); |
| }, |
| |
| /** |
| * @inherit |
| * |
| * @param options Optional options object. May contain the following property: |
| * keepFocus - If false, the focus won't remain on the input. |
| */ |
| close: function(options) { |
| |
| this._closing = true; |
| |
| callSuper(this, 'close'); |
| |
| var $input = this.$('.selectivity-single-select-input'); |
| if (!this.$searchInput) { |
| this.initSearchInput($input, { noSearch: true }); |
| } |
| |
| if (!options || options.keepFocus !== false) { |
| $input.focus(); |
| } |
| |
| this._closing = false; |
| }, |
| |
| /** |
| * Returns the correct data for a given value. |
| * |
| * @param value The value to get the data for. Should be an ID. |
| * |
| * @return The corresponding data. Will be an object with 'id' and 'text' properties. Note that |
| * if no items are defined, this method assumes the text label will be equal to the ID. |
| */ |
| getDataForValue: function(value) { |
| |
| return this.getItemForId(value); |
| }, |
| |
| /** |
| * Returns the correct value for the given data. |
| * |
| * @param data The data to get the value for. Should be an object with 'id' and 'text' |
| * properties or null. |
| * |
| * @return The corresponding value. Will be an ID or null. |
| */ |
| getValueForData: function(data) { |
| |
| return (data ? data.id : null); |
| }, |
| |
| /** |
| * @inherit |
| */ |
| open: function(options) { |
| |
| var showSearchInput = (this.options.showSearchInputInDropdown !== false); |
| |
| callSuper(this, 'open', $.extend({ showSearchInput: showSearchInput }, options)); |
| |
| if (!showSearchInput) { |
| this.focus(); |
| } |
| }, |
| |
| /** |
| * @inherit |
| * |
| * @param options Options object. In addition to the options supported in the base |
| * implementation, this may contain the following properties: |
| * allowClear - Boolean whether the selected item may be removed. |
| * showSearchInputInDropdown - Set to false to remove the search input used in |
| * dropdowns. The default is true. |
| */ |
| setOptions: function(options) { |
| |
| options = options || {}; |
| |
| options.allowedTypes = $.extend(options.allowedTypes || {}, { |
| allowClear: 'boolean', |
| showSearchInputInDropdown: 'boolean' |
| }); |
| |
| callSuper(this, 'setOptions', options); |
| }, |
| |
| /** |
| * Validates data to set. Throws an exception if the data is invalid. |
| * |
| * @param data The data to validate. Should be an object with 'id' and 'text' properties or null |
| * to indicate no item is selected. |
| * |
| * @return The validated data. This may differ from the input data. |
| */ |
| validateData: function(data) { |
| |
| return (data === null ? data : this.validateItem(data)); |
| }, |
| |
| /** |
| * Validates a value to set. Throws an exception if the value is invalid. |
| * |
| * @param value The value to validate. Should be null or a valid ID. |
| * |
| * @return The validated value. This may differ from the input value. |
| */ |
| validateValue: function(value) { |
| |
| if (value === null || Selectivity.isValidId(value)) { |
| return value; |
| } else { |
| throw new Error('Value for SingleSelectivity instance should be a valid ID or null'); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _clicked: function() { |
| |
| if (this.enabled) { |
| if (this.dropdown) { |
| this.close(); |
| } else if (this.options.showDropdown !== false) { |
| this.open(); |
| } |
| |
| return false; |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _focused: function() { |
| |
| if (this.enabled && !this._closing && this.options.showDropdown !== false) { |
| this.open(); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _itemRemoveClicked: function() { |
| |
| this.data(null); |
| |
| return false; |
| }, |
| |
| /** |
| * @private |
| */ |
| _rerenderSelection: function() { |
| |
| var $container = this.$('.selectivity-single-result-container'); |
| if (this._data) { |
| $container.html( |
| this.template('singleSelectedItem', $.extend({ |
| removable: this.options.allowClear && !this.options.readOnly |
| }, this._data)) |
| ); |
| |
| $container.find('.selectivity-single-selected-item-remove') |
| .on('click', this._itemRemoveClicked.bind(this)); |
| } else { |
| $container.html( |
| this.template('singleSelectPlaceholder', { placeholder: this.options.placeholder }) |
| ); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _resultSelected: function(event) { |
| |
| this.data(event.item); |
| |
| this.close(); |
| } |
| |
| }); |
| |
| module.exports = Selectivity.InputTypes.Single = SingleSelectivity; |
| |
| },{"8":8,"jquery":"jquery"}],16:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var Selectivity = _dereq_(8); |
| var SelectivityDropdown = _dereq_(10); |
| |
| /** |
| * Extended dropdown that supports submenus. |
| */ |
| function SelectivitySubmenu(options) { |
| |
| /** |
| * Optional parent dropdown menu from which this dropdown was opened. |
| */ |
| this.parentMenu = options.parentMenu; |
| |
| SelectivityDropdown.call(this, options); |
| |
| this._closeSubmenuTimeout = 0; |
| |
| this._openSubmenuTimeout = 0; |
| } |
| |
| var callSuper = Selectivity.inherits(SelectivitySubmenu, SelectivityDropdown, { |
| |
| /** |
| * @inherit |
| */ |
| close: function() { |
| |
| if (this.options.restoreOptions) { |
| this.selectivity.setOptions(this.options.restoreOptions); |
| } |
| if (this.options.restoreResults) { |
| this.selectivity.results = this.options.restoreResults; |
| } |
| |
| if (this.submenu) { |
| this.submenu.close(); |
| } |
| |
| callSuper(this, 'close'); |
| |
| if (this.parentMenu) { |
| this.parentMenu.submenu = null; |
| this.parentMenu = null; |
| } |
| |
| clearTimeout(this._closeSubmenuTimeout); |
| clearTimeout(this._openSubmenuTimeout); |
| }, |
| |
| /** |
| * @inherit |
| * |
| * @param options Optional options object. May contain the following property: |
| * delay - If true, indicates any submenu should not be opened until after some |
| * delay. |
| */ |
| highlight: function(item, options) { |
| |
| if (options && options.delay) { |
| callSuper(this, 'highlight', item); |
| |
| clearTimeout(this._openSubmenuTimeout); |
| this._openSubmenuTimeout = setTimeout(this._doHighlight.bind(this, item), 300); |
| } else if (this.submenu) { |
| if (this.highlightedResult && this.highlightedResult.id === item.id) { |
| this._doHighlight(item); |
| } else { |
| clearTimeout(this._closeSubmenuTimeout); |
| this._closeSubmenuTimeout = setTimeout( |
| this._closeSubmenuAndHighlight.bind(this, item), 100 |
| ); |
| } |
| } else { |
| if (this.parentMenu && this.parentMenu._closeSubmenuTimeout) { |
| clearTimeout(this.parentMenu._closeSubmenuTimeout); |
| this.parentMenu._closeSubmenuTimeout = 0; |
| } |
| |
| this._doHighlight(item); |
| } |
| }, |
| |
| /** |
| * @inherit |
| */ |
| selectHighlight: function() { |
| |
| if (this.submenu) { |
| this.submenu.selectHighlight(); |
| } else { |
| callSuper(this, 'selectHighlight'); |
| } |
| }, |
| |
| /** |
| * @inherit |
| */ |
| selectItem: function(id) { |
| |
| var selectivity = this.selectivity; |
| var item = Selectivity.findNestedById(selectivity.results, id); |
| if (item && !item.submenu) { |
| var options = { id: id, item: item }; |
| if (selectivity.triggerEvent('selectivity-selecting', options)) { |
| selectivity.triggerEvent('selectivity-selected', options); |
| } |
| } |
| }, |
| |
| /** |
| * @inherit |
| */ |
| showResults: function(results, options) { |
| |
| if (this.submenu) { |
| this.submenu.showResults(results, options); |
| } else { |
| callSuper(this, 'showResults', results, options); |
| } |
| }, |
| |
| /** |
| * @inherit |
| */ |
| triggerClose: function() { |
| |
| if (this.parentMenu) { |
| this.selectivity.$el.trigger('selectivity-close-submenu'); |
| } else { |
| callSuper(this, 'triggerClose'); |
| } |
| }, |
| |
| /** |
| * @inherit |
| */ |
| triggerOpen: function() { |
| |
| if (this.parentMenu) { |
| this.selectivity.$el.trigger('selectivity-open-submenu'); |
| } else { |
| callSuper(this, 'triggerOpen'); |
| } |
| }, |
| |
| /** |
| * @private |
| */ |
| _closeSubmenuAndHighlight: function(item) { |
| |
| if (this.submenu) { |
| this.submenu.close(); |
| } |
| |
| this._doHighlight(item); |
| }, |
| |
| /** |
| * @private |
| */ |
| _doHighlight: function(item) { |
| |
| callSuper(this, 'highlight', item); |
| |
| if (item.submenu && !this.submenu) { |
| var selectivity = this.selectivity; |
| var Dropdown = selectivity.options.dropdown || Selectivity.Dropdown; |
| if (Dropdown) { |
| var quotedId = Selectivity.quoteCssAttr(item.id); |
| var $item = this.$('.selectivity-result-item[data-item-id=' + quotedId + ']'); |
| var $dropdownEl = this.$el; |
| |
| this.submenu = new Dropdown({ |
| parentMenu: this, |
| position: item.submenu.positionDropdown || function($el) { |
| var dropdownPosition = $dropdownEl.position(); |
| var width = $dropdownEl.width(); |
| $el.css({ |
| left: dropdownPosition.left + width + 'px', |
| top: $item.position().top + dropdownPosition.top + 'px' |
| }).width(width); |
| }, |
| restoreOptions: { |
| items: selectivity.items, |
| query: selectivity.options.query || null |
| }, |
| restoreResults: selectivity.results, |
| selectivity: selectivity, |
| showSearchInput: item.submenu.showSearchInput |
| }); |
| |
| selectivity.setOptions({ |
| items: item.submenu.items || null, |
| query: item.submenu.query || null |
| }); |
| |
| selectivity.search(''); |
| } |
| } |
| } |
| |
| }); |
| |
| Selectivity.Dropdown = SelectivitySubmenu; |
| |
| Selectivity.findNestedById = function(array, id) { |
| |
| for (var i = 0, length = array.length; i < length; i++) { |
| var item = array[i], result; |
| if (item.id === id) { |
| result = item; |
| } else if (item.children) { |
| result = Selectivity.findNestedById(item.children, id); |
| } else if (item.submenu && item.submenu.items) { |
| result = Selectivity.findNestedById(item.submenu.items, id); |
| } |
| if (result) { |
| return result; |
| } |
| } |
| return null; |
| }; |
| |
| module.exports = SelectivitySubmenu; |
| |
| },{"10":10,"8":8}],17:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var escape = _dereq_(4); |
| |
| var Selectivity = _dereq_(8); |
| |
| _dereq_(13); |
| |
| /** |
| * Default set of templates to use with Selectivity.js. |
| * |
| * Note that every template can be defined as either a string, a function returning a string (like |
| * Handlebars templates, for instance) or as an object containing a render function (like Hogan.js |
| * templates, for instance). |
| */ |
| Selectivity.Templates = { |
| |
| /** |
| * Renders the dropdown. |
| * |
| * The template is expected to have at least one element with the class |
| * 'selectivity-results-container', which is where all results will be added to. |
| * |
| * @param options Options object containing the following properties: |
| * dropdownCssClass - Optional CSS class to add to the top-level element. |
| * searchInputPlaceholder - Optional placeholder text to display in the search |
| * input in the dropdown. |
| * showSearchInput - Boolean whether a search input should be shown. If true, |
| * an input element with the 'selectivity-search-input' is |
| * expected. |
| */ |
| dropdown: function(options) { |
| var extraClass = (options.dropdownCssClass ? ' ' + options.dropdownCssClass : ''), |
| searchInput = ''; |
| if (options.showSearchInput) { |
| extraClass += ' has-search-input'; |
| |
| var placeholder = options.searchInputPlaceholder; |
| searchInput = ( |
| '<div class="selectivity-search-input-container">' + |
| '<input type="text" class="selectivity-search-input"' + |
| (placeholder ? ' placeholder="' + escape(placeholder) + '"' |
| : '') + '>' + |
| '</div>' |
| ); |
| } |
| return ( |
| '<div class="selectivity-dropdown' + extraClass + '">' + |
| searchInput + |
| '<div class="selectivity-results-container"></div>' + |
| '</div>' |
| ); |
| }, |
| |
| /** |
| * Renders an error message in the dropdown. |
| * |
| * @param options Options object containing the following properties: |
| * escape - Boolean whether the message should be HTML-escaped. |
| * message - The message to display. |
| */ |
| error: function(options) { |
| return ( |
| '<div class="selectivity-error">' + |
| (options.escape ? escape(options.message) : options.message) + |
| '</div>' |
| ); |
| }, |
| |
| /** |
| * Renders a loading indicator in the dropdown. |
| * |
| * This template is expected to have an element with a 'selectivity-loading' class which may be |
| * replaced with actual results. |
| */ |
| loading: function() { |
| return '<div class="selectivity-loading">' + Selectivity.Locale.loading + '</div>'; |
| }, |
| |
| /** |
| * Load more indicator. |
| * |
| * This template is expected to have an element with a 'selectivity-load-more' class which, when |
| * clicked, will load more results. |
| */ |
| loadMore: function() { |
| return '<div class="selectivity-load-more">' + Selectivity.Locale.loadMore + '</div>'; |
| }, |
| |
| /** |
| * Renders multi-selection input boxes. |
| * |
| * The template is expected to have at least have elements with the following classes: |
| * 'selectivity-multiple-input-container' - The element containing all the selected items and |
| * the input for selecting additional items. |
| * 'selectivity-multiple-input' - The actual input element that allows the user to type to |
| * search for more items. When selected items are added, they are |
| * inserted right before this element. |
| * 'selectivity-width-detector' - This element is optional, but important to make sure the |
| * '.selectivity-multiple-input' element will fit in the |
| * container. The width detector also has the |
| * 'select2-multiple-input' class on purpose to be able to detect |
| * the width of text entered in the input element. |
| * |
| * @param options Options object containing the following property: |
| * enabled - Boolean whether the input is enabled. |
| */ |
| multipleSelectInput: function(options) { |
| return ( |
| '<div class="selectivity-multiple-input-container">' + |
| (options.enabled ? '<input type="text" autocomplete="off" autocorrect="off" ' + |
| 'autocapitalize="off" ' + |
| 'class="selectivity-multiple-input">' + |
| '<span class="selectivity-multiple-input ' + |
| 'selectivity-width-detector"></span>' |
| : '<div class="selectivity-multiple-input ' + |
| 'selectivity-placeholder"></div>') + |
| '<div class="selectivity-clearfix"></div>' + |
| '</div>' |
| ); |
| }, |
| |
| /** |
| * Renders a selected item in multi-selection input boxes. |
| * |
| * The template is expected to have a top-level element with the class |
| * 'selectivity-multiple-selected-item'. This element is also required to have a 'data-item-id' |
| * attribute with the ID set to that passed through the options object. |
| * |
| * An element with the class 'selectivity-multiple-selected-item-remove' should be present |
| * which, when clicked, will cause the element to be removed. |
| * |
| * @param options Options object containing the following properties: |
| * highlighted - Boolean whether this item is currently highlighted. |
| * id - Identifier for the item. |
| * removable - Boolean whether a remove icon should be displayed. |
| * text - Text label which the user sees. |
| */ |
| multipleSelectedItem: function(options) { |
| var extraClass = (options.highlighted ? ' highlighted' : ''); |
| return ( |
| '<span class="selectivity-multiple-selected-item' + extraClass + '" ' + |
| 'data-item-id="' + escape(options.id) + '">' + |
| (options.removable ? '<a class="selectivity-multiple-selected-item-remove">' + |
| '<i class="glyphicon glyphicon-remove"></i>' + |
| '</a>' |
| : '') + |
| escape(options.text) + |
| '</span>' |
| ); |
| }, |
| |
| /** |
| * Renders a message there are no results for the given query. |
| * |
| * @param options Options object containing the following property: |
| * term - Search term the user is searching for. |
| */ |
| noResults: function(options) { |
| var Locale = Selectivity.Locale; |
| return ( |
| '<div class="selectivity-error">' + |
| (options.term ? Locale.noResultsForTerm(options.term) : Locale.noResults) + |
| '</div>' |
| ); |
| }, |
| |
| /** |
| * Renders a container for item children. |
| * |
| * The template is expected to have an element with the class 'selectivity-result-children'. |
| * |
| * @param options Options object containing the following property: |
| * childrenHtml - Rendered HTML for the children. |
| */ |
| resultChildren: function(options) { |
| return '<div class="selectivity-result-children">' + options.childrenHtml + '</div>'; |
| }, |
| |
| /** |
| * Render a result item in the dropdown. |
| * |
| * The template is expected to have a top-level element with the class |
| * 'selectivity-result-item'. This element is also required to have a 'data-item-id' attribute |
| * with the ID set to that passed through the options object. |
| * |
| * @param options Options object containing the following properties: |
| * id - Identifier for the item. |
| * text - Text label which the user sees. |
| * submenu - Truthy if the result item has a menu with subresults. |
| */ |
| resultItem: function(options) { |
| return ( |
| '<div class="selectivity-result-item" data-item-id="' + escape(options.id) + '">' + |
| escape(options.text) + |
| (options.submenu ? '<i class="selectivity-submenu-icon fa fa-chevron-right"></i>' |
| : '') + |
| '</div>' |
| ); |
| }, |
| |
| /** |
| * Render a result label in the dropdown. |
| * |
| * The template is expected to have a top-level element with the class |
| * 'selectivity-result-label'. |
| * |
| * @param options Options object containing the following properties: |
| * text - Text label. |
| */ |
| resultLabel: function(options) { |
| return '<div class="selectivity-result-label">' + escape(options.text) + '</div>'; |
| }, |
| |
| /** |
| * Renders single-select input boxes. |
| * |
| * The template is expected to have at least one element with the class |
| * 'selectivity-single-result-container' which is the element containing the selected item or |
| * the placeholder. |
| */ |
| singleSelectInput: ( |
| '<div class="selectivity-single-select">' + |
| '<input type="text" class="selectivity-single-select-input">' + |
| '<div class="selectivity-single-result-container"></div>' + |
| '<i class="fa fa-sort-desc selectivity-caret"></i>' + |
| '</div>' |
| ), |
| |
| /** |
| * Renders the placeholder for single-select input boxes. |
| * |
| * The template is expected to have a top-level element with the class |
| * 'selectivity-placeholder'. |
| * |
| * @param options Options object containing the following property: |
| * placeholder - The placeholder text. |
| */ |
| singleSelectPlaceholder: function(options) { |
| return ( |
| '<div class="selectivity-placeholder">' + |
| escape(options.placeholder) + |
| '</div>' |
| ); |
| }, |
| |
| /** |
| * Renders the selected item in single-select input boxes. |
| * |
| * The template is expected to have a top-level element with the class |
| * 'selectivity-single-selected-item'. This element is also required to have a 'data-item-id' |
| * attribute with the ID set to that passed through the options object. |
| * |
| * @param options Options object containing the following properties: |
| * id - Identifier for the item. |
| * removable - Boolean whether a remove icon should be displayed. |
| * text - Text label which the user sees. |
| */ |
| singleSelectedItem: function(options) { |
| return ( |
| '<span class="selectivity-single-selected-item" ' + |
| 'data-item-id="' + escape(options.id) + '">' + |
| (options.removable ? '<a class="selectivity-single-selected-item-remove">' + |
| '<i class="glyphicon glyphicon-remove"></i>' + |
| '</a>' |
| : '') + |
| escape(options.text) + |
| '</span>' |
| ); |
| }, |
| |
| /** |
| * Renders select-box inside single-select input that was initialized on |
| * traditional <select> element. |
| * |
| * @param options Options object containing the following properties: |
| * name - Name of the <select> element. |
| * mode - Mode in which select exists, single or multiple. |
| */ |
| selectCompliance: function(options) { |
| if (options.mode === 'multiple' && options.name.slice(-2) !== '[]') { |
| options.name += '[]'; |
| } |
| return ('<select name="' + options.name + '"' + (options.mode === 'multiple' ? ' multiple' : '') + '></select>'); |
| }, |
| |
| /** |
| * Renders the selected item in compliance <select> element as <option>. |
| * |
| * @param options Options object containing the following properties |
| * id - Identifier for the item. |
| * text - Text label which the user sees. |
| */ |
| selectOptionCompliance: function(options) { |
| return ( |
| '<option value="' + escape(options.id) + '" selected>' + |
| escape(options.text) + |
| '</option>' |
| ); |
| } |
| |
| }; |
| |
| },{"13":13,"4":4,"8":8}],18:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var Selectivity = _dereq_(8); |
| |
| function defaultTokenizer(input, selection, createToken, options) { |
| |
| var createTokenItem = options.createTokenItem || function(token) { |
| return token ? { id: token, text: token } : null; |
| }; |
| |
| var separators = options.tokenSeparators; |
| |
| function hasToken(input) { |
| return input ? separators.some(function(separator) { |
| return input.indexOf(separator) > -1; |
| }) : false; |
| } |
| |
| function takeToken(input) { |
| for (var i = 0, length = input.length; i < length; i++) { |
| if (separators.indexOf(input[i]) > -1) { |
| return { term: input.slice(0, i), input: input.slice(i + 1) }; |
| } |
| } |
| return {}; |
| } |
| |
| while (hasToken(input)) { |
| var token = takeToken(input); |
| if (token.term) { |
| var item = createTokenItem(token.term); |
| if (item && !Selectivity.findById(selection, item.id)) { |
| createToken(item); |
| } |
| } |
| input = token.input; |
| } |
| |
| return input; |
| } |
| |
| /** |
| * Option listener that provides a default tokenizer which is used when the tokenSeparators option |
| * is specified. |
| * |
| * @param options Options object. In addition to the options supported in the multi-input |
| * implementation, this may contain the following property: |
| * tokenSeparators - Array of string separators which are used to separate the search |
| * string into tokens. If specified and the tokenizer property is |
| * not set, the tokenizer property will be set to a function which |
| * splits the search term into tokens separated by any of the given |
| * separators. The tokens will be converted into selectable items |
| * using the 'createTokenItem' function. The default tokenizer also |
| * filters out already selected items. |
| */ |
| Selectivity.OptionListeners.push(function(selectivity, options) { |
| |
| if (options.tokenSeparators) { |
| options.allowedTypes = $.extend({ tokenSeparators: 'array' }, options.allowedTypes); |
| |
| options.tokenizer = options.tokenizer || defaultTokenizer; |
| } |
| }); |
| |
| },{"8":8,"jquery":"jquery"}],19:[function(_dereq_,module,exports){ |
| 'use strict'; |
| |
| var $ = window.jQuery || window.Zepto; |
| |
| var Selectivity = _dereq_(8); |
| |
| function replaceSelectElement($el, options) { |
| |
| var data = (options.multiple ? [] : null); |
| |
| var mapOptions = function() { |
| var $this = $(this); |
| if ($this.is('option')) { |
| var text = $this.text(); |
| var id = $this.attr('value') || text; |
| if ($this.prop('selected')) { |
| var item = { id: id, text: text }; |
| if (options.multiple) { |
| data.push(item); |
| } else { |
| data = item; |
| } |
| } |
| |
| return { |
| id: id, |
| text: $this.attr('label') || text |
| }; |
| } else { |
| return { |
| text: $this.attr('label'), |
| children: $this.children('option,optgroup').map(mapOptions).get() |
| }; |
| } |
| }; |
| |
| options.allowClear = ('allowClear' in options ? options.allowClear : !$el.prop('required')); |
| |
| var items = $el.children('option,optgroup').map(mapOptions).get(); |
| options.items = (options.query ? null : items); |
| |
| options.placeholder = options.placeholder || $el.data('placeholder') || ''; |
| |
| options.data = data; |
| |
| var classes = ($el.attr('class') || 'selectivity-input').split(' '); |
| if (classes.indexOf('selectivity-input') === -1) { |
| classes.push('selectivity-input'); |
| } |
| |
| var $div = $('<div>').attr({ |
| 'id': $el.attr('id'), |
| 'class': classes.join(' '), |
| 'style': $el.attr('style'), |
| 'data-name': $el.attr('name') |
| }); |
| $el.replaceWith($div); |
| return $div; |
| } |
| |
| function bindTraditionalSelectEvents(selectivity) { |
| |
| var $el = selectivity.$el; |
| |
| $el.on('selectivity-init', function(event, mode) { |
| |
| $el.append(selectivity.template('selectCompliance', {name: $el.attr('data-name'), mode: mode})) |
| .removeAttr('data-name'); |
| }) |
| .on('selectivity-init change', function() { |
| var data = selectivity._data; |
| var $select = $el.find('select'); |
| |
| if (data instanceof Array) { |
| $select.empty(); |
| |
| data.forEach(function(item) { |
| $select.append(selectivity.template('selectOptionCompliance', item)); |
| }); |
| } else { |
| if (data) { |
| $select.html(selectivity.template('selectOptionCompliance', data)); |
| } else { |
| $select.empty(); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Option listener providing support for converting traditional <select> boxes into Selectivity |
| * instances. |
| */ |
| Selectivity.OptionListeners.push(function(selectivity, options) { |
| |
| var $el = selectivity.$el; |
| if ($el.is('select')) { |
| if ($el.attr('autofocus')) { |
| setTimeout(function() { |
| selectivity.focus(); |
| }, 1); |
| } |
| |
| selectivity.$el = replaceSelectElement($el, options); |
| selectivity.$el[0].selectivity = selectivity; |
| |
| bindTraditionalSelectEvents(selectivity); |
| } |
| }); |
| |
| },{"8":8,"jquery":"jquery"}]},{},[1])(1) |
| }); |