diff --git a/manifest.json b/manifest.json index 259f2f0..77c033a 100644 --- a/manifest.json +++ b/manifest.json @@ -57,6 +57,14 @@ "js": [ "src/content/tags.js" ] + }, + { + "matches": [ + "*://*.furbooru.org/images/*" + ], + "js": [ + "src/content/tags-editor.js" + ] } ], "action": { diff --git a/src/content/tags-editor.js b/src/content/tags-editor.js new file mode 100644 index 0000000..91207dd --- /dev/null +++ b/src/content/tags-editor.js @@ -0,0 +1,3 @@ +import {TagsForm} from "$lib/components/TagsForm.js"; + +TagsForm.watchForEditors(); diff --git a/src/lib/components/TagsForm.js b/src/lib/components/TagsForm.js new file mode 100644 index 0000000..f6abf84 --- /dev/null +++ b/src/lib/components/TagsForm.js @@ -0,0 +1,81 @@ +import {BaseComponent} from "$lib/components/base/BaseComponent.js"; +import {getComponent} from "$lib/components/base/ComponentUtils.js"; + +export class TagsForm extends BaseComponent { + /** + * Collect all the tag categories available on the page and color the tags in the editor according to them. + */ + refreshTagColors() { + const tagCategories = this.#gatherTagCategories(); + const editableTags = this.container.querySelectorAll('.tag'); + + for (let tagElement of editableTags) { + // Tag name is stored in the "remove" link and not in the tag itself. + const removeLink = tagElement.querySelector('a'); + + if (!removeLink) { + continue; + } + + const tagName = removeLink.dataset.tagName; + + if (!tagCategories.has(tagName)) { + continue; + } + + const categoryName = tagCategories.get(tagName); + + tagElement.dataset.tagCategory = categoryName; + tagElement.setAttribute('data-tag-category', categoryName); + } + } + + /** + * Collect list of categories from the tags on the page. + * @return {Map} + */ + #gatherTagCategories() { + /** @type {Map} */ + const tagCategories = new Map(); + + for (let tagElement of document.querySelectorAll('.tag[data-tag-name][data-tag-category]')) { + tagCategories.set(tagElement.dataset.tagName, tagElement.dataset.tagCategory); + } + + return tagCategories; + } + + static watchForEditors() { + document.body.addEventListener('click', event => { + const targetElement = event.target; + + if (!(targetElement instanceof HTMLElement)) { + return; + } + + const tagEditorWrapper = targetElement.closest('#image_tags_and_source'); + + if (!tagEditorWrapper) { + return; + } + + const refreshTrigger = targetElement.closest('.js-taginput-show, #edit-tags') + + if (!refreshTrigger) { + return; + } + + const tagFormElement = tagEditorWrapper.querySelector('#tags-form'); + + /** @type {TagsForm|null} */ + let tagEditor = getComponent(tagFormElement); + + if (!tagEditor || (!tagEditor instanceof TagsForm)) { + tagEditor = new TagsForm(tagFormElement); + tagEditor.initialize(); + } + + tagEditor.refreshTagColors(); + }); + } +}