From b877c037b21188af4f37cebf622f84b57275c29a Mon Sep 17 00:00:00 2001 From: evazion Date: Tue, 13 Feb 2018 21:39:19 -0600 Subject: [PATCH 1/2] autocomplete: factor out insert_completion function. --- app/assets/javascripts/autocomplete.js.erb | 37 ++++++++++------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/autocomplete.js.erb b/app/assets/javascripts/autocomplete.js.erb index c22ab7189..8067c98df 100644 --- a/app/assets/javascripts/autocomplete.js.erb +++ b/app/assets/javascripts/autocomplete.js.erb @@ -53,20 +53,10 @@ return false; }, select: function(event, ui) { - var before_caret_text = this.value.substring(0, this.selectionStart).replace(/\S+$/, ui.item.value + " "); - var after_caret_text = this.value.substring(this.selectionStart); - this.value = before_caret_text; + Danbooru.Autocomplete.insert_completion(this, ui.item.value); - // Preserve original caret position to prevent it from jumping to the end - var original_start = this.selectionStart; - this.value += after_caret_text; - this.selectionStart = this.selectionEnd = original_start; - - // Prevent the enter key from submitting the tag edit form (Danbooru.Upload.initialize_enter_on_tags). - event.stopImmediatePropagation(); // Prevent the tab key from moving the focus to the next element. event.preventDefault(); - return false; }, source: function(req, resp) { @@ -115,16 +105,7 @@ return false; } - var before_caret_text = this.value.substring(0, this.selectionStart); - var after_caret_text = this.value.substring(this.selectionStart); - var prefixes = "-|~|" + "<%= TagCategory.mapping.keys.map {|category| category + ':'}.join('|') %>"; - var regexp = new RegExp("(" + prefixes + ")?\\S+$", "g"); - this.value = before_caret_text.replace(regexp, "$1" + ui.item.value + " "); - - // Preserve original caret position to prevent it from jumping to the end - var original_start = this.selectionStart; - this.value += after_caret_text; - this.selectionStart = this.selectionEnd = original_start; + Danbooru.Autocomplete.insert_completion(this, ui.item.value); event.stopImmediatePropagation(); event.preventDefault(); @@ -281,6 +262,20 @@ return { metatag: metatag, term: term }; }; + // Update the input field with the item currently focused in the + // autocomplete menu, then position the caret just after the inserted completion. + Danbooru.Autocomplete.insert_completion = function(input, completion) { + var before_caret_text = input.value.substring(0, input.selectionStart).trim(); + var after_caret_text = input.value.substring(input.selectionStart).trim(); + + var prefixes = "-|~|" + "<%= TagCategory.mapping.keys.map {|category| category + ':'}.join('|') %>"; + var regexp = new RegExp("(" + prefixes + ")?\\S+$", "g"); + before_caret_text = before_caret_text.replace(regexp, "$1") + completion + " "; + + input.value = before_caret_text + after_caret_text; + input.selectionStart = input.selectionEnd = before_caret_text.length; + }; + Danbooru.Autocomplete.render_item = function(list, item) { var $link = $(""); From 0e259bd4f6fa11d6bfd42f39816a76e71308520f Mon Sep 17 00:00:00 2001 From: evazion Date: Wed, 14 Feb 2018 21:58:20 -0600 Subject: [PATCH 2/2] autocomplete: fix issues with Enter key. * Disable autoFocus. This means that the first item in the autocomplete menu isn't automatically selected. * Add Tab keybinding, to make the Tab key work as normal with autoFocus disabled. * Fix the Enter key to 1) insert the selected tag when inside the autocomplete menu, and 2) submit the search as normal when not inside the autocomplete menu. --- app/assets/javascripts/autocomplete.js.erb | 44 ++++++++++++++++------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/autocomplete.js.erb b/app/assets/javascripts/autocomplete.js.erb index 8067c98df..f3b88c03d 100644 --- a/app/assets/javascripts/autocomplete.js.erb +++ b/app/assets/javascripts/autocomplete.js.erb @@ -45,18 +45,17 @@ Danbooru.Autocomplete.initialize_mention_autocomplete = function() { var $fields = $(".autocomplete-mentions textarea"); + + $fields.on("keydown.danbooru.autocomplete.tab", null, "tab", Danbooru.Autocomplete.on_tab); $fields.autocomplete({ delay: 500, minLength: 2, - autoFocus: true, + autoFocus: false, focus: function() { return false; }, select: function(event, ui) { Danbooru.Autocomplete.insert_completion(this, ui.item.value); - - // Prevent the tab key from moving the focus to the next element. - event.preventDefault(); return false; }, source: function(req, resp) { @@ -92,23 +91,21 @@ var $fields_multiple = $('[data-autocomplete="tag-query"], [data-autocomplete="tag-edit"]'); var $fields_single = $('[data-autocomplete="tag"]'); + $fields_multiple.on("keydown.danbooru.autocomplete.tab", null, "tab", Danbooru.Autocomplete.on_tab); $fields_multiple.autocomplete({ delay: 100, - autoFocus: true, + autoFocus: false, focus: function() { return false; }, select: function(event, ui) { - var query = Danbooru.Autocomplete.parse_query(this.value, this.selectionStart); - if (event.key === "Enter" && query.term === ui.item.value) { - $(this).parents("form").submit(); - return false; + // Prevent Danbooru.Upload.initialize_enter_on_tags from running if the + // Enter key is used to select a tag from the autocomplete menu. + if (event.key === "Enter") { + event.stopImmediatePropagation(); } Danbooru.Autocomplete.insert_completion(this, ui.item.value); - - event.stopImmediatePropagation(); - event.preventDefault(); return false; }, source: function(req, resp) { @@ -276,6 +273,29 @@ input.selectionStart = input.selectionEnd = before_caret_text.length; }; + // If we press tab while the autocomplete menu is open but nothing is + // focused, complete the first item and close the menu. + Danbooru.Autocomplete.on_tab = function(event) { + var input = this; + var autocomplete = $(input).autocomplete("instance"); + var $autocomplete_menu = autocomplete.menu.element; + + if (!$autocomplete_menu.is(":visible")) { + return; + } + + if ($autocomplete_menu.has(".ui-state-focus").length === 0) { + var $first_item = $autocomplete_menu.find(".ui-menu-item").first(); + var completion = $first_item.data().uiAutocompleteItem.value; + + Danbooru.Autocomplete.insert_completion(input, completion); + autocomplete.close(); + } + + // Prevent the tab key from moving focus to the next element. + event.preventDefault(); + }; + Danbooru.Autocomplete.render_item = function(list, item) { var $link = $("");