From 0404d0dfa2f166ef9fc058212d76fbb8d22a9f51 Mon Sep 17 00:00:00 2001 From: Andrew Shu Date: Tue, 14 Jul 2020 20:37:07 -0700 Subject: [PATCH] Process tags to left of comma only If user types "tag1 tag2" then adds a comma between, it should respect the comma to give "tag1" and "tag2". We use keydown and setTimeout because keyup works on a keyboard but not reliably on mobile. Nonzero timeout is needed or else the comma is sometimes inserted too late and not seen by addChip(), tested on desktop Firefox. --- .../static/js/behaviors/autocomplete-input.js | 72 +++++++++++-------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/tildes/static/js/behaviors/autocomplete-input.js b/tildes/static/js/behaviors/autocomplete-input.js index 52f4d39..fb68f6d 100644 --- a/tildes/static/js/behaviors/autocomplete-input.js +++ b/tildes/static/js/behaviors/autocomplete-input.js @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later $.onmount("[data-js-autocomplete-input]", function() { - function addChip($input) { + function addChip($input, userTypedComma) { var $autocompleteContainer = $input .parents("[data-js-autocomplete-container]") .first(); @@ -11,7 +11,8 @@ $.onmount("[data-js-autocomplete-input]", function() { .first(); var $tagsHiddenInput = $("[data-js-autocomplete-hidden-input]"); - $input + var remaining = ""; + var inputTags = $input .val() .split(",") .map(function(tag) { @@ -19,36 +20,43 @@ $.onmount("[data-js-autocomplete-input]", function() { }) .filter(function(tag) { return tag !== ""; - }) - .forEach(function(tag) { - if (!$tagsHiddenInput.val().match(new RegExp("(^|,)" + tag + ","))) { - var clearIcon = document.createElement("a"); - clearIcon.classList.add("btn"); - clearIcon.classList.add("btn-clear"); - clearIcon.setAttribute("data-js-autocomplete-chip-clear", ""); - clearIcon.setAttribute("aria-label", "Close"); - clearIcon.setAttribute("role", "button"); - clearIcon.setAttribute("tabindex", $chips.children().length); - - var $chip = $(document.createElement("div")); - $chip.addClass("chip"); - $chip.html(tag); - $chip.append(clearIcon); - - if (!tag.match(/^[\w .]+$/)) { - $chip.addClass("error"); - $chip.attr( - "title", - "Tags may only contain letters, numbers, and spaces." - ); - } + }); - $chips.append($chip); + // process only first tag, to left of comma, if user typed comma + if (userTypedComma && $input.val().indexOf(",") !== -1) { + remaining = inputTags.slice(1).join(", "); + inputTags = inputTags.slice(0, 1); + } - $tagsHiddenInput.val($tagsHiddenInput.val() + tag + ","); + inputTags.forEach(function(tag) { + if (!$tagsHiddenInput.val().match(new RegExp("(^|,)" + tag + ","))) { + var clearIcon = document.createElement("a"); + clearIcon.classList.add("btn"); + clearIcon.classList.add("btn-clear"); + clearIcon.setAttribute("data-js-autocomplete-chip-clear", ""); + clearIcon.setAttribute("aria-label", "Close"); + clearIcon.setAttribute("role", "button"); + clearIcon.setAttribute("tabindex", $chips.children().length); + + var $chip = $(document.createElement("div")); + $chip.addClass("chip"); + $chip.html(tag); + $chip.append(clearIcon); + + if (!tag.match(/^[\w .]+$/)) { + $chip.addClass("error"); + $chip.attr( + "title", + "Tags may only contain letters, numbers, and spaces." + ); } - }); - $autocompleteContainer.find("[data-js-autocomplete-input]").val(""); + + $chips.append($chip); + + $tagsHiddenInput.val($tagsHiddenInput.val() + tag + ","); + } + }); + $autocompleteContainer.find("[data-js-autocomplete-input]").val(remaining); $autocompleteContainer.find("[data-js-autocomplete-suggestions]").html(""); $.onmount(); @@ -102,6 +110,7 @@ $.onmount("[data-js-autocomplete-input]", function() { }); $(this).keydown(function(event) { + var $this = $(this); var $autocompleteMenu = $("[data-js-autocomplete-menu]").first(); var $nextActiveItem = null; @@ -111,6 +120,11 @@ $.onmount("[data-js-autocomplete-input]", function() { $(this).blur(); break; case ",": + // wait for comma to be added to text so addChip() sees it + setTimeout(function() { + addChip($this, true); + }, 100); + break; case "Enter": event.preventDefault(); addChip($(this));