aboutsummaryrefslogtreecommitdiff
path: root/static/scripts/dynamic_input.js
diff options
context:
space:
mode:
authorArjun Satarkar <me@arjunsatarkar.net>2023-08-04 20:02:00 +0000
committerArjun Satarkar <me@arjunsatarkar.net>2023-08-04 20:03:29 +0000
commitb42091406ba4f4abe8591a793e2334d38613aaf5 (patch)
tree6b1e30d7a42cb41cff2ef50887b6010516152329 /static/scripts/dynamic_input.js
parent8f5488436b90d85969abb8bdcbb0ecf14d8936bd (diff)
downloadtagrss-b42091406ba4f4abe8591a793e2334d38613aaf5.tar
tagrss-b42091406ba4f4abe8591a793e2334d38613aaf5.tar.gz
tagrss-b42091406ba4f4abe8591a793e2334d38613aaf5.zip
Make tag input nicer with JS (if enabled)HEADmain
Diffstat (limited to 'static/scripts/dynamic_input.js')
-rw-r--r--static/scripts/dynamic_input.js84
1 files changed, 84 insertions, 0 deletions
diff --git a/static/scripts/dynamic_input.js b/static/scripts/dynamic_input.js
new file mode 100644
index 0000000..df1c8fe
--- /dev/null
+++ b/static/scripts/dynamic_input.js
@@ -0,0 +1,84 @@
+"use strict";
+(() => {
+ const outerContainer = document.querySelector("div.tag-input-container");
+ const rawInput = document.createElement("input");
+ const name = outerContainer.querySelector("span#tags-input-name-span").innerText;
+ rawInput.setAttribute("type", "hidden");
+ rawInput.setAttribute("name", name);
+ outerContainer.appendChild(rawInput);
+
+ function parseSpaceSeparatedTags(inp) {
+ const tags = new Set();
+ let tag = ""
+ let escaped = false;
+ for (const c of inp) {
+ switch (c) {
+ case "\\":
+ if (!escaped) {
+ escaped = true;
+ continue;
+ }
+ case " ":
+ if (!escaped) {
+ tags.add(tag);
+ tag = "";
+ continue;
+ }
+ }
+ escaped = false;
+ tag += c;
+ }
+ if (tag) {
+ tags.add(tag);
+ }
+ return Array.from(tags).sort((a, b) => a.localeCompare(b));
+ }
+
+ const dynamicInputContainer = document.createElement("span");
+
+ function createDynamicInput() {
+ const dynamicInput = document.createElement("input");
+ dynamicInput.setAttribute("class", "dynamic-tag-input");
+ // So autocomplete will work
+ dynamicInput.setAttribute("name", "dynamic_tag_input");
+ dynamicInput.addEventListener("input", handleInput);
+ return dynamicInput;
+ };
+
+ function handleInput(e) {
+ const sources = document.querySelectorAll("input.dynamic-tag-input");
+ const lastDynamicInput = sources[sources.length - 1];
+ if (e.currentTarget === lastDynamicInput && e.currentTarget.value) {
+ dynamicInputContainer.appendChild(createDynamicInput());
+ } else if (e.currentTarget === sources[sources.length - 2] && !e.currentTarget.value) {
+ dynamicInputContainer.removeChild(lastDynamicInput);
+ }
+ let serialised = "";
+ for (const [i, source] of sources.entries()) {
+ const tag = source.value;
+ if (!tag) { continue; }
+ if (i > 0) {
+ serialised += " ";
+ }
+ serialised += tag.replaceAll("\\", "\\\\").replaceAll(" ", "\\ ");
+ }
+ rawInput.value = serialised;
+ };
+
+ const firstDynamicInput = createDynamicInput();
+ firstDynamicInput.setAttribute("id", "tags-input");
+ dynamicInputContainer.appendChild(firstDynamicInput);
+
+ const initialValue = outerContainer.querySelector("span#tags-input-initial-value-span").innerText;
+ if (initialValue) {
+ const tags = parseSpaceSeparatedTags(initialValue);
+ let input = dynamicInputContainer.querySelector("input.dynamic-tag-input:last-of-type");
+ for (const tag of tags) {
+ input.value = tag;
+ input = createDynamicInput();
+ dynamicInputContainer.appendChild(input);
+ }
+ }
+
+ outerContainer.appendChild(dynamicInputContainer);
+})();