diff --git a/src/c3nav/site/static/site/js/typeahead.js b/src/c3nav/site/static/site/js/typeahead.js index bb0c8aed..53e90b42 100644 --- a/src/c3nav/site/static/site/js/typeahead.js +++ b/src/c3nav/site/static/site/js/typeahead.js @@ -1,18 +1,18 @@ /*! - * typeahead.js 0.11.1 + * typeahead.js 1.2.0 * https://github.com/twitter/typeahead.js - * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT + * Copyright 2013-2017 Twitter, Inc. and other contributors; Licensed MIT */ (function(root, factory) { if (typeof define === "function" && define.amd) { - define("bloodhound", [ "jquery" ], function(a0) { + define([ "jquery" ], function(a0) { return root["Bloodhound"] = factory(a0); }); } else if (typeof exports === "object") { module.exports = factory(require("jquery")); } else { - root["Bloodhound"] = factory(jQuery); + root["Bloodhound"] = factory(root["jQuery"]); } })(this, function($) { var _ = function() { @@ -148,18 +148,27 @@ stringify: function(val) { return _.isString(val) ? val : JSON.stringify(val); }, + guid: function() { + function _p8(s) { + var p = (Math.random().toString(16) + "000000000").substr(2, 8); + return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; + } + return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); + }, noop: function() {} }; }(); - var VERSION = "0.11.1"; + var VERSION = "1.2.0"; var tokenizers = function() { "use strict"; return { nonword: nonword, whitespace: whitespace, + ngram: ngram, obj: { nonword: getObjTokenizer(nonword), - whitespace: getObjTokenizer(whitespace) + whitespace: getObjTokenizer(whitespace), + ngram: getObjTokenizer(ngram) } }; function whitespace(str) { @@ -170,6 +179,19 @@ str = _.toStr(str); return str ? str.split(/\W+/) : []; } + function ngram(str) { + str = _.toStr(str); + var tokens = [], word = ""; + _.each(str.split(""), function(char) { + if (char.match(/\s+/)) { + word = ""; + } else { + tokens.push(word + char); + word += char; + } + }); + return tokens; + } function getObjTokenizer(tokenizer) { return function setKey(keys) { keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0); @@ -341,9 +363,10 @@ }(); var Transport = function() { "use strict"; - var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10); + var pendingRequestsCount = 0, pendingRequests = {}, sharedCache = new LruCache(10); function Transport(o) { o = o || {}; + this.maxPendingRequests = o.maxPendingRequests || 6; this.cancelled = false; this.lastReq = null; this._send = o.transport; @@ -351,7 +374,7 @@ this._cache = o.cache === false ? new LruCache(0) : sharedCache; } Transport.setMaxPendingRequests = function setMaxPendingRequests(num) { - maxPendingRequests = num; + this.maxPendingRequests = num; }; Transport.resetCache = function resetCache() { sharedCache.reset(); @@ -369,7 +392,7 @@ } if (jqXhr = pendingRequests[fingerprint]) { jqXhr.done(done).fail(fail); - } else if (pendingRequestsCount < maxPendingRequests) { + } else if (pendingRequestsCount < this.maxPendingRequests) { pendingRequestsCount++; pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always); } else { @@ -423,6 +446,7 @@ this.identify = o.identify || _.stringify; this.datumTokenizer = o.datumTokenizer; this.queryTokenizer = o.queryTokenizer; + this.matchAnyQueryToken = o.matchAnyQueryToken; this.reset(); } _.mixin(SearchIndex.prototype, { @@ -459,7 +483,7 @@ tokens = normalizeTokens(this.queryTokenizer(query)); _.each(tokens, function(token) { var node, chars, ch, ids; - if (matches && matches.length === 0) { + if (matches && matches.length === 0 && !that.matchAnyQueryToken) { return false; } node = that.trie; @@ -471,8 +495,10 @@ ids = node[IDS].slice(0); matches = matches ? getIntersection(matches, ids) : ids; } else { - matches = []; - return false; + if (!that.matchAnyQueryToken) { + matches = []; + return false; + } } }); return matches ? _.map(unique(matches), function(id) { @@ -614,10 +640,12 @@ this.url = o.url; this.prepare = o.prepare; this.transform = o.transform; + this.indexResponse = o.indexResponse; this.transport = new Transport({ cache: o.cache, limiter: o.limiter, - transport: o.transport + transport: o.transport, + maxPendingRequests: o.maxPendingRequests }); } _.mixin(Remote.prototype, { @@ -655,7 +683,9 @@ identify: _.stringify, datumTokenizer: null, queryTokenizer: null, + matchAnyQueryToken: false, sufficient: 5, + indexRemote: false, sorter: null, local: [], prefetch: null, @@ -744,7 +774,7 @@ } else if (o.wildcard) { prepare = prepareByWildcard; } else { - prepare = idenityPrepare; + prepare = identityPrepare; } return prepare; function prepareByReplace(query, settings) { @@ -755,7 +785,7 @@ settings.url = settings.url.replace(wildcard, encodeURIComponent(query)); return settings; } - function idenityPrepare(query, settings) { + function identityPrepare(query, settings) { return settings; } } @@ -806,6 +836,7 @@ this.sorter = o.sorter; this.identify = o.identify; this.sufficient = o.sufficient; + this.indexRemote = o.indexRemote; this.local = o.local; this.remote = o.remote ? new Remote(o.remote) : null; this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null; @@ -875,6 +906,8 @@ }, search: function search(query, sync, async) { var that = this, local; + sync = sync || _.noop; + async = async || _.noop; local = this.sorter(this.index.search(query)); sync(this.remote ? local.slice() : local); if (this.remote && local.length < this.sufficient) { @@ -890,7 +923,8 @@ return that.identify(r) === that.identify(l); }) && nonDuplicates.push(r); }); - async && async(nonDuplicates); + that.indexRemote && that.add(nonDuplicates); + async(nonDuplicates); } }, all: function all() { @@ -919,13 +953,13 @@ (function(root, factory) { if (typeof define === "function" && define.amd) { - define("typeahead.js", [ "jquery" ], function(a0) { + define([ "jquery" ], function(a0) { return factory(a0); }); } else if (typeof exports === "object") { module.exports = factory(require("jquery")); } else { - factory(jQuery); + factory(root["jQuery"]); } })(this, function($) { var _ = function() { @@ -1061,6 +1095,13 @@ stringify: function(val) { return _.isString(val) ? val : JSON.stringify(val); }, + guid: function() { + function _p8(s) { + var p = (Math.random().toString(16) + "000000000").substr(2, 8); + return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; + } + return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); + }, noop: function() {} }; }(); @@ -1102,7 +1143,7 @@ function buildHtml(c) { return { wrapper: '', - menu: '
' + menu: '' }; } function buildSelectors(classes) { @@ -1177,10 +1218,8 @@ } _.mixin(EventBus.prototype, { _trigger: function(type, args) { - var $e; - $e = $.Event(namespace + type); - (args = args || []).unshift($e); - this.$el.trigger.apply(this.$el, args); + var $e = $.Event(namespace + type); + this.$el.trigger.call(this.$el, $e, args || []); return $e; }, before: function(type) { @@ -1297,7 +1336,36 @@ tagName: "strong", className: null, wordsOnly: false, - caseSensitive: false + caseSensitive: false, + diacriticInsensitive: false + }; + var accented = { + A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]", + B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]", + C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]", + D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]", + E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]", + F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]", + G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]", + H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]", + I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]", + J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]", + K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]", + L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]", + M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]", + N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]", + O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]", + P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]", + Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]", + R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]", + S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]", + T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]", + U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]", + V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]", + W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]", + X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]", + Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]", + Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]" }; return function hightlight(o) { var regex; @@ -1306,7 +1374,7 @@ return; } o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; - regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly); + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); traverse(o.node, hightlightTextNode); function hightlightTextNode(textNode) { var match, patternNode, wrapperNode; @@ -1332,10 +1400,17 @@ } } }; - function getRegex(patterns, caseSensitive, wordsOnly) { + function accent_replacer(chr) { + return accented[chr.toUpperCase()] || chr; + } + function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { var escapedPatterns = [], regexStr; for (var i = 0, len = patterns.length; i < len; i++) { - escapedPatterns.push(_.escapeRegExChars(patterns[i])); + var escapedWord = _.escapeRegExChars(patterns[i]); + if (diacriticInsensitive) { + escapedWord = escapedWord.replace(/\S/g, accent_replacer); + } + escapedPatterns.push(escapedWord); } regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); @@ -1361,6 +1436,14 @@ www.mixin(this); this.$hint = $(o.hint); this.$input = $(o.input); + this.$input.attr({ + "aria-activedescendant": "", + "aria-owns": this.$input.attr("id") + "_listbox", + role: "combobox", + "aria-readonly": "true", + "aria-autocomplete": "list" + }); + $(www.menu).attr("id", this.$input.attr("id") + "_listbox"); this.query = this.$input.val(); this.queryWhenFocused = this.hasFocus() ? this.query : null; this.$overflowHelper = buildOverflowHelper(this.$input); @@ -1368,6 +1451,7 @@ if (this.$hint.length === 0) { this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; } + this.onSync("cursorchange", this._updateDescendent); } Input.normalizeQuery = function(str) { return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); @@ -1437,6 +1521,9 @@ this.trigger("whitespaceChanged", this.query); } }, + _updateDescendent: function updateDescendent(event, id) { + this.$input.attr("aria-activedescendant", id); + }, bind: function() { var that = this, onBlur, onFocus, onKeydown, onInput; onBlur = _.bind(this._onBlur, this); @@ -1560,6 +1647,7 @@ "use strict"; var keys, nameGenerator; keys = { + dataset: "tt-selectable-dataset", val: "tt-selectable-display", obj: "tt-selectable-object" }; @@ -1579,19 +1667,20 @@ } www.mixin(this); this.highlight = !!o.highlight; - this.name = o.name || nameGenerator(); + this.name = _.toStr(o.name || nameGenerator()); this.limit = o.limit || 5; this.displayFn = getDisplayFn(o.display || o.displayKey); this.templates = getTemplates(o.templates, this.displayFn); this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; this._resetLastSuggestion(); - this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); + this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); } Dataset.extractData = function extractData(el) { var $el = $(el); if ($el.data(keys.obj)) { return { + dataset: $el.data(keys.dataset) || "", val: $el.data(keys.val) || "", obj: $el.data(keys.obj) || null }; @@ -1610,7 +1699,7 @@ } else { this._empty(); } - this.trigger("rendered", this.name, suggestions, false); + this.trigger("rendered", suggestions, false, this.name); }, _append: function append(query, suggestions) { suggestions = suggestions || []; @@ -1621,7 +1710,7 @@ } else if (!this.$lastSuggestion.length && this.templates.notFound) { this._renderNotFound(query); } - this.trigger("rendered", this.name, suggestions, true); + this.trigger("rendered", suggestions, true, this.name); }, _renderSuggestions: function renderSuggestions(query, suggestions) { var $fragment; @@ -1662,7 +1751,7 @@ _.each(suggestions, function getSuggestionNode(suggestion) { var $el, context; context = that._injectQuery(query, suggestion); - $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); + $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); fragment.appendChild($el[0]); }); this.highlight && highlight({ @@ -1700,7 +1789,7 @@ this.cancel = function cancel() { canceled = true; that.cancel = $.noop; - that.async && that.trigger("asyncCanceled", query); + that.async && that.trigger("asyncCanceled", query, that.name); }; this.source(query, sync, async); !syncCalled && sync([]); @@ -1713,16 +1802,17 @@ rendered = suggestions.length; that._overwrite(query, suggestions); if (rendered < that.limit && that.async) { - that.trigger("asyncRequested", query); + that.trigger("asyncRequested", query, that.name); } } function async(suggestions) { suggestions = suggestions || []; if (!canceled && rendered < that.limit) { that.cancel = $.noop; - rendered += suggestions.length; - that._append(query, suggestions.slice(0, that.limit - rendered)); - that.async && that.trigger("asyncReceived", query); + var idx = Math.abs(rendered - that.limit); + rendered += idx; + that._append(query, suggestions.slice(0, idx)); + that.async && that.trigger("asyncReceived", query, that.name); } } }, @@ -1756,7 +1846,7 @@ suggestion: templates.suggestion || suggestionTemplate }; function suggestionTemplate(context) { - return $("