From 977cc47966f4b9dfddf62e53d9c614593fd29f7f Mon Sep 17 00:00:00 2001 From: rr- Date: Thu, 29 Sep 2016 22:45:40 +0200 Subject: [PATCH] client/search: escape : in tag search --- client/js/controls/auto_complete_control.js | 67 +++++++++++++-------- client/js/util/misc.js | 5 ++ client/js/views/posts_header_view.js | 3 +- client/js/views/tags_header_view.js | 3 +- 4 files changed, 52 insertions(+), 26 deletions(-) diff --git a/client/js/controls/auto_complete_control.js b/client/js/controls/auto_complete_control.js index 2bb1c9f8..3f46ab5b 100644 --- a/client/js/controls/auto_complete_control.js +++ b/client/js/controls/auto_complete_control.js @@ -28,6 +28,7 @@ class AutoCompleteControl { this._sourceInputNode = sourceInputNode; this._options = {}; Object.assign(this._options, { + transform: null, verticalShift: 2, source: null, addSpace: false, @@ -37,27 +38,8 @@ class AutoCompleteControl { const start = _getSelectionStart(sourceInputNode); return value.substring(0, start).replace(/.*\s+/, ''); }, - confirm: text => { - const start = _getSelectionStart(sourceInputNode); - let prefix = ''; - let suffix = sourceInputNode.value.substring(start); - let middle = sourceInputNode.value.substring(0, start); - const index = middle.lastIndexOf(' '); - if (index !== -1) { - prefix = sourceInputNode.value.substring(0, index + 1); - middle = sourceInputNode.value.substring(index + 1); - } - sourceInputNode.value = prefix + - this._results[this._activeResult].value + - ' ' + - suffix.trimLeft(); - if (!this._options.addSpace) { - sourceInputNode.value = sourceInputNode.value.trim(); - } - sourceInputNode.focus(); - }, - delete: text => { - }, + confirm: null, + delete: null, getMatches: null, }, options); @@ -74,6 +56,43 @@ class AutoCompleteControl { this._isVisible = false; } + defaultConfirmStrategy(text) { + const start = _getSelectionStart(this._sourceInputNode); + let prefix = ''; + let suffix = this._sourceInputNode.value.substring(start); + let middle = this._sourceInputNode.value.substring(0, start); + const index = middle.lastIndexOf(' '); + if (index !== -1) { + prefix = this._sourceInputNode.value.substring(0, index + 1); + middle = this._sourceInputNode.value.substring(index + 1); + } + this._sourceInputNode.value = prefix + text + ' ' + suffix.trimLeft(); + if (!this._options.addSpace) { + this._sourceInputNode.value = this._sourceInputNode.value.trim(); + } + this._sourceInputNode.focus(); + } + + _delete(text) { + if (this._options.transform) { + text = this._options.transform(text); + } + if (this._options.delete) { + this._options.delete(text); + } + } + + _confirm(text) { + if (this._options.transform) { + text = this._options.transform(text); + } + if (this._options.confirm) { + this._options.confirm(text); + } else { + this.defaultConfirmStrategy(text); + } + } + _show() { this._suggestionDiv.style.display = 'block'; this._isVisible = true; @@ -136,12 +155,12 @@ class AutoCompleteControl { func = () => { this._selectNext(); }; } else if (key === KEY_RETURN && this._activeResult >= 0) { func = () => { - this._options.confirm(this._getActiveSuggestion()); + this._confirm(this._getActiveSuggestion()); this.hide(); }; } else if (key === KEY_DELETE && this._activeResult >= 0) { func = () => { - this._options.delete(this._getActiveSuggestion()); + this._delete(this._getActiveSuggestion()); this.hide(); }; } @@ -229,7 +248,7 @@ class AutoCompleteControl { e => { e.preventDefault(); this._activeResult = resultIndexWorkaround; - this._options.confirm(this._getActiveSuggestion()); + this._confirm(this._getActiveSuggestion()); this.hide(); }); listItem.appendChild(link); diff --git a/client/js/util/misc.js b/client/js/util/misc.js index 32580301..56eb66e6 100644 --- a/client/js/util/misc.js +++ b/client/js/util/misc.js @@ -213,6 +213,10 @@ function arraysDiffer(source1, source2, orderImportant) { source2.filter(value => !source1.includes(value)).length > 0); } +function escapeSearchTerm(text) { + return text.replace(/([a-z_-]):/g, '$1\\:'); +} + module.exports = { range: range, formatUrlParameters: formatUrlParameters, @@ -231,4 +235,5 @@ module.exports = { splitByWhitespace: splitByWhitespace, arraysDiffer: arraysDiffer, decamelize: decamelize, + escapeSearchTerm: escapeSearchTerm, }; diff --git a/client/js/views/posts_header_view.js b/client/js/views/posts_header_view.js index 2425f51c..04764c1e 100644 --- a/client/js/views/posts_header_view.js +++ b/client/js/views/posts_header_view.js @@ -21,7 +21,8 @@ class PostsHeaderView extends events.EventTarget { views.replaceContent(this._hostNode, template(ctx)); this._queryAutoCompleteControl = new TagAutoCompleteControl( - this._queryInputNode, {addSpace: true}); + this._queryInputNode, + {addSpace: true, transform: misc.escapeSearchTerm}); if (this._massTagInputNode) { this._masstagAutoCompleteControl = new TagAutoCompleteControl( this._massTagInputNode, {addSpace: false}); diff --git a/client/js/views/tags_header_view.js b/client/js/views/tags_header_view.js index cb0489e8..8b1b4767 100644 --- a/client/js/views/tags_header_view.js +++ b/client/js/views/tags_header_view.js @@ -17,7 +17,8 @@ class TagsHeaderView extends events.EventTarget { views.replaceContent(this._hostNode, template(ctx)); if (this._queryInputNode) { - new TagAutoCompleteControl(this._queryInputNode); + new TagAutoCompleteControl( + this._queryInputNode, {transform: misc.escapeSearchTerm}); } search.searchInputNodeFocusHelper(this._queryInputNode);