mirror of
https://github.com/koloml/furbooru-tagging-assistant.git
synced 2025-12-24 07:12:57 +00:00
Tags Editor: Removed Web Component with a component made with Svelte
Additionally, this editor works a little bit better when used with keyboard. It supports tabbing between "remove" buttons inside the tags and pressing them with Space/Enter. Web Component was an idea to keep the editor the same between frontend and Svelte app, but as I figured out later, extensions can't use those. Unfortunate.
This commit is contained in:
@@ -1,21 +1,94 @@
|
||||
<script>
|
||||
import "$lib/web-components/TagEditorComponent.js";
|
||||
|
||||
/**
|
||||
* List of tags to edit. Any duplicated tags present in the array will be removed on the first edit.
|
||||
* @type {string[]}
|
||||
*/
|
||||
export let tags = [];
|
||||
|
||||
let tagsAttribute = tags.join(',');
|
||||
/** @type {Set<string>} */
|
||||
let uniqueTags = new Set();
|
||||
|
||||
$: uniqueTags = new Set(tags);
|
||||
|
||||
/** @type {string} */
|
||||
let addedTagName = '';
|
||||
|
||||
/**
|
||||
* @param {CustomEvent<string[]>} event
|
||||
* Create a callback function to pass into both mouse & keyboard events for tag removal.
|
||||
* @param {string} tagName
|
||||
* @return {function(Event)} Callback to pass as event listener.
|
||||
*/
|
||||
function onTagsChanged(event) {
|
||||
tags = event.detail;
|
||||
function createTagRemoveHandler(tagName) {
|
||||
return event => {
|
||||
if (event.type === 'click') {
|
||||
removeTag(tagName);
|
||||
}
|
||||
|
||||
if (event instanceof KeyboardEvent && (event.code === 'Enter' || event.code === 'Space')) {
|
||||
// To be more comfortable, automatically focus next available tag's remove button in the list.
|
||||
if (event.currentTarget instanceof HTMLElement) {
|
||||
const currenTagElement = event.currentTarget.closest('.tag');
|
||||
const nextTagElement = currenTagElement?.previousElementSibling ?? currenTagElement?.parentElement?.firstElementChild;
|
||||
const nextRemoveButton = nextTagElement?.querySelector('.remove');
|
||||
|
||||
if (nextRemoveButton instanceof HTMLElement) {
|
||||
nextRemoveButton.focus();
|
||||
}
|
||||
}
|
||||
|
||||
removeTag(tagName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: tagsAttribute = tags.join(',');
|
||||
/**
|
||||
* @param {string} tagName
|
||||
*/
|
||||
function removeTag(tagName) {
|
||||
uniqueTags.delete(tagName);
|
||||
tags = Array.from(uniqueTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} tagName
|
||||
*/
|
||||
function addTag(tagName) {
|
||||
uniqueTags.add(tagName);
|
||||
tags = Array.from(uniqueTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle adding new tags to the list or removing them when backspace is pressed.
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
function handleKeyPresses(event) {
|
||||
if (event.code === 'Enter' && addedTagName.length) {
|
||||
addTag(addedTagName)
|
||||
addedTagName = '';
|
||||
}
|
||||
|
||||
if (event.code === 'Backspace' && !addedTagName.length && tags?.length) {
|
||||
removeTag(tags[tags.length - 1]);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<tags-editor tags="{tagsAttribute}" on:change={onTagsChanged}></tags-editor>
|
||||
<div class="tags-editor">
|
||||
{#each uniqueTags.values() as tagName}
|
||||
<div class="tag">
|
||||
{tagName}
|
||||
<span class="remove" on:click={createTagRemoveHandler(tagName)}
|
||||
on:keydown={createTagRemoveHandler(tagName)}
|
||||
role="button" tabindex="0">x</span>
|
||||
</div>
|
||||
{/each}
|
||||
<input type="text" bind:value={addedTagName} on:keydown={handleKeyPresses}/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.tags-editor {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user