/** * @license * Selectivity.js 3.0.6 * Copyright (c) 2014-2016 Arend van Beelen jr. * (c) 2016 Speakap BV * Available under MIT license */ (function (f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.selectivity = f() } })(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) { var root = _dereq_(10); /** Built-in value references. */ var Symbol = root.Symbol; module.exports = Symbol; }, {"10": 10}], 2: [function (_dereq_, module, exports) { /** * A specialized version of `_.map` for arrays without support for iteratee * shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the new mapped array. */ function arrayMap(array, iteratee) { var index = -1, length = array == null ? 0 : array.length, result = Array(length); while (++index < length) { result[index] = iteratee(array[index], index, array); } return result; } module.exports = arrayMap; }, {}], 3: [function (_dereq_, module, exports) { var Symbol = _dereq_(1), getRawTag = _dereq_(8), objectToString = _dereq_(9); /** `Object#toString` result references. */ var nullTag = '[object Null]', undefinedTag = '[object Undefined]'; /** Built-in value references. */ var symToStringTag = Symbol ? Symbol.toStringTag : undefined; /** * The base implementation of `getTag` without fallbacks for buggy environments. * * @private * @param {*} value The value to query. * @returns {string} Returns the `toStringTag`. */ function baseGetTag(value) { if (value == null) { return value === undefined ? undefinedTag : nullTag; } return (symToStringTag && symToStringTag in Object(value)) ? getRawTag(value) : objectToString(value); } module.exports = baseGetTag; }, {"1": 1, "8": 8, "9": 9}], 4: [function (_dereq_, module, exports) { /** * The base implementation of `_.propertyOf` without support for deep paths. * * @private * @param {Object} object The object to query. * @returns {Function} Returns the new accessor function. */ function basePropertyOf(object) { return function (key) { return object == null ? undefined : object[key]; }; } module.exports = basePropertyOf; }, {}], 5: [function (_dereq_, module, exports) { var Symbol = _dereq_(1), arrayMap = _dereq_(2), isArray = _dereq_(13), isSymbol = _dereq_(17); /** Used as references for various `Number` constants. */ var INFINITY = 1 / 0; /** Used to convert symbols to primitives and strings. */ var symbolProto = Symbol ? Symbol.prototype : undefined, symbolToString = symbolProto ? symbolProto.toString : undefined; /** * The base implementation of `_.toString` which doesn't convert nullish * values to empty strings. * * @private * @param {*} value The value to process. * @returns {string} Returns the string. */ function baseToString(value) { // Exit early for strings to avoid a performance hit in some environments. if (typeof value == 'string') { return value; } if (isArray(value)) { // Recursively convert values (susceptible to call stack limits). return arrayMap(value, baseToString) + ''; } if (isSymbol(value)) { return symbolToString ? symbolToString.call(value) : ''; } var result = (value + ''); return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; } module.exports = baseToString; }, {"1": 1, "13": 13, "17": 17, "2": 2}], 6: [function (_dereq_, module, exports) { var basePropertyOf = _dereq_(4); /** Used to map characters to HTML entities. */ var htmlEscapes = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; /** * Used by `_.escape` to convert characters to HTML entities. * * @private * @param {string} chr The matched character to escape. * @returns {string} Returns the escaped character. */ var escapeHtmlChar = basePropertyOf(htmlEscapes); module.exports = escapeHtmlChar; }, {"4": 4}], 7: [function (_dereq_, module, exports) { (function (global) { /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; module.exports = freeGlobal; }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) }, {}], 8: [function (_dereq_, module, exports) { var Symbol = _dereq_(1); /** Used for built-in method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var nativeObjectToString = objectProto.toString; /** Built-in value references. */ var symToStringTag = Symbol ? Symbol.toStringTag : undefined; /** * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. * * @private * @param {*} value The value to query. * @returns {string} Returns the raw `toStringTag`. */ function getRawTag(value) { var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag]; try { value[symToStringTag] = undefined; var unmasked = true; } catch (e) { } var result = nativeObjectToString.call(value); if (unmasked) { if (isOwn) { value[symToStringTag] = tag; } else { delete value[symToStringTag]; } } return result; } module.exports = getRawTag; }, {"1": 1}], 9: [function (_dereq_, module, exports) { /** Used for built-in method references. */ var objectProto = Object.prototype; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var nativeObjectToString = objectProto.toString; /** * Converts `value` to a string using `Object.prototype.toString`. * * @private * @param {*} value The value to convert. * @returns {string} Returns the converted string. */ function objectToString(value) { return nativeObjectToString.call(value); } module.exports = objectToString; }, {}], 10: [function (_dereq_, module, exports) { var freeGlobal = _dereq_(7); /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); module.exports = root; }, {"7": 7}], 11: [function (_dereq_, module, exports) { var isObject = _dereq_(14), now = _dereq_(18), toNumber = _dereq_(19); /** Error message constants. */ var FUNC_ERROR_TEXT = 'Expected a function'; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeMax = Math.max, nativeMin = Math.min; /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel * delayed `func` invocations and a `flush` method to immediately invoke them. * Provide `options` to indicate whether `func` should be invoked on the * leading and/or trailing edge of the `wait` timeout. The `func` is invoked * with the last arguments provided to the debounced function. Subsequent * calls to the debounced function return the result of the last `func` * invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the debounced function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=false] * Specify invoking on the leading edge of the timeout. * @param {number} [options.maxWait] * The maximum time `func` is allowed to be delayed before it's invoked. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @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)); * * // Invoke `sendMail` when clicked, debouncing subsequent calls. * jQuery(element).on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * * // Ensure `batchLog` is invoked once after 1 second of debounced calls. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); * var source = new EventSource('/stream'); * jQuery(source).on('message', debounced); * * // Cancel the trailing debounced invocation. * jQuery(window).on('popstate', debounced.cancel); */ function debounce(func, wait, options) { var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = toNumber(wait) || 0; if (isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs, thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = setTimeout(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result = wait - timeSinceLastCall; return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); } function timerExpired() { var time = now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = setTimeout(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { clearTimeout(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(now()); } function debounced() { var time = now(), isInvoking = shouldInvoke(time); lastArgs = arguments; lastThis = this; lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; return debounced; } module.exports = debounce; }, {"14": 14, "18": 18, "19": 19}], 12: [function (_dereq_, module, exports) { var escapeHtmlChar = _dereq_(6), toString = _dereq_(20); /** Used to match HTML entities and HTML characters. */ var reUnescapedHtml = /[&<>"']/g, reHasUnescapedHtml = RegExp(reUnescapedHtml.source); /** * Converts the characters "&", "<", ">", '"', and "'" in `string` to their * corresponding HTML entities. * * **Note:** No other characters are escaped. To escape additional * characters use a third-party library like [_he_](https://mths.be/he). * * Though the ">" character is escaped for symmetry, characters like * ">" and "/" don't need escaping in HTML and have no special meaning * unless they're part of a tag or unquoted attribute value. See * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) * (under "semi-related fun fact") for more details. * * When working with HTML you should always * [quote attribute values](http://wonko.com/post/html-escaping) to reduce * XSS vectors. * * @static * @since 0.1.0 * @memberOf _ * @category String * @param {string} [string=''] The string to escape. * @returns {string} Returns the escaped string. * @example * * _.escape('fred, barney, & pebbles'); * // => 'fred, barney, & pebbles' */ function escape(string) { string = toString(string); return (string && reHasUnescapedHtml.test(string)) ? string.replace(reUnescapedHtml, escapeHtmlChar) : string; } module.exports = escape; }, {"20": 20, "6": 6}], 13: [function (_dereq_, module, exports) { /** * Checks if `value` is classified as an `Array` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array, else `false`. * @example * * _.isArray([1, 2, 3]); * // => true * * _.isArray(document.body.children); * // => false * * _.isArray('abc'); * // => false * * _.isArray(_.noop); * // => false */ var isArray = Array.isArray; module.exports = isArray; }, {}], 14: [function (_dereq_, module, exports) { /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return value != null && (type == 'object' || type == 'function'); } module.exports = isObject; }, {}], 15: [function (_dereq_, module, exports) { /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return value != null && typeof value == 'object'; } module.exports = isObjectLike; }, {}], 16: [function (_dereq_, module, exports) { var baseGetTag = _dereq_(3), isArray = _dereq_(13), isObjectLike = _dereq_(15); /** `Object#toString` result references. */ var stringTag = '[object String]'; /** * Checks if `value` is classified as a `String` primitive or object. * * @static * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a string, else `false`. * @example * * _.isString('abc'); * // => true * * _.isString(1); * // => false */ function isString(value) { return typeof value == 'string' || (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); } module.exports = isString; }, {"13": 13, "15": 15, "3": 3}], 17: [function (_dereq_, module, exports) { var baseGetTag = _dereq_(3), isObjectLike = _dereq_(15); /** `Object#toString` result references. */ var symbolTag = '[object Symbol]'; /** * Checks if `value` is classified as a `Symbol` primitive or object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. * @example * * _.isSymbol(Symbol.iterator); * // => true * * _.isSymbol('abc'); * // => false */ function isSymbol(value) { return typeof value == 'symbol' || (isObjectLike(value) && baseGetTag(value) == symbolTag); } module.exports = isSymbol; }, {"15": 15, "3": 3}], 18: [function (_dereq_, module, exports) { var root = _dereq_(10); /** * Gets the timestamp of the number of milliseconds that have elapsed since * the Unix epoch (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ * @since 2.4.0 * @category Date * @returns {number} Returns the timestamp. * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); * // => Logs the number of milliseconds it took for the deferred invocation. */ var now = function () { return root.Date.now(); }; module.exports = now; }, {"10": 10}], 19: [function (_dereq_, module, exports) { var isObject = _dereq_(14), isSymbol = _dereq_(17); /** Used as references for various `Number` constants. */ var NAN = 0 / 0; /** Used to match leading and trailing whitespace. */ var reTrim = /^\s+|\s+$/g; /** Used to detect bad signed hexadecimal string values. */ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; /** Used to detect binary string values. */ var reIsBinary = /^0b[01]+$/i; /** Used to detect octal string values. */ var reIsOctal = /^0o[0-7]+$/i; /** Built-in method references without a dependency on `root`. */ var freeParseInt = parseInt; /** * Converts `value` to a number. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {number} Returns the number. * @example * * _.toNumber(3.2); * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 * * _.toNumber(Infinity); * // => Infinity * * _.toNumber('3.2'); * // => 3.2 */ function toNumber(value) { if (typeof value == 'number') { return value; } if (isSymbol(value)) { return NAN; } if (isObject(value)) { var other = typeof value.valueOf == 'function' ? value.valueOf() : value; value = isObject(other) ? (other + '') : other; } if (typeof value != 'string') { return value === 0 ? value : +value; } value = value.replace(reTrim, ''); var isBinary = reIsBinary.test(value); return (isBinary || reIsOctal.test(value)) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : (reIsBadHex.test(value) ? NAN : +value); } module.exports = toNumber; }, {"14": 14, "17": 17}], 20: [function (_dereq_, module, exports) { var baseToString = _dereq_(5); /** * Converts `value` to a string. An empty string is returned for `null` * and `undefined` values. The sign of `-0` is preserved. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to convert. * @returns {string} Returns the converted string. * @example * * _.toString(null); * // => '' * * _.toString(-0); * // => '-0' * * _.toString([1, 2, 3]); * // => '1,2,3' */ function toString(value) { return value == null ? '' : baseToString(value); } module.exports = toString; }, {"5": 5}], 21: [function (_dereq_, module, exports) { 'use strict'; var $ = (window.jQuery || window.Zepto); var isString = _dereq_(16); var Selectivity = _dereq_(38); var EVENT_PROPERTIES = { change: ['added', 'removed', 'value'], 'selectivity-change': ['added', 'removed', 'value'], 'selectivity-highlight': ['id', 'item'], 'selectivity-selected': ['id', 'item'], 'selectivity-selecting': ['id', 'item'] }; // create event listeners that will copy the custom properties from the native events // to the jQuery events, so jQuery users can use them seamlessly function patchEvents($el) { $.each(EVENT_PROPERTIES, function (eventName, properties) { $el.on(eventName, function (event) { if (event.originalEvent) { properties.forEach(function (propertyName) { event[propertyName] = event.originalEvent[propertyName]; }); } }); }); } /** * 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. If a method name is given, the options * parameter is ignored and any additional parameters are passed to the given * method. * @param options Options object to pass to the constructor or the setOptions() method. In case * a new instance is being created, the following properties are used: * inputType - The input type to use. Default inputs include 'Multiple' and 'Single', * but you can add custom inputs to the Selectivity.Inputs map or just * specify one here as a function. The default value is 'Multiple' if * `multiple` is true and 'Single' otherwise. * multiple - Boolean determining whether multiple items may be selected * (default: false). If true, the default `inputType` is set to * 'Multiple'. * * @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. */ $.fn.selectivity = function selectivity(methodName, options) { var methodArgs = Array.prototype.slice.call(arguments, 1); var result; this.each(function () { var instance = this.selectivity; if (instance) { if (methodName === 'data') { methodName = methodArgs.length ? 'setData' : 'getData'; } else if (methodName === 'val' || methodName === 'value') { methodName = methodArgs.length ? 'setValue' : 'getValue'; } else if (!isString(methodName)) { methodArgs = [methodName]; methodName = 'setOptions'; } if ($.isFunction(instance[methodName])) { if (result === undefined) { result = instance[methodName].apply(instance, methodArgs); } } else { throw new Error('Unknown method: ' + methodName); } } else if (isString(methodName)) { 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 "traditional" plugin, because // the plugin 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 Inputs = Selectivity.Inputs; var InputType = options.inputType || (options.multiple ? 'Multiple' : 'Single'); if (!$.isFunction(InputType)) { if (Inputs[InputType]) { InputType = Inputs[InputType]; } else { throw new Error('Unknown Selectivity input type: ' + InputType); } } this.selectivity = new InputType(options); $this = $(this.selectivity.el); patchEvents($this); if (result === undefined) { result = $this; } } }); return result === undefined ? this : result; }; Selectivity.patchEvents = patchEvents; $.Selectivity = Selectivity; }, {"16": 16, "38": 38, "jquery": "jquery"}], 22: [function (_dereq_, module, exports) { 'use strict'; var assign = (window.jQuery || window.Zepto).extend; var EventListener = _dereq_(23); var getItemSelector = _dereq_(41); var matchesSelector = _dereq_(43); var parseElement = _dereq_(44); var removeElement = _dereq_(45); var stopPropagation = _dereq_(46); var toggleClass = _dereq_(47); var Selectivity = _dereq_(38); var HIGHLIGHT_CLASS = 'highlight'; var HIGHLIGHT_SELECTOR = '.' + HIGHLIGHT_CLASS; var LOAD_MORE_SELECTOR = '.selectivity-load-more'; var RESULT_ITEM_SELECTOR = '.selectivity-result-item'; var SCROLL_EVENTS = ['scroll', 'touchend', 'touchmove']; function findClosestElementMatchingSelector(el, selector) { while (el && !matchesSelector(el, selector)) { el = el.parentElement; } return el || null; } /** * Selectivity Dropdown Constructor. * * @param selectivity Selectivity instance to which the dropdown belongs. * @param options Options object. Should have the following properties: * highlightFirstItem - Set to false if you don't want the first item to be * automatically highlighted (optional). * items - Array of items to display. * position - Callback for positioning the dropdown. * query - Callback to fetch the items to display. * showSearchInput - Boolean whether a search input should be shown. */ function SelectivityDropdown(selectivity, options) { this.el = parseElement( selectivity.template('dropdown', { dropdownCssClass: selectivity.options.dropdownCssClass, searchInputPlaceholder: selectivity.options.searchInputPlaceholder, showSearchInput: options.showSearchInput }) ); /** * DOM element to add the results to. */ this.resultsContainer = 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._lastMousePosition = {}; this.close = this.close.bind(this); this.position = this.position.bind(this); if (selectivity.options.closeOnSelect !== false) { selectivity.events.on('selectivity-selecting', this.close); } this.addToDom(); this.showLoading(); if (options.showSearchInput) { selectivity.initInput(this.$('.selectivity-search-input')); selectivity.focus(); } var events = {}; events['click ' + LOAD_MORE_SELECTOR] = this._loadMoreClicked; events['click ' + RESULT_ITEM_SELECTOR] = this._resultClicked; events['mouseenter ' + LOAD_MORE_SELECTOR] = this._loadMoreHovered; events['mouseenter ' + RESULT_ITEM_SELECTOR] = this._resultHovered; this.events = new EventListener(this.el, this); this.events.on(events); this._attachScrollListeners(); this._suppressWheel(); setTimeout(this.triggerOpen.bind(this), 1); } /** * Methods. */ assign(SelectivityDropdown.prototype, { /** * Convenience shortcut for this.el.querySelector(selector). */ $: function (selector) { return this.el.querySelector(selector); }, /** * Adds the dropdown to the DOM. */ addToDom: function () { this.selectivity.el.appendChild(this.el); }, /** * Closes the dropdown. */ close: function () { if (!this._closed) { this._closed = true; removeElement(this.el); this.selectivity.events.off('selectivity-selecting', this.close); this.triggerClose(); this._removeScrollListeners(); } }, /** * Highlights a result item. * * @param item The item to highlight. * @param options Optional options object that may contain the following property: * reason - The reason why the result item is being highlighted. Possible * values: 'current_value', 'first_result', 'hovered'. */ highlight: function (item, options) { toggleClass(this.$(HIGHLIGHT_SELECTOR), HIGHLIGHT_CLASS, false); toggleClass(this.$(getItemSelector(RESULT_ITEM_SELECTOR, item.id)), HIGHLIGHT_CLASS, true); this.highlightedResult = item; this.loadMoreHighlighted = false; this.selectivity.triggerEvent('selectivity-highlight', { item: item, id: item.id, reason: (options && options.reason) || 'unspecified' }); }, /** * Highlights the load more link. * * @param item The item to highlight. */ highlightLoadMore: function () { toggleClass(this.$(HIGHLIGHT_SELECTOR), HIGHLIGHT_CLASS, false); toggleClass(this.$(LOAD_MORE_SELECTOR), HIGHLIGHT_CLASS, true); this.highlightedResult = null; this.loadMoreHighlighted = true; }, /** * 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 () { removeElement(this.$(LOAD_MORE_SELECTOR)); this.resultsContainer.innerHTML += this.selectivity.template('loading'); this.options.query({ callback: function (response) { if (response && response.results) { this._showResults(Selectivity.processItems(response.results), { add: true, hasMore: !!response.more }); } else { throw new Error('callback must be passed a response object'); } }.bind(this), error: this._showResults.bind(this, [], {add: true}), offset: this.results.length, selectivity: this.selectivity, term: this.term }); }, /** * Positions the dropdown inside the DOM. */ position: function () { var position = this.options.position; if (position) { position(this.el, this.selectivity.el); } this._scrolled(); }, /** * 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(''); }, /** * Searches for results based on the term given. * * 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 Term to search for. */ search: function (term) { this.term = term; if (this.options.items) { term = Selectivity.transformText(term); var matcher = this.selectivity.options.matcher || Selectivity.matcher; this._showResults( this.options.items .map(function (item) { return matcher(item, term); }) .filter(function (item) { return !!item; }), {term: term} ); } else if (this.options.query) { this.options.query({ callback: function (response) { if (response && response.results) { this._showResults(Selectivity.processItems(response.results), { hasMore: !!response.more, term: term }); } else { throw new Error('callback must be passed a response object'); } }.bind(this), error: this.showError.bind(this), offset: 0, selectivity: this.selectivity, term: term }); } }, /** * Selects the highlighted item. */ selectHighlight: function () { if (this.highlightedResult) { this.selectItem(this.highlightedResult.id); } else if (this.loadMoreHighlighted) { this.loadMore(); } }, /** * Selects the item with the given ID. * * @param id ID of the item to select. */ selectItem: function (id) { var item = Selectivity.findNestedById(this.results, id); if (item && !item.disabled && item.selectable !== false) { var options = {id: id, item: item}; if (this.selectivity.triggerEvent('selectivity-selecting', options)) { this.selectivity.triggerEvent('selectivity-selected', options); } } }, /** * 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) { this.resultsContainer.innerHTML = this.selectivity.template('error', { escape: !options || 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.resultsContainer.innerHTML = 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. * dropdown - The dropdown instance for which the results are meant. * 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) { if (options.add) { removeElement(this.$('.selectivity-loading')); } else { this.resultsContainer.innerHTML = ''; } var filteredResults = this.selectivity.filterResults(results); var resultsHtml = this.renderItems(filteredResults); if (options.hasMore) { resultsHtml += this.selectivity.template('loadMore'); } else if (!resultsHtml && !options.add) { resultsHtml = this.selectivity.template('noResults', {term: options.term}); } this.resultsContainer.innerHTML += resultsHtml; this.results = options.add ? this.results.concat(results) : results; this.hasMore = options.hasMore; var value = this.selectivity.getValue(); if (value && !Array.isArray(value)) { var item = Selectivity.findNestedById(results, value); if (item) { this.highlight(item, {reason: 'current_value'}); } } else if ( this.options.highlightFirstItem !== false && (!options.add || this.loadMoreHighlighted) ) { this._highlightFirstItem(filteredResults); } this.position(); }, /** * Triggers the 'selectivity-close' event. */ triggerClose: function () { this.selectivity.triggerEvent('selectivity-close'); }, /** * Triggers the 'selectivity-open' event. */ triggerOpen: function () { this.selectivity.triggerEvent('selectivity-open'); }, /** * @private */ _attachScrollListeners: function () { for (var i = 0; i < SCROLL_EVENTS.length; i++) { window.addEventListener(SCROLL_EVENTS[i], this.position, true); } window.addEventListener('resize', this.position); }, /** * @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, {reason: 'first_result'}); } else { this.highlightedResult = null; this.loadMoreHighlighted = false; } }, /** * @private */ _loadMoreClicked: function (event) { this.loadMore(); stopPropagation(event); }, /** * @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 */ _removeScrollListeners: function () { for (var i = 0; i < SCROLL_EVENTS.length; i++) { window.removeEventListener(SCROLL_EVENTS[i], this.position, true); } window.removeEventListener('resize', this.position); }, /** * @private */ _resultClicked: function (event) { this.selectItem(this.selectivity.getRelatedItemId(event)); stopPropagation(event); }, /** * @private */ _resultHovered: function (event) { if ( !event.screenX || event.screenX !== this._lastMousePosition.x || !event.screenY || event.screenY !== this._lastMousePosition.y ) { var id = this.selectivity.getRelatedItemId(event); var item = Selectivity.findNestedById(this.results, id); if (item && !item.disabled) { this.highlight(item, {reason: 'hovered'}); } this._recordMousePosition(event); } }, /** * @private */ _scrolled: function () { var el = this.$(LOAD_MORE_SELECTOR); if (el && el.offsetTop - this.resultsContainer.scrollTop < this.el.clientHeight) { this.loadMore(); } }, /** * @private */ _showResults: function (results, options) { this.showResults(results, assign({dropdown: this}, options)); }, /** * @private */ _suppressWheel: function () { var suppressWheelSelector = this.selectivity.options.suppressWheelSelector; if (suppressWheelSelector === null) { return; } var selector = suppressWheelSelector || '.selectivity-results-container'; this.events.on('wheel', selector, function (event) { // Thanks to Troy Alford: // http://stackoverflow.com/questions/5802467/prevent-scrolling-of-parent-element var delta = event.deltaMode === 0 ? event.deltaY : event.deltaY * 40; var el = findClosestElementMatchingSelector(event.target, selector); var height = el.clientHeight; var scrollHeight = el.scrollHeight; var scrollTop = el.scrollTop; function prevent() { stopPropagation(event); event.preventDefault(); } if (scrollHeight > height) { if (delta < -scrollTop) { // Scrolling up, but this will take us past the top. el.scrollTop = 0; prevent(); } else if (delta > scrollHeight - height - scrollTop) { // Scrolling down, but this will take us past the bottom. el.scrollTop = scrollHeight; prevent(); } } }); } }); module.exports = Selectivity.Dropdown = SelectivityDropdown; }, { "23": 23, "38": 38, "41": 41, "43": 43, "44": 44, "45": 45, "46": 46, "47": 47, "lodash/assign": "lodash/assign" }], 23: [function (_dereq_, module, exports) { 'use strict'; var assign = (window.jQuery || window.Zepto).extend; var isString = _dereq_(16); var matchesSelector = _dereq_(43); var CAPTURED_EVENTS = ['blur', 'focus', 'mouseenter', 'mouseleave', 'scroll']; /** * Listens to events dispatched to an element or its children. * * @param el The element to listen to. * @param context Optional context in which to execute the callbacks. */ function EventListener(el, context) { this.context = context || null; this.el = el; this.events = {}; this._onEvent = this._onEvent.bind(this); } assign(EventListener.prototype, { /** * Destructor. * * Removes all event listeners and cleans up all references. */ destruct: function () { Object.keys(this.events).forEach(function (eventName) { var useCapture = CAPTURED_EVENTS.indexOf(eventName) > -1; this.el.removeEventListener(eventName, this._onEvent, useCapture); }, this); this.context = null; this.el = null; this.events = null; }, /** * Stops listening to an event. * * The arguments are the same as for on(), but when no callback is given, all callbacks for the * given event and class are discarded. */ off: function (eventName, selector, callback) { if (!isString(selector)) { callback = selector; selector = ''; } if (callback) { var events = this.events[eventName]; if (events) { events = events[selector]; if (events) { for (var i = 0; i < events.length; i++) { if (events[i] === callback) { events.splice(i, 1); i--; } } } } } else { this.events[eventName][selector] = []; } }, /** * Starts listening to an event. * * @param eventName Name of the event to listen to, in lower-case. * @param selector Optional CSS selector. If given, only events inside a child element matching * the selector are caught. * @param callback Callback to invoke when the event is caught. * * Alternatively, the arguments may be provided using a map to start listening to multiple * events at once. Here, the keys of the map are eventNames and the values are callbacks. * Selectors may be specified by separating them from the event name with a space. For example: * * .on({ * 'blur': this._blurred, * 'click .some-input': this._inputClicked, * }) */ on: function (eventName, selector, callback) { if (!isString(eventName)) { var eventsMap = eventName; for (var key in eventsMap) { if (eventsMap.hasOwnProperty(key)) { var split = key.split(' '); if (split.length > 1) { this.on(split[0], split[1], eventsMap[key]); } else { this.on(split[0], eventsMap[key]); } } } return; } if (!isString(selector)) { callback = selector; selector = ''; } if (!this.events.hasOwnProperty(eventName)) { var useCapture = CAPTURED_EVENTS.indexOf(eventName) > -1; this.el.addEventListener(eventName, this._onEvent, useCapture); this.events[eventName] = {}; } if (!this.events[eventName].hasOwnProperty(selector)) { this.events[eventName][selector] = []; } if (this.events[eventName][selector].indexOf(callback) < 0) { this.events[eventName][selector].push(callback); } }, _onEvent: function (event) { var isPropagationStopped = false; var stopPropagation = event.stopPropagation; event.stopPropagation = function () { stopPropagation.call(event); isPropagationStopped = true; }; var context = this.context; function callAll(callbacks) { for (var i = 0; i < callbacks.length; i++) { callbacks[i].call(context, event); } } var target = event.target; var events = this.events[event.type.toLowerCase()]; while (target && target !== this.el && !isPropagationStopped) { for (var selector in events) { if ( selector && events.hasOwnProperty(selector) && matchesSelector(target, selector) ) { callAll(events[selector]); } } target = target.parentElement; } if (!isPropagationStopped && events.hasOwnProperty('')) { callAll(events['']); } } }); module.exports = EventListener; }, {"16": 16, "43": 43, "lodash/assign": "lodash/assign"}], 24: [function (_dereq_, module, exports) { 'use strict'; var assign = (window.jQuery || window.Zepto).extend; var MultipleInput = _dereq_(25); var Selectivity = _dereq_(38); function isValidEmail(email) { var atIndex = email.indexOf('@'); if (atIndex === -1 || email.indexOf(' ') > -1) { return false; // email needs to have an '@', and may not contain any spaces } var dotIndex = email.lastIndexOf('.'); if (dotIndex === -1) { // no dot is fine, as long as the '@' is followed by at least two more characters return atIndex < email.length - 2; } // but if there is a dot after the '@', it must be followed by at least two more characters return dotIndex > atIndex ? dotIndex < email.length - 2 : true; } 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.charAt(0) === 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; } /** * EmailInput Constructor. * * @param options Options object. Accepts all options from the MultipleInput Constructor. */ function EmailInput(options) { MultipleInput.call( this, assign( { createTokenItem: createEmailItem, showDropdown: false, tokenizer: emailTokenizer }, options ) ); this.events.on('blur', function () { var input = this.input; if (input && isValidEmail(lastWord(input.value))) { this.add(createEmailItem(input.value)); } }); } Selectivity.inherits(EmailInput, MultipleInput); module.exports = Selectivity.Inputs.Email = EmailInput; }, {"25": 25, "38": 38, "lodash/assign": "lodash/assign"}], 25: [function (_dereq_, module, exports) { 'use strict'; var assign = (window.jQuery || window.Zepto).extend; var isString = _dereq_(16); var Selectivity = _dereq_(38); var getItemSelector = _dereq_(41); var getKeyCode = _dereq_(42); var parseElement = _dereq_(44); var removeElement = _dereq_(45); var stopPropagation = _dereq_(46); var toggleClass = _dereq_(47); var KEY_BACKSPACE = 8; var KEY_DELETE = 46; var KEY_ENTER = 13; var INPUT_SELECTOR = '.selectivity-multiple-input'; var SELECTED_ITEM_SELECTOR = '.selectivity-multiple-selected-item'; var hasTouch = 'ontouchstart' in window; /** * MultipleInput Constructor. */ function MultipleInput(options) { Selectivity.call( this, assign( { // 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 positionDropdown: function (el, selectEl) { var rect = selectEl.getBoundingClientRect(); var dropdownHeight = el.clientHeight; var openUpwards = rect.bottom + dropdownHeight > window.innerHeight && rect.top - dropdownHeight > 0; assign(el.style, { left: rect.left + 'px', top: (openUpwards ? rect.top - dropdownHeight : rect.bottom) + 'px', width: rect.width + 'px' }); }, showSearchInputInDropdown: false }, options ) ); this._reset(); var events = { change: this.rerenderSelection, click: this._clicked, 'selectivity-selected': this._resultSelected }; events['change ' + INPUT_SELECTOR] = stopPropagation; events['click ' + SELECTED_ITEM_SELECTOR] = this._itemClicked; events['click ' + SELECTED_ITEM_SELECTOR + '-remove'] = this._itemRemoveClicked; events['keydown ' + INPUT_SELECTOR] = this._keyHeld; events['keyup ' + INPUT_SELECTOR] = this._keyReleased; events['paste ' + INPUT_SELECTOR] = this._onPaste; this.events.on(events); } /** * Methods. */ var callSuper = Selectivity.inherits(MultipleInput, Selectivity, { /** * 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.input.value = ''; this._updateInputWidth(); }, /** * Clears the data and value. */ clear: function () { this.setData([]); }, /** * @inherit */ filterResults: function (results) { var hasChildren = results.some(function (item) { return item.children; }); if (hasChildren) { results = results.map(function (item) { return { id: item.id, text: item.text, children: this.filterResults(item.children) }; }, this); } 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, 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 = 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; } this._updateInputWidth(); }, /** * Re-renders the selection. * * Normally the UI is automatically updated whenever the selection changes, but you may want to * call this method explicitly if you've updated the selection with the triggerChange option set * to false. */ rerenderSelection: function (event) { event = event || {}; if (event.added) { this._renderSelectedItem(event.added); this._scrollToBottom(); } else if (event.removed) { removeElement(this.$(getItemSelector(SELECTED_ITEM_SELECTOR, event.removed.id))); } else { this._forEachSelectedItem(removeElement); this._data.forEach(this._renderSelectedItem, this); this._updateInputWidth(); } if (event.added || event.removed) { if (this.dropdown) { this.dropdown.showResults(this.filterResults(this.dropdown.results), { hasMore: this.dropdown.hasMore }); } if (!hasTouch) { this.focus(); } } this.positionDropdown(); this._updatePlaceholder(); }, /** * @inherit */ search: function (term) { if (this.options.tokenizer) { term = this.options.tokenizer(term, this._data, this.add.bind(this), this.options); if (isString(term) && term !== this.input.value) { this.input.value = term; } } this._updateInputWidth(); if (this.dropdown) { callSuper(this, 'search', term); } }, /** * @inherit */ setOptions: function (options) { var wasEnabled = this.enabled; callSuper(this, 'setOptions', options); if (wasEnabled !== this.enabled) { this._reset(); } }, /** * 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 (Array.isArray(data)) { return data.map(this.validateItem, this); } else { throw new Error('Data for MultiSelectivity instance should be an 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 (Array.isArray(value)) { 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 (event) { if (this.enabled) { if (this.options.showDropdown !== false) { this.open(); } else { this.focus(); } stopPropagation(event); } }, /** * @private */ _createToken: function () { var term = this.input.value; 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 */ _forEachSelectedItem: function (callback) { Array.prototype.forEach.call(this.el.querySelectorAll(SELECTED_ITEM_SELECTOR), callback); }, /** * @private */ _highlightItem: function (id) { this._highlightedItemId = id; this._forEachSelectedItem(function (el) { toggleClass(el, 'highlighted', el.getAttribute('data-item-id') === id); }); if (!hasTouch) { this.focus(); } }, /** * @private */ _itemClicked: function (event) { if (this.enabled) { this._highlightItem(this.getRelatedItemId(event)); } }, /** * @private */ _itemRemoveClicked: function (event) { this.remove(this.getRelatedItemId(event)); stopPropagation(event); }, /** * @private */ _keyHeld: function (event) { this._originalValue = this.input.value; if (getKeyCode(event) === KEY_ENTER && !event.ctrlKey) { event.preventDefault(); } }, /** * @private */ _keyReleased: function (event) { var inputHadText = !!this._originalValue; var keyCode = getKeyCode(event); if (keyCode === KEY_ENTER && !event.ctrlKey) { this._createToken(); } else if (keyCode === KEY_BACKSPACE && !inputHadText) { this._backspacePressed(); } else if (keyCode === KEY_DELETE && !inputHadText) { this._deletePressed(); } }, /** * @private */ _onPaste: function () { setTimeout( function () { this.search(this.input.value); this._createToken(); }.bind(this), 10 ); }, /** * @private */ _renderSelectedItem: function (item) { var el = parseElement( this.template( 'multipleSelectedItem', assign( { highlighted: item.id === this._highlightedItemId, removable: !this.options.readOnly }, item ) ) ); this.input.parentNode.insertBefore(el, this.input); }, /** * @private */ _reset: function () { this.el.innerHTML = this.template('multipleSelectInput', {enabled: this.enabled}); this._highlightedItemId = null; this.initInput(this.$(INPUT_SELECTOR)); this.rerenderSelection(); }, /** * @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.$(INPUT_SELECTOR + '-container'); inputContainer.scrollTop = inputContainer.clientHeight; }, /** * @private */ _updateInputWidth: function () { if (this.enabled) { var inputContent = this.input.value || (!this._data.length && this.options.placeholder) || ''; this.input.setAttribute('size', inputContent.length + 2); this.positionDropdown(); } }, /** * @private */ _updatePlaceholder: function () { var placeholder = (!this._data.length && this.options.placeholder) || ''; if (this.enabled) { this.input.setAttribute('placeholder', placeholder); } else { this.$('.selectivity-placeholder').textContent = placeholder; } } }); module.exports = Selectivity.Inputs.Multiple = MultipleInput; }, { "16": 16, "38": 38, "41": 41, "42": 42, "44": 44, "45": 45, "46": 46, "47": 47, "lodash/assign": "lodash/assign" }], 26: [function (_dereq_, module, exports) { 'use strict'; var assign = (window.jQuery || window.Zepto).extend; var Selectivity = _dereq_(38); var stopPropagation = _dereq_(46); /** * SingleInput Constructor. */ function SingleInput(options) { Selectivity.call( this, assign( { // 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. positionDropdown: function (el, selectEl) { var rect = selectEl.getBoundingClientRect(); var dropdownTop = rect.bottom; var deltaUp = Math.min( Math.max(dropdownTop + el.clientHeight - window.innerHeight, 0), rect.top + rect.height ); assign(el.style, { left: rect.left + 'px', top: dropdownTop - deltaUp + 'px', width: rect.width + 'px' }); } }, options ) ); this.rerender(); if (options.showSearchInputInDropdown === false) { this.initInput(this.$('.selectivity-single-select-input'), {search: false}); } this.events.on({ change: this.rerenderSelection, click: this._clicked, 'click .selectivity-search-input': stopPropagation, 'click .selectivity-single-selected-item-remove': this._itemRemoveClicked, 'focus .selectivity-single-select-input': this._focused, 'selectivity-selected': this._resultSelected }); } /** * Methods. */ var callSuper = Selectivity.inherits(SingleInput, Selectivity, { /** * Clears the data and value. */ clear: function () { this.setData(null); }, /** * @inherit * * @param options Optional options object. May contain the following property: * keepFocus - If true, the focus will remain on the input. */ close: function (options) { this._closing = true; callSuper(this, 'close'); if (options && options.keepFocus && this.input) { this.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; }, /** * Rerenders the entire component. */ rerender: function () { this.el.innerHTML = this.template('singleSelectInput', this.options); this.rerenderSelection(); }, /** * Re-renders the selection. * * Normally the UI is automatically updated whenever the selection changes, but you may want to * call this method explicitly if you've updated the selection with the triggerChange option set * to false. */ rerenderSelection: function () { var template = this._data ? 'singleSelectedItem' : 'singleSelectPlaceholder'; var options = this._data ? assign( { removable: this.options.allowClear && !this.options.readOnly }, this._data ) : {placeholder: this.options.placeholder}; this.el.querySelector('input').value = this._value; this.$('.selectivity-single-result-container').innerHTML = this.template(template, options); }, /** * @inherit */ setOptions: function (options) { var wasEnabled = this.enabled; callSuper(this, 'setOptions', options); if (wasEnabled !== this.enabled) { this.rerender(); } }, /** * 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({keepFocus: true}); } else if (this.options.showDropdown !== false) { this.open(); } } }, /** * @private */ _focused: function () { if ( this.enabled && !this._closing && !this._opening && this.options.showDropdown !== false ) { this.open(); } }, /** * @private */ _itemRemoveClicked: function (event) { this.setData(null); stopPropagation(event); }, /** * @private */ _resultSelected: function (event) { this.setData(event.item); this.close({keepFocus: true}); } }); module.exports = Selectivity.Inputs.Single = SingleInput; }, {"38": 38, "46": 46, "lodash/assign": "lodash/assign"}], 27: [function (_dereq_, module, exports) { 'use strict'; var escape = _dereq_(12); var Selectivity = _dereq_(38); /** * 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. */ module.exports = Selectivity.Locale = { loading: 'Loading...', loadMore: 'Load more...', noResults: 'No results found', ajaxError: function (term) { if (term) { return 'Failed to fetch results for ' + escape(term) + ''; } else { return 'Failed to fetch results'; } }, needMoreCharacters: function (numCharacters) { return 'Enter ' + numCharacters + ' more characters to search'; }, noResultsForTerm: function (term) { return 'No results for ' + escape(term) + ''; } }; }, {"12": 12, "38": 38}], 28: [function (_dereq_, module, exports) { 'use strict'; var debounce = _dereq_(11); var Selectivity = _dereq_(38); var Locale = _dereq_(27); function addUrlParam(url, key, value) { return url + (url.indexOf('?') > -1 ? '&' : '?') + key + '=' + encodeURIComponent(value); } function pick(object, keys) { var result = {}; keys.forEach(function (key) { if (object[key] !== undefined) { result[key] = object[key]; } }); return result; } function doFetch(ajax, queryOptions) { var fetch = ajax.fetch || window.fetch; var term = queryOptions.term; var url = typeof ajax.url === 'function' ? ajax.url(queryOptions) : ajax.url; if (ajax.params) { var params = ajax.params(term, queryOptions.offset || 0); for (var key in params) { if (params.hasOwnProperty(key)) { url = addUrlParam(url, key, params[key]); } } } var init = pick(ajax, [ 'body', 'cache', 'credentials', 'headers', 'integrity', 'method', 'mode', 'redirect', 'referrer', 'referrerPolicy' ]); fetch(url, init, queryOptions) .then(function (response) { if (response.ok) { return response.json(); } else if (Array.isArray(response) || response.results) { return response; } else { throw new Error('Unexpected AJAX response'); } }) .then(function (response) { if (Array.isArray(response)) { queryOptions.callback({results: response, more: false}); } else { queryOptions.callback({results: response.results, more: !!response.more}); } }) .catch(function (error) { var formatError = ajax.formatError || Locale.ajaxError; queryOptions.error(formatError(term, error), {escape: false}); }); } /** * 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 fetch = ajax.quietMillis ? debounce(doFetch, ajax.quietMillis) : doFetch; options.query = function (queryOptions) { var numCharsNeeded = ajax.minimumInputLength - queryOptions.term.length; if (numCharsNeeded > 0) { queryOptions.error(Locale.needMoreCharacters(numCharsNeeded)); return; } fetch(ajax, queryOptions); }; } }); }, {"11": 11, "27": 27, "38": 38}], 29: [function (_dereq_, module, exports) { 'use strict'; var Selectivity = _dereq_(38); 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; } }); }, {"38": 38}], 30: [function (_dereq_, module, exports) { 'use strict'; var DIACRITICS = { '\u24B6': 'A', A: 'A', À: 'A', Á: 'A', Â: 'A', Ầ: 'A', Ấ: 'A', Ẫ: 'A', Ẩ: 'A', Ã: 'A', Ā: 'A', Ă: 'A', Ằ: 'A', Ắ: 'A', Ẵ: 'A', Ẳ: 'A', Ȧ: 'A', Ǡ: 'A', Ä: 'A', Ǟ: 'A', Ả: 'A', Å: 'A', Ǻ: 'A', Ǎ: 'A', Ȁ: 'A', Ȃ: 'A', Ạ: 'A', Ậ: 'A', Ặ: 'A', Ḁ: 'A', Ą: 'A', Ⱥ: 'A', Ɐ: 'A', Ꜳ: 'AA', Æ: 'AE', Ǽ: 'AE', Ǣ: 'AE', Ꜵ: 'AO', Ꜷ: 'AU', Ꜹ: 'AV', Ꜻ: 'AV', Ꜽ: 'AY', '\u24B7': 'B', B: 'B', Ḃ: 'B', Ḅ: 'B', Ḇ: 'B', Ƀ: 'B', Ƃ: 'B', Ɓ: 'B', '\u24B8': 'C', C: 'C', Ć: 'C', Ĉ: 'C', Ċ: 'C', Č: 'C', Ç: 'C', Ḉ: 'C', Ƈ: 'C', Ȼ: 'C', Ꜿ: 'C', '\u24B9': 'D', D: 'D', Ḋ: 'D', Ď: 'D', Ḍ: 'D', Ḑ: 'D', Ḓ: 'D', Ḏ: 'D', Đ: 'D', Ƌ: 'D', Ɗ: 'D', Ɖ: 'D', Ꝺ: 'D', DZ: 'DZ', DŽ: 'DZ', Dz: 'Dz', Dž: 'Dz', '\u24BA': 'E', E: 'E', È: 'E', É: 'E', Ê: 'E', Ề: 'E', Ế: 'E', Ễ: 'E', Ể: 'E', Ẽ: 'E', Ē: 'E', Ḕ: 'E', Ḗ: 'E', Ĕ: 'E', Ė: 'E', Ë: 'E', Ẻ: 'E', Ě: 'E', Ȅ: 'E', Ȇ: 'E', Ẹ: 'E', Ệ: 'E', Ȩ: 'E', Ḝ: 'E', Ę: 'E', Ḙ: 'E', Ḛ: 'E', Ɛ: 'E', Ǝ: 'E', '\u24BB': 'F', F: 'F', Ḟ: 'F', Ƒ: 'F', Ꝼ: 'F', '\u24BC': 'G', G: 'G', Ǵ: 'G', Ĝ: 'G', Ḡ: 'G', Ğ: 'G', Ġ: 'G', Ǧ: 'G', Ģ: 'G', Ǥ: 'G', Ɠ: 'G', Ꞡ: 'G', Ᵹ: 'G', Ꝿ: 'G', '\u24BD': 'H', H: 'H', Ĥ: 'H', Ḣ: 'H', Ḧ: 'H', Ȟ: 'H', Ḥ: 'H', Ḩ: 'H', Ḫ: 'H', Ħ: 'H', Ⱨ: 'H', Ⱶ: 'H', Ɥ: 'H', '\u24BE': 'I', I: 'I', Ì: 'I', Í: 'I', Î: 'I', Ĩ: 'I', Ī: 'I', Ĭ: 'I', İ: 'I', Ï: 'I', Ḯ: 'I', Ỉ: 'I', Ǐ: 'I', Ȉ: 'I', Ȋ: 'I', Ị: 'I', Į: 'I', Ḭ: 'I', Ɨ: 'I', '\u24BF': 'J', J: 'J', Ĵ: 'J', Ɉ: 'J', '\u24C0': 'K', K: 'K', Ḱ: 'K', Ǩ: 'K', Ḳ: 'K', Ķ: 'K', Ḵ: 'K', Ƙ: 'K', Ⱪ: 'K', Ꝁ: 'K', Ꝃ: 'K', Ꝅ: 'K', Ꞣ: 'K', '\u24C1': 'L', L: 'L', Ŀ: 'L', Ĺ: 'L', Ľ: 'L', Ḷ: 'L', Ḹ: 'L', Ļ: 'L', Ḽ: 'L', Ḻ: 'L', Ł: 'L', Ƚ: 'L', Ɫ: 'L', Ⱡ: 'L', Ꝉ: 'L', Ꝇ: 'L', Ꞁ: 'L', LJ: 'LJ', Lj: 'Lj', '\u24C2': 'M', M: 'M', Ḿ: 'M', Ṁ: 'M', Ṃ: 'M', Ɱ: 'M', Ɯ: 'M', '\u24C3': 'N', N: 'N', Ǹ: 'N', Ń: 'N', Ñ: 'N', Ṅ: 'N', Ň: 'N', Ṇ: 'N', Ņ: 'N', Ṋ: 'N', Ṉ: 'N', Ƞ: 'N', Ɲ: 'N', Ꞑ: 'N', Ꞥ: 'N', NJ: 'NJ', Nj: 'Nj', '\u24C4': 'O', O: 'O', Ò: 'O', Ó: 'O', Ô: 'O', Ồ: 'O', Ố: 'O', Ỗ: 'O', Ổ: 'O', Õ: 'O', Ṍ: 'O', Ȭ: 'O', Ṏ: 'O', Ō: 'O', Ṑ: 'O', Ṓ: 'O', Ŏ: 'O', Ȯ: 'O', Ȱ: 'O', Ö: 'O', Ȫ: 'O', Ỏ: 'O', Ő: 'O', Ǒ: 'O', Ȍ: 'O', Ȏ: 'O', Ơ: 'O', Ờ: 'O', Ớ: 'O', Ỡ: 'O', Ở: 'O', Ợ: 'O', Ọ: 'O', Ộ: 'O', Ǫ: 'O', Ǭ: 'O', Ø: 'O', Ǿ: 'O', Ɔ: 'O', Ɵ: 'O', Ꝋ: 'O', Ꝍ: 'O', Ƣ: 'OI', Ꝏ: 'OO', Ȣ: 'OU', '\u24C5': 'P', P: 'P', Ṕ: 'P', Ṗ: 'P', Ƥ: 'P', Ᵽ: 'P', Ꝑ: 'P', Ꝓ: 'P', Ꝕ: 'P', '\u24C6': 'Q', Q: 'Q', Ꝗ: 'Q', Ꝙ: 'Q', Ɋ: 'Q', '\u24C7': 'R', R: 'R', Ŕ: 'R', Ṙ: 'R', Ř: 'R', Ȑ: 'R', Ȓ: 'R', Ṛ: 'R', Ṝ: 'R', Ŗ: 'R', Ṟ: 'R', Ɍ: 'R', Ɽ: 'R', Ꝛ: 'R', Ꞧ: 'R', Ꞃ: 'R', '\u24C8': 'S', S: 'S', ẞ: 'S', Ś: 'S', Ṥ: 'S', Ŝ: 'S', Ṡ: 'S', Š: 'S', Ṧ: 'S', Ṣ: 'S', Ṩ: 'S', Ș: 'S', Ş: 'S', Ȿ: 'S', Ꞩ: 'S', Ꞅ: 'S', '\u24C9': 'T', T: 'T', Ṫ: 'T', Ť: 'T', Ṭ: 'T', Ț: 'T', Ţ: 'T', Ṱ: 'T', Ṯ: 'T', Ŧ: 'T', Ƭ: 'T', Ʈ: 'T', Ⱦ: 'T', Ꞇ: 'T', Ꜩ: 'TZ', '\u24CA': 'U', U: 'U', Ù: 'U', Ú: 'U', Û: 'U', Ũ: 'U', Ṹ: 'U', Ū: 'U', Ṻ: 'U', Ŭ: 'U', Ü: 'U', Ǜ: 'U', Ǘ: 'U', Ǖ: 'U', Ǚ: 'U', Ủ: 'U', Ů: 'U', Ű: 'U', Ǔ: 'U', Ȕ: 'U', Ȗ: 'U', Ư: 'U', Ừ: 'U', Ứ: 'U', Ữ: 'U', Ử: 'U', Ự: 'U', Ụ: 'U', Ṳ: 'U', Ų: 'U', Ṷ: 'U', Ṵ: 'U', Ʉ: 'U', '\u24CB': 'V', V: 'V', Ṽ: 'V', Ṿ: 'V', Ʋ: 'V', Ꝟ: 'V', Ʌ: 'V', Ꝡ: 'VY', '\u24CC': 'W', W: 'W', Ẁ: 'W', Ẃ: 'W', Ŵ: 'W', Ẇ: 'W', Ẅ: 'W', Ẉ: 'W', Ⱳ: 'W', '\u24CD': 'X', X: 'X', Ẋ: 'X', Ẍ: 'X', '\u24CE': 'Y', Y: 'Y', Ỳ: 'Y', Ý: 'Y', Ŷ: 'Y', Ỹ: 'Y', Ȳ: 'Y', Ẏ: 'Y', Ÿ: 'Y', Ỷ: 'Y', Ỵ: 'Y', Ƴ: 'Y', Ɏ: 'Y', Ỿ: 'Y', '\u24CF': 'Z', Z: 'Z', Ź: 'Z', Ẑ: 'Z', Ż: 'Z', Ž: 'Z', Ẓ: 'Z', Ẕ: 'Z', Ƶ: 'Z', Ȥ: 'Z', Ɀ: 'Z', Ⱬ: 'Z', Ꝣ: 'Z', '\u24D0': 'a', a: 'a', ẚ: 'a', à: 'a', á: 'a', â: 'a', ầ: 'a', ấ: 'a', ẫ: 'a', ẩ: 'a', ã: 'a', ā: 'a', ă: 'a', ằ: 'a', ắ: 'a', ẵ: 'a', ẳ: 'a', ȧ: 'a', ǡ: 'a', ä: 'a', ǟ: 'a', ả: 'a', å: 'a', ǻ: 'a', ǎ: 'a', ȁ: 'a', ȃ: 'a', ạ: 'a', ậ: 'a', ặ: 'a', ḁ: 'a', ą: 'a', ⱥ: 'a', ɐ: 'a', ꜳ: 'aa', æ: 'ae', ǽ: 'ae', ǣ: 'ae', ꜵ: 'ao', ꜷ: 'au', ꜹ: 'av', ꜻ: 'av', ꜽ: 'ay', '\u24D1': 'b', b: 'b', ḃ: 'b', ḅ: 'b', ḇ: 'b', ƀ: 'b', ƃ: 'b', ɓ: 'b', '\u24D2': 'c', c: 'c', ć: 'c', ĉ: 'c', ċ: 'c', č: 'c', ç: 'c', ḉ: 'c', ƈ: 'c', ȼ: 'c', ꜿ: 'c', ↄ: 'c', '\u24D3': 'd', d: 'd', ḋ: 'd', ď: 'd', ḍ: 'd', ḑ: 'd', ḓ: 'd', ḏ: 'd', đ: 'd', ƌ: 'd', ɖ: 'd', ɗ: 'd', ꝺ: 'd', dz: 'dz', dž: 'dz', '\u24D4': 'e', e: 'e', è: 'e', é: 'e', ê: 'e', ề: 'e', ế: 'e', ễ: 'e', ể: 'e', ẽ: 'e', ē: 'e', ḕ: 'e', ḗ: 'e', ĕ: 'e', ė: 'e', ë: 'e', ẻ: 'e', ě: 'e', ȅ: 'e', ȇ: 'e', ẹ: 'e', ệ: 'e', ȩ: 'e', ḝ: 'e', ę: 'e', ḙ: 'e', ḛ: 'e', ɇ: 'e', ɛ: 'e', ǝ: 'e', '\u24D5': 'f', f: 'f', ḟ: 'f', ƒ: 'f', ꝼ: 'f', '\u24D6': 'g', g: 'g', ǵ: 'g', ĝ: 'g', ḡ: 'g', ğ: 'g', ġ: 'g', ǧ: 'g', ģ: 'g', ǥ: 'g', ɠ: 'g', ꞡ: 'g', ᵹ: 'g', ꝿ: 'g', '\u24D7': 'h', h: 'h', ĥ: 'h', ḣ: 'h', ḧ: 'h', ȟ: 'h', ḥ: 'h', ḩ: 'h', ḫ: 'h', ẖ: 'h', ħ: 'h', ⱨ: 'h', ⱶ: 'h', ɥ: 'h', ƕ: 'hv', '\u24D8': 'i', i: 'i', ì: 'i', í: 'i', î: 'i', ĩ: 'i', ī: 'i', ĭ: 'i', ï: 'i', ḯ: 'i', ỉ: 'i', ǐ: 'i', ȉ: 'i', ȋ: 'i', ị: 'i', į: 'i', ḭ: 'i', ɨ: 'i', ı: 'i', '\u24D9': 'j', j: 'j', ĵ: 'j', ǰ: 'j', ɉ: 'j', '\u24DA': 'k', k: 'k', ḱ: 'k', ǩ: 'k', ḳ: 'k', ķ: 'k', ḵ: 'k', ƙ: 'k', ⱪ: 'k', ꝁ: 'k', ꝃ: 'k', ꝅ: 'k', ꞣ: 'k', '\u24DB': 'l', l: 'l', ŀ: 'l', ĺ: 'l', ľ: 'l', ḷ: 'l', ḹ: 'l', ļ: 'l', ḽ: 'l', ḻ: 'l', ſ: 'l', ł: 'l', ƚ: 'l', ɫ: 'l', ⱡ: 'l', ꝉ: 'l', ꞁ: 'l', ꝇ: 'l', lj: 'lj', '\u24DC': 'm', m: 'm', ḿ: 'm', ṁ: 'm', ṃ: 'm', ɱ: 'm', ɯ: 'm', '\u24DD': 'n', n: 'n', ǹ: 'n', ń: 'n', ñ: 'n', ṅ: 'n', ň: 'n', ṇ: 'n', ņ: 'n', ṋ: 'n', ṉ: 'n', ƞ: 'n', ɲ: 'n', ʼn: 'n', ꞑ: 'n', ꞥ: 'n', nj: 'nj', '\u24DE': 'o', o: 'o', ò: 'o', ó: 'o', ô: 'o', ồ: 'o', ố: 'o', ỗ: 'o', ổ: 'o', õ: 'o', ṍ: 'o', ȭ: 'o', ṏ: 'o', ō: 'o', ṑ: 'o', ṓ: 'o', ŏ: 'o', ȯ: 'o', ȱ: 'o', ö: 'o', ȫ: 'o', ỏ: 'o', ő: 'o', ǒ: 'o', ȍ: 'o', ȏ: 'o', ơ: 'o', ờ: 'o', ớ: 'o', ỡ: 'o', ở: 'o', ợ: 'o', ọ: 'o', ộ: 'o', ǫ: 'o', ǭ: 'o', ø: 'o', ǿ: 'o', ɔ: 'o', ꝋ: 'o', ꝍ: 'o', ɵ: 'o', ƣ: 'oi', ȣ: 'ou', ꝏ: 'oo', '\u24DF': 'p', p: 'p', ṕ: 'p', ṗ: 'p', ƥ: 'p', ᵽ: 'p', ꝑ: 'p', ꝓ: 'p', ꝕ: 'p', '\u24E0': 'q', q: 'q', ɋ: 'q', ꝗ: 'q', ꝙ: 'q', '\u24E1': 'r', r: 'r', ŕ: 'r', ṙ: 'r', ř: 'r', ȑ: 'r', ȓ: 'r', ṛ: 'r', ṝ: 'r', ŗ: 'r', ṟ: 'r', ɍ: 'r', ɽ: 'r', ꝛ: 'r', ꞧ: 'r', ꞃ: 'r', '\u24E2': 's', s: 's', ß: 's', ś: 's', ṥ: 's', ŝ: 's', ṡ: 's', š: 's', ṧ: 's', ṣ: 's', ṩ: 's', ș: 's', ş: 's', ȿ: 's', ꞩ: 's', ꞅ: 's', ẛ: 's', '\u24E3': 't', t: 't', ṫ: 't', ẗ: 't', ť: 't', ṭ: 't', ț: 't', ţ: 't', ṱ: 't', ṯ: 't', ŧ: 't', ƭ: 't', ʈ: 't', ⱦ: 't', ꞇ: 't', ꜩ: 'tz', '\u24E4': 'u', u: 'u', ù: 'u', ú: 'u', û: 'u', ũ: 'u', ṹ: 'u', ū: 'u', ṻ: 'u', ŭ: 'u', ü: 'u', ǜ: 'u', ǘ: 'u', ǖ: 'u', ǚ: 'u', ủ: 'u', ů: 'u', ű: 'u', ǔ: 'u', ȕ: 'u', ȗ: 'u', ư: 'u', ừ: 'u', ứ: 'u', ữ: 'u', ử: 'u', ự: 'u', ụ: 'u', ṳ: 'u', ų: 'u', ṷ: 'u', ṵ: 'u', ʉ: 'u', '\u24E5': 'v', v: 'v', ṽ: 'v', ṿ: 'v', ʋ: 'v', ꝟ: 'v', ʌ: 'v', ꝡ: 'vy', '\u24E6': 'w', w: 'w', ẁ: 'w', ẃ: 'w', ŵ: 'w', ẇ: 'w', ẅ: 'w', ẘ: 'w', ẉ: 'w', ⱳ: 'w', '\u24E7': 'x', x: 'x', ẋ: 'x', ẍ: 'x', '\u24E8': 'y', y: 'y', ỳ: 'y', ý: 'y', ŷ: 'y', ỹ: 'y', ȳ: 'y', ẏ: 'y', ÿ: 'y', ỷ: 'y', ẙ: 'y', ỵ: 'y', ƴ: 'y', ɏ: 'y', ỿ: 'y', '\u24E9': 'z', z: 'z', ź: 'z', ẑ: 'z', ż: 'z', ž: 'z', ẓ: 'z', ẕ: 'z', ƶ: 'z', ȥ: 'z', ɀ: 'z', ⱬ: 'z', ꝣ: 'z', Ά: '\u0391', Έ: '\u0395', Ή: '\u0397', Ί: '\u0399', Ϊ: '\u0399', Ό: '\u039F', Ύ: '\u03A5', Ϋ: '\u03A5', Ώ: '\u03A9', ά: '\u03B1', έ: '\u03B5', ή: '\u03B7', ί: '\u03B9', ϊ: '\u03B9', ΐ: '\u03B9', ό: '\u03BF', ύ: '\u03C5', ϋ: '\u03C5', ΰ: '\u03C5', ω: '\u03C9', ς: '\u03C3' }; var Selectivity = _dereq_(38); 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); }; }, {"38": 38}], 31: [function (_dereq_, module, exports) { 'use strict'; var $ = (window.jQuery || window.Zepto); var Selectivity = _dereq_(38); /** * 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 && !ajax.fetch && $.Deferred) { ajax.fetch = function (url, init) { return $.ajax(url, { cache: init.cache !== 'no-cache', headers: init.headers || null, method: init.method || 'GET', xhrFields: init.credentials === 'include' ? {withCredentials: true} : null }).then( function (data) { return { results: $.map(data, function (result) { return result; }), more: false }; }, function (jqXHR, textStatus, errorThrown) { throw new Error( 'AJAX request returned: ' + textStatus + (errorThrown ? ', ' + errorThrown : '') ); } ); }; } }); }, {"38": 38, "jquery": "jquery"}], 32: [function (_dereq_, module, exports) { 'use strict'; var $ = (window.jQuery || window.Zepto); var Selectivity = _dereq_(38); function createSelectivityNextToSelectElement($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'); if (id === undefined) { id = 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.data = data; options.items = options.query ? null : items; options.placeholder = options.placeholder || $el.data('placeholder') || ''; options.tabIndex = options.tabIndex === undefined ? $el.attr('tabindex') || 0 : options.tabIndex; var classes = ($el.attr('class') || 'selectivity-input').split(' '); if (classes.indexOf('selectivity-input') < 0) { classes.push('selectivity-input'); } var $div = $('
').attr({ id: 's9y_' + $el.attr('id'), class: classes.join(' '), style: $el.attr('style'), 'data-name': $el.attr('name') }); $div.insertAfter($el); $el.hide(); return $div[0]; } function bindTraditionalSelectEvents(selectivity) { var $el = $(selectivity.el); $el.on('change', function (event) { var value = event.originalEvent.value; $el .prev('select') .val($.type(value) === 'array' ? value.slice(0) : value) .trigger(event); }); } /** * Option listener providing support for converting traditional ' + '
'; } return ( '
' + searchInput + '
' + '
' ); }, /** * 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 ( '
' + (options.escape ? escape(options.message) : options.message) + '
' ); }, /** * 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 '
' + Locale.loading + '
'; }, /** * 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 '
' + Locale.loadMore + '
'; }, /** * 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. * * @param options Options object containing the following property: * enabled - Boolean whether the input is enabled. */ multipleSelectInput: function (options) { return ( '
' + (options.enabled ? '' : '
') + '
' + '
' ); }, /** * 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 ( '' + (options.removable ? '' + '' + '' : '') + escape(options.text) + '' ); }, /** * 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) { return ( '
' + (options.term ? Locale.noResultsForTerm(options.term) : Locale.noResults) + '
' ); }, /** * 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 '
' + options.childrenHtml + '
'; }, /** * 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. * disabled - Truthy if the item should be disabled. * submenu - Truthy if the result item has a menu with subresults. */ resultItem: function (options) { return ( '
' + escape(options.text) + (options.submenu ? '' : '') + '
' ); }, /** * 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 '
' + escape(options.text) + '
'; }, /** * 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: function (options) { return ( '
' + '' + '
' + '' + '
' ); }, /** * 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 '
' + escape(options.placeholder) + '
'; }, /** * 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 ( '' + (options.removable ? '' + '' + '' : '') + escape(options.text) + '' ); }, /** * Renders select-box inside single-select input that was initialized on * traditional element. * mode - Mode in which select exists, single or multiple. */ selectCompliance: function (options) { var mode = options.mode; var name = options.name; if (mode === 'multiple' && name.slice(-2) !== '[]') { name += '[]'; } return ( '' ); }, /** * Renders the selected item in compliance