mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	Add bulk tagging
This commit is contained in:
		@@ -2,14 +2,17 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
    callPopup,
 | 
			
		||||
    characters, deleteCharacter,
 | 
			
		||||
    characters,
 | 
			
		||||
    deleteCharacter,
 | 
			
		||||
    event_types,
 | 
			
		||||
    eventSource,
 | 
			
		||||
    getCharacters,
 | 
			
		||||
    getRequestHeaders, handleDeleteCharacter, this_chid
 | 
			
		||||
    getRequestHeaders,
 | 
			
		||||
    this_chid
 | 
			
		||||
} from "../script.js";
 | 
			
		||||
import {favsToHotswap} from "./RossAscends-mods.js";
 | 
			
		||||
import {convertCharacterToPersona} from "./personas.js";
 | 
			
		||||
import {createTagInput, getTagKeyForCharacter, tag_map} from "./tags.js";
 | 
			
		||||
 | 
			
		||||
const popupMessage = {
 | 
			
		||||
    deleteChat(characterCount) {
 | 
			
		||||
@@ -20,9 +23,6 @@ const popupMessage = {
 | 
			
		||||
                    <span>Also delete the chat files</span>
 | 
			
		||||
                </label><br></b>`;
 | 
			
		||||
    },
 | 
			
		||||
    exportCharacters(characterCount) {
 | 
			
		||||
        return `<h3>Export ${characterCount} characters?</h3>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const toggleFavoriteHighlight = (characterId) => {
 | 
			
		||||
@@ -30,20 +30,16 @@ const toggleFavoriteHighlight = (characterId) => {
 | 
			
		||||
    element.classList.toggle('is_fav');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implement a SingletonPattern, allowing access to the group overlay instance
 | 
			
		||||
 * from everywhere via (new CharacterGroupOverlay())
 | 
			
		||||
 *
 | 
			
		||||
 * @type BulkEditOverlay
 | 
			
		||||
 */
 | 
			
		||||
let characterGroupOverlayInstance = null;
 | 
			
		||||
 | 
			
		||||
class CharacterGroupOverlayState {
 | 
			
		||||
    static browse = 0;
 | 
			
		||||
    static select = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class CharacterContextMenu {
 | 
			
		||||
    static tag = (selectedCharacters) => {
 | 
			
		||||
        BulkTagPopupHandler.show(selectedCharacters);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Duplicate a character
 | 
			
		||||
     *
 | 
			
		||||
@@ -141,13 +137,72 @@ class CharacterContextMenu {
 | 
			
		||||
            {id: 'character_context_menu_favorite', callback: characterGroupOverlay.handleContextMenuFavorite},
 | 
			
		||||
            {id: 'character_context_menu_duplicate', callback: characterGroupOverlay.handleContextMenuDuplicate},
 | 
			
		||||
            {id: 'character_context_menu_delete', callback: characterGroupOverlay.handleContextMenuDelete},
 | 
			
		||||
            {id: 'character_context_menu_persona', callback: characterGroupOverlay.handleContextMenuPersona}
 | 
			
		||||
            {id: 'character_context_menu_persona', callback: characterGroupOverlay.handleContextMenuPersona},
 | 
			
		||||
            {id: 'character_context_menu_tag', callback: characterGroupOverlay.handleContextMenuTag}
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        contextMenuItems.forEach(contextMenuItem => document.getElementById(contextMenuItem.id).addEventListener('click', contextMenuItem.callback))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Appends/Removes the bulk tag popup
 | 
			
		||||
 */
 | 
			
		||||
class BulkTagPopupHandler {
 | 
			
		||||
    static #getHtml = (characterIds) => {
 | 
			
		||||
        const characterData = JSON.stringify({characterIds: characterIds});
 | 
			
		||||
        return `<div id="bulk_tag_shadow_popup">
 | 
			
		||||
            <div id="bulk_tag_popup">
 | 
			
		||||
                <div id="bulk_tag_popup_holder">
 | 
			
		||||
                <h3 class="m-b-1">Add tags to ${characterIds.length} characters</h3>
 | 
			
		||||
                <br>
 | 
			
		||||
                    <div id="bulk_tags_div" class="marginBot5" data-characters='${characterData}'>
 | 
			
		||||
                        <div class="tag_controls">
 | 
			
		||||
                            <input id="bulkTagInput" class="text_pole tag_input wide100p margin0" data-i18n="[placeholder]Search / Create Tags" placeholder="Search / Create tags" maxlength="25" />
 | 
			
		||||
                            <div class="tags_view menu_button fa-solid fa-tags" title="View all tags" data-i18n="[title]View all tags"></div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div id="bulkTagList" class="m-t-1 tags"></div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div id="dialogue_popup_controls" class="m-t-1">
 | 
			
		||||
                        <div id="bulk_tag_popup_cancel" class="menu_button" data-i18n="Cancel">Close</div>
 | 
			
		||||
                        <div id="bulk_tag_popup_reset" class="menu_button" data-i18n="Cancel">Remove all</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    `
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static show(characters) {
 | 
			
		||||
        document.body.insertAdjacentHTML('beforeend', this.#getHtml(characters));
 | 
			
		||||
        createTagInput('#bulkTagInput', '#bulkTagList');
 | 
			
		||||
        document.querySelector('#bulk_tag_popup_cancel').addEventListener('click', this.hide.bind(this));
 | 
			
		||||
        document.querySelector('#bulk_tag_popup_reset').addEventListener('click', this.resetTags.bind(this, characters));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static hide() {
 | 
			
		||||
        let popupElement = document.querySelector('#bulk_tag_shadow_popup');
 | 
			
		||||
        if (popupElement) {
 | 
			
		||||
            document.body.removeChild(popupElement);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static resetTags(characterIds) {
 | 
			
		||||
        characterIds.forEach((characterId) => {
 | 
			
		||||
            const key = getTagKeyForCharacter(characterId);
 | 
			
		||||
            if (key) tag_map[key] = [];
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implement a SingletonPattern, allowing access to the group overlay instance
 | 
			
		||||
 * from everywhere via (new CharacterGroupOverlay())
 | 
			
		||||
 *
 | 
			
		||||
 * @type BulkEditOverlay
 | 
			
		||||
 */
 | 
			
		||||
let bulkEditOverlayInstance = null;
 | 
			
		||||
 | 
			
		||||
class BulkEditOverlay {
 | 
			
		||||
    static containerId = 'rm_print_characters_block';
 | 
			
		||||
    static contextMenuId = 'character_context_menu';
 | 
			
		||||
@@ -191,19 +246,23 @@ class BulkEditOverlay {
 | 
			
		||||
        return this.#stateChangeCallbacks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @returns {*[]}
 | 
			
		||||
     */
 | 
			
		||||
    get selectedCharacters() {
 | 
			
		||||
        return this.#selectedCharacters;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        if (characterGroupOverlayInstance instanceof BulkEditOverlay)
 | 
			
		||||
            return characterGroupOverlayInstance
 | 
			
		||||
        if (bulkEditOverlayInstance instanceof BulkEditOverlay)
 | 
			
		||||
            return bulkEditOverlayInstance
 | 
			
		||||
 | 
			
		||||
        this.container = document.getElementById(BulkEditOverlay.containerId);
 | 
			
		||||
        this.container.addEventListener('click', this.handleCancelClick);
 | 
			
		||||
 | 
			
		||||
        eventSource.on(event_types.CHARACTER_GROUP_OVERLAY_STATE_CHANGE_AFTER, this.handleStateChange);
 | 
			
		||||
        characterGroupOverlayInstance = Object.freeze(this);
 | 
			
		||||
        bulkEditOverlayInstance = Object.freeze(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    browseState = () => this.state = CharacterGroupOverlayState.browse;
 | 
			
		||||
@@ -349,6 +408,10 @@ class BulkEditOverlay {
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleContextMenuTag = () => {
 | 
			
		||||
        CharacterContextMenu.tag(this.selectedCharacters);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addStateChangeCallback = callback => this.stateChangeCallbacks.push(callback);
 | 
			
		||||
 | 
			
		||||
    selectCharacter = characterId => this.selectedCharacters.push(String(characterId));
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user