From 24b69f723d1bdf996ef6fe424b6fa4d36898cd83 Mon Sep 17 00:00:00 2001 From: Chris Hallberg <crhallberg@gmail.com> Date: Fri, 29 Sep 2017 15:17:06 -0400 Subject: [PATCH] Update to autocomplete.js v0.17.0 --- themes/bootstrap3/js/common.js | 8 +- themes/bootstrap3/js/lib/autocomplete.js | 321 ++++++++++++----------- 2 files changed, 173 insertions(+), 156 deletions(-) diff --git a/themes/bootstrap3/js/common.js b/themes/bootstrap3/js/common.js index b58310d703c..a7c50bcd250 100644 --- a/themes/bootstrap3/js/common.js +++ b/themes/bootstrap3/js/common.js @@ -246,10 +246,8 @@ function setupAutocomplete() { if (searchbox.length < 1) { return; } - var cacheObj = {}; // Search autocomplete searchbox.autocomplete({ - cacheObj: cacheObj, maxResults: 10, loadingString: VuFind.translate('loading') + '...', handler: function vufindACHandler(input, cb) { @@ -285,11 +283,7 @@ function setupAutocomplete() { }); // Update autocomplete on type change $('#searchForm_type').change(function searchTypeChange() { - for (var i in cacheObj) { - for (var j in cacheObj[i]) { - delete cacheObj[i][j]; - } - } + searchbox.autocomplete().clearCache(); }); } diff --git a/themes/bootstrap3/js/lib/autocomplete.js b/themes/bootstrap3/js/lib/autocomplete.js index 35ce87424d4..db78e438fb3 100644 --- a/themes/bootstrap3/js/lib/autocomplete.js +++ b/themes/bootstrap3/js/lib/autocomplete.js @@ -1,14 +1,14 @@ -/* https://github.com/vufind-org/autocomplete.js 1.0b */ -(function autocomplete( $ ) { +/* https://github.com/vufind-org/autocomplete.js 1.0b2 */ +(function autocomplete($) { var element = false, + cache = {}, + optionStorage = {}, xhr = false; function Factory(_input, settings) { - var cache = (typeof(settings) === "object" && typeof(settings.cacheObj) === "object") - ? settings.cacheObj : {}; - return (function acClosure() { - var input = $(this), - options; + return function acClosure() { + var input = $(this); + var options = optionStorage[input.data('ac-id')]; var _align = function _align() { var position = input.offset(); @@ -17,61 +17,67 @@ left: position.left, minWidth: input.width() }); - } + }; - var show = function show() { + var _show = function _show() { element.removeClass(options.hidingClass); - } + }; var hide = function hide() { element.addClass(options.hidingClass); - } + }; var _populate = function _populate(item, eventType) { + input.trigger('ac:select', [item, eventType]); + var ret; if (options.callback) { - if (options.callback(item, input, eventType) === true && typeof item.href !== 'undefined') { + ret = options.callback(item, input, eventType); + if (ret === true && typeof item.href !== 'undefined') { return window.location.assign(item.href); } + if (ret === false) { + return false; + } } else if (typeof item.href !== 'undefined') { return window.location.assign(item.href); } - input.val(item.value); + input.val(typeof ret === 'undefined' ? item.value : ret); // Reset element.find('.ac-item.selected').removeClass('selected'); - $(this).data('selected', -1); + $(this).data('ac-selected', -1); setTimeout(function acPopulateDelay() { input.focus(); hide(); }, 10); - } + }; var _listToHTML = function _listToHTML(list, regex) { var shell = $('<div/>'); for (var i = 0; i < list.length; i++) { if (typeof list[i] === 'string') { - list[i] = {value: list[i]}; + list[i] = { value: list[i] }; } var content = list[i].label || list[i].value; if (options.highlight) { content = content.replace(regex, '<b>$1</b>'); } - var item = typeof list[i].href === 'undefined' - ? $('<div/>') - : $('<a/>').attr('href', list[i].href); + var item = typeof list[i].href === 'undefined' ? $('<div/>') : $('<a/>').attr('href', list[i].href); // list - item.data(list[i]) - .addClass('ac-item') - .html(content); + item + .data(list[i]) + .addClass('ac-item') + .html(content); if (typeof list[i].description !== 'undefined') { - item.append($('<small/>').html( - options.highlight - ? list[i].description.replace(regex, '<b>$1</b>') - : list[i].description - )); + item.append( + $('<small/>').html( + options.highlight ? list[i].description.replace(regex, '<b>$1</b>') : list[i].description + ) + ); } shell.append(item); } + input.trigger('ac:render', [shell[0]]); return shell; - } + }; var _createList = function _createList(data) { // highlighting setup // escape term for regex - https://github.com/sindresorhus/escape-string-regexp/blob/master/index.js @@ -87,10 +93,12 @@ shell.append($('<hr/>', { class: 'ac-section-divider' })); } if (typeof data.groups[i].label !== 'undefined') { - shell.append($('<header>', { - class: 'ac-section-header', - html: data.groups[i].label - })); + shell.append( + $('<header>', { + class: 'ac-section-header', + html: data.groups[i].label + }) + ); } if (typeof data.groups[i].label !== 'undefined' && data.groups[i].items.length > 0) { shell.append(_listToHTML(data.groups[i].items, regex)); @@ -100,29 +108,31 @@ } } element.html(shell); - input.data('length', shell.find('.ac-item').length); + input.data('ac-length', shell.find('.ac-item').length); element.find('.ac-item').mousedown(function acItemClick() { - _populate($(this).data(), {mouse: true}); + _populate($(this).data(), { mouse: true }); }); _align(); - } + }; var _handleResults = function _handleResults(term, _data) { // Limit results - var data = typeof _data.groups === 'undefined' - ? _data.slice(0, Math.min(options.maxResults, _data.length)) - : _data; - var cid = input.data('cacheId'); + var data = + typeof _data.groups === 'undefined' + ? _data.slice(0, Math.min(options.maxResults, _data.length)) + : _data; + var cid = input.data('ac-id'); cache[cid][term] = data; if (data.length === 0 || (typeof data.groups !== 'undefined' && data.groups.length === 0)) { hide(); } else { _createList(data); } - } - var _defaultStaticSort = function _defaultStaticSort(a, b) { // .bind(lcterm) + }; + var _defaultStaticSort = function _defaultStaticSort(a, b) { + // .bind(lcterm) return a.match.indexOf(this) - b.match.indexOf(this); - } + }; var _staticGroups = function _staticGroups(lcterm) { var matches = []; for (var i = 0; i < options.static.groups.length; i++) { @@ -156,24 +166,26 @@ } } return matches; - } + }; var search = function search() { - if (xhr) { xhr.abort(); } + if (xhr) { + xhr.abort(); + } if (input.val().length >= options.minLength) { element.html('<i class="ac-item loading">' + options.loadingString + '</i>'); - show(); + _show(); _align(); - input.data('selected', -1); + input.data('ac-selected', -1); var term = input.val(); // Check cache (only for handler-based setups) - var cid = input.data('cacheId'); - if (options.cache && typeof cache[cid][term] !== "undefined") { + var cid = input.data('ac-id'); + if (options.cache && typeof cache[cid][term] !== 'undefined') { if (cache[cid][term].length === 0) { hide(); } else { _createList(cache[cid][term]); } - // Check for static list + // Check for static list } else if (typeof options.static !== 'undefined') { var lcterm = term.toLowerCase(); var matches; @@ -190,7 +202,7 @@ } } _handleResults(term, matches); - // Call handler + // Call handler } else { options.handler(input, function achandlerCallback(data) { _handleResults(term, data); @@ -199,16 +211,26 @@ } else { hide(); } - } + }; function preprocessStatic(_item) { - var item = typeof _item === 'string' - ? { value: _item } - : _item; + var item = typeof _item === 'string' ? { value: _item } : _item; item.match = (item.label || item.value).toLowerCase(); return item; } - var _setup = function _setup() { + var _setup = function _setup(settings) { + var cid = Math.floor(Math.random() * 1000); + input.data('ac-id', cid); + input.data('ac-selected', -1); + input.data('ac-length', 0); + + options = $.extend({}, $.fn.autocomplete.defaults, settings); + optionStorage[input.data('ac-id')] = options; + + if (options.cache) { + cache[cid] = {}; + } + element = $('.autocomplete-results'); if (element.length === 0) { element = $('<div/>') @@ -218,15 +240,6 @@ $(document.body).append(element); } - input.data('selected', -1); - input.data('length', 0); - - if (options.cache) { - var cid = Math.floor(Math.random() * 1000); - input.data('cacheId', cid); - cache[cid] = {}; - } - input.blur(function acinputBlur(e) { if (e.target.acitem) { setTimeout(hide, 10); @@ -240,6 +253,9 @@ input.focus(function acinputFocus() { search(); }); + input.on('paste', function acinputPaste() { + requestAnimationFrame(search); + }); input.keyup(function acinputKeyup(event) { // Ignore navigation keys // - Ignore control functions @@ -251,26 +267,26 @@ return; } switch (event.which) { - case 9: // tab - case 13: // enter - case 16: // shift - case 20: // caps lock - case 27: // esc - case 33: // page up - case 34: // page down - case 35: // end - case 36: // home - case 37: // arrows - case 38: - case 39: - case 40: - case 45: // insert - case 144: // num lock - case 145: // scroll lock - case 19: // pause/break - return; - default: - search(); + case 9: // tab + case 13: // enter + case 16: // shift + case 20: // caps lock + case 27: // esc + case 33: // page up + case 34: // page down + case 35: // end + case 36: // home + case 37: // arrows + case 38: + case 39: + case 40: + case 45: // insert + case 144: // num lock + case 145: // scroll lock + case 19: // pause/break + return; + default: + search(); } }); input.keydown(function acinputKeydown(event) { @@ -278,69 +294,63 @@ if (event.ctrlKey || event.which === 17) { return; } - var position = $(this).data('selected'); + var position = $(this).data('ac-selected'); switch (event.which) { // arrow keys through items - case 38: // up key - event.preventDefault(); - element.find('.ac-item.selected').removeClass('selected'); - if (position > -1) { - if (position-- > 0) { + case 38: // up key + event.preventDefault(); + element.find('.ac-item.selected').removeClass('selected'); + if (position > -1) { + if (position-- > 0) { + element.find('.ac-item:eq(' + position + ')').addClass('selected'); + } + $(this).data('ac-selected', position); + } + break; + case 40: // down key + event.preventDefault(); + if (element.hasClass(options.hidingClass)) { + search(); + } else if (position < input.data('ac-length') - 1) { + position++; + element.find('.ac-item.selected').removeClass('selected'); element.find('.ac-item:eq(' + position + ')').addClass('selected'); + $(this).data('ac-selected', position); } - $(this).data('selected', position); - } - break; - case 40: // down key - event.preventDefault(); - if (element.hasClass(options.hidingClass)) { - search(); - } else if (position < input.data('length') - 1) { - position++; - element.find('.ac-item.selected').removeClass('selected'); - element.find('.ac-item:eq(' + position + ')').addClass('selected'); - $(this).data('selected', position); - } - break; + break; // enter to nav or populate - case 9: - case 13: - var selected = element.find('.ac-item.selected'); - if (selected.length > 0) { - event.preventDefault(); - if (event.which === 13 && selected.attr('href')) { - return window.location.assign(selected.attr('href')); - } else { - _populate(selected.data(), $(this), {key: true}); + case 9: + case 13: + var selected = element.find('.ac-item.selected'); + if (selected.length > 0) { + event.preventDefault(); + if (event.which === 13 && selected.attr('href') && options.callback === 'undefined') { + return window.location.assign(selected.attr('href')); + } else { + _populate(selected.data(), $(this), { key: true }); + } } - } - break; + break; // hide on escape - case 27: - hide(); - $(this).data('selected', -1); - break; + case 27: + hide(); + $(this).data('ac-selected', -1); + break; } }); - window.addEventListener("resize", hide, false); - } + window.addEventListener('resize', hide, false); + }; - if (typeof settings === "string") { - if (settings === "show") { - show(); - _align(); - } else if (settings === "hide") { - hide(); - } else if (options.cache && settings === "clear cache") { - var cid = parseInt(input.data('cacheId'), 10); - cache[cid] = {}; + // Setup + if (!input.data('ac-id')) { + if (typeof settings === 'undefined') { + console.error('Autocomplete not initialized, please pass setup parameters.'); + } + if (typeof settings.handler === 'undefined' && typeof settings.static === 'undefined') { + console.error('Neither handler function nor static result list provided for autocomplete'); + return null; } - return input; - } else if (typeof settings.handler === 'undefined' && typeof settings.static === 'undefined') { - console.error('Neither handler function nor static result list provided for autocomplete'); - return input; - } else { if (typeof settings.static !== 'undefined') { // Preprocess strings into items if (typeof settings.static.groups !== 'undefined') { @@ -355,18 +365,29 @@ settings.static = settings.static.map(preprocessStatic); } } - options = $.extend( {}, $.fn.autocomplete.defaults, settings ); - _setup(); + _setup(settings); } - return input; - }.bind(_input))(); + return { + show: function show() { + _show(); + _align(); + }, + hide: hide, + search: search, + clearCache: function clearCache() { + cache[input.data('ac-id')] = {}; + } + }; + }.bind(_input)(); } $.fn.autocomplete = function acJQuery(settings) { - return this.each(function acJQueryEach() { - return Factory(this, settings); + var ac; + this.each(function acJQueryEach() { + ac = Factory(this, settings); }); + return ac; }; $.fn.autocomplete.defaults = { @@ -380,12 +401,14 @@ var timer = false; $.fn.autocomplete.ajax = function acAjax(ops) { - if (timer) { clearTimeout(timer); } - if (xhr) { xhr.abort(); } - timer = setTimeout( - function acajaxDelay() { xhr = $.ajax(ops); }, - 200 - ); + if (timer) { + clearTimeout(timer); + } + if (xhr) { + xhr.abort(); + } + timer = setTimeout(function acajaxDelay() { + xhr = $.ajax(ops); + }, 200); }; - -}( jQuery )); +})(jQuery); -- GitLab