diff --git a/phpBB/assets/javascript/editor.js b/phpBB/assets/javascript/editor.js index 9972ffdd6a..b6382304bc 100644 --- a/phpBB/assets/javascript/editor.js +++ b/phpBB/assets/javascript/editor.js @@ -387,15 +387,35 @@ function getCaretPosition(txtarea) { (function($) { function Mentions() { let $mentionDataContainer = $('[data-mention-url]:first'); + let mentionURL = $mentionDataContainer.data('mentionUrl'); + let mentionBatchSize = $mentionDataContainer.data('mentionBatchSize'); + let mentionNamesLimit = $mentionDataContainer.data('mentionNamesLimit'); + let mentionTopicId = $mentionDataContainer.data('topicId'); let queryInProgress = null; - let cachedNames = null; - let cachedFor = null; + let cachedNames = []; let cachedSearchKey = 'name'; function defaultAvatar(type) { return (type === 'group') ? '' : ''; } + function getCachedNames(query) { + if (!cachedNames) { + return null; + } + + let i; + + for (i = query.length; i > 0; i--) { + let startStr = query.substr(0, i); + if (cachedNames[startStr]) { + return cachedNames[startStr]; + } + } + + return cachedNames['']; + } + function getMatchedNames(query, items, searchKey) { let i; let len; @@ -413,15 +433,50 @@ function getCaretPosition(txtarea) { return getMatchedNames(query, cachedNames, cachedSearchKey).length; } + function remoteFilter(query, callback) { + /* + * Do not make a new request until the previous one for the same query is returned + * This fixes duplicate server queries e.g. when arrow keys are pressed + */ + if (queryInProgress === query) { + setTimeout(function() { + remoteFilter(query, callback); + }, 1000); + return; + } + + let cachedNamesForQuery = getCachedNames(query); + + /* + * Use cached values when we can: + * 1) There are some names in the cache relevant for the query + * (cache for the query with the same first characters cointains some data) + * 2) We have enough names to display OR + * all relevant names have been fetched from the server + */ + if (cachedNamesForQuery && + (getNumberOfMatchedCachedNames(query) >= mentionNamesLimit || + cachedNamesForQuery.length < mentionBatchSize)) { + callback(cachedNamesForQuery); + return; + } + + queryInProgress = query; + + let params = {keyword: query, topic_id: mentionTopicId, _referer: location.href}; + $.getJSON(mentionURL, params, function(data) { + cachedNames[query] = data; + callback(data); + }).always(function() { + queryInProgress = null; + }); + } + this.isEnabled = function() { return $mentionDataContainer.length; }; this.handle = function(txtarea) { - let mentionURL = $mentionDataContainer.data('mentionUrl'); - let mentionBatchSize = $mentionDataContainer.data('mentionBatchSize'); - let mentionNamesLimit = $mentionDataContainer.data('mentionNamesLimit'); - let mentionTopicId = $mentionDataContainer.data('topicId'); $(txtarea).atwho({ at: "@", acceptSpaceBar: true, @@ -434,40 +489,7 @@ function getCaretPosition(txtarea) { insertTpl: "[mention=${type}:${id}]${name}[/mention]", limit: mentionNamesLimit, callbacks: { - remoteFilter: function(query, callback) { - /* - * Use cached values when we can: - * 1) There are some names in the cache - * 2) The cache contains relevant data for the query - * (it was made for the query with the same first characters) - * 3) We have enough names to display OR - * all relevant names have been fetched from the server - */ - if (cachedNames && - query.indexOf(cachedFor) === 0 && - (getNumberOfMatchedCachedNames(query) >= mentionNamesLimit || - cachedNames.length < mentionBatchSize)) { - callback(cachedNames); - return; - } - - /* - * Do not make a new request until the previous one for the same query is returned - * This fixes duplicate server queries e.g. when arrow keys are pressed - */ - if (queryInProgress === query) { - return; - } - queryInProgress = query; - - let params = {keyword: query, topic_id: mentionTopicId, _referer: location.href}; - $.getJSON(mentionURL, params, function (data) { - cachedNames = data; - cachedFor = query; - queryInProgress = null; - callback(data); - }); - }, + remoteFilter: remoteFilter, sorter: function(query, items, searchKey) { let i; let len;