mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Global refactor of printCharacter and filter print
- (!) Refactor character list and filter redrawing to one global debounce - Refactor all places where character list and filters where redrawn to the correct usage (hope I didn't miss any) - Automatically redraw character list on each tag bulk edit - Fix tags not being sorted in bulk edit mutual tags list - Refactor bulk tag edit class to actually be an instance object - Remember scroll position on character list redraw - unless it's a full refresh
This commit is contained in:
@ -282,6 +282,7 @@ export {
|
|||||||
mesForShowdownParse,
|
mesForShowdownParse,
|
||||||
characterGroupOverlay,
|
characterGroupOverlay,
|
||||||
printCharacters,
|
printCharacters,
|
||||||
|
printCharactersDebounced,
|
||||||
isOdd,
|
isOdd,
|
||||||
countOccurrences,
|
countOccurrences,
|
||||||
};
|
};
|
||||||
@ -498,6 +499,14 @@ const durationSaveEdit = 1000;
|
|||||||
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
|
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
|
||||||
export const saveCharacterDebounced = debounce(() => $('#create_button').trigger('click'), durationSaveEdit);
|
export const saveCharacterDebounced = debounce(() => $('#create_button').trigger('click'), durationSaveEdit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the character list in a debounced fashion without blocking, with a delay of 100 milliseconds.
|
||||||
|
* Use this function instead of a direct `printCharacters()` whenever the reprinting of the character list is not the primary focus.
|
||||||
|
*
|
||||||
|
* The printing will also always reprint all filter options of the global list, to keep them up to date.
|
||||||
|
*/
|
||||||
|
const printCharactersDebounced = debounce(() => { printCharacters(false); }, 100);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum {string} System message types
|
* @enum {string} System message types
|
||||||
*/
|
*/
|
||||||
@ -836,7 +845,7 @@ export let active_character = '';
|
|||||||
/** The tag of the active group. (Coincidentally also the id) */
|
/** The tag of the active group. (Coincidentally also the id) */
|
||||||
export let active_group = '';
|
export let active_group = '';
|
||||||
|
|
||||||
export const entitiesFilter = new FilterHelper(debounce(printCharacters, 100));
|
export const entitiesFilter = new FilterHelper(printCharactersDebounced);
|
||||||
export const personasFilter = new FilterHelper(debounce(getUserAvatars, 100));
|
export const personasFilter = new FilterHelper(debounce(getUserAvatars, 100));
|
||||||
|
|
||||||
export function getRequestHeaders() {
|
export function getRequestHeaders() {
|
||||||
@ -1275,19 +1284,31 @@ function getCharacterBlock(item, id) {
|
|||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the global character list, optionally doing a full refresh of the list
|
||||||
|
* Use this function whenever the reprinting of the character list is the primary focus, otherwise using `printCharactersDebounced` is preferred for a cleaner, non-blocking experience.
|
||||||
|
*
|
||||||
|
* The printing will also always reprint all filter options of the global list, to keep them up to date.
|
||||||
|
*
|
||||||
|
* @param {boolean} fullRefresh - If true, the list is fully refreshed and the navigation is being reset
|
||||||
|
*/
|
||||||
async function printCharacters(fullRefresh = false) {
|
async function printCharacters(fullRefresh = false) {
|
||||||
if (fullRefresh) {
|
|
||||||
saveCharactersPage = 0;
|
|
||||||
printTagFilters(tag_filter_types.character);
|
|
||||||
printTagFilters(tag_filter_types.group_member);
|
|
||||||
|
|
||||||
await delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const storageKey = 'Characters_PerPage';
|
const storageKey = 'Characters_PerPage';
|
||||||
const listId = '#rm_print_characters_block';
|
const listId = '#rm_print_characters_block';
|
||||||
const entities = getEntitiesList({ doFilter: true });
|
const entities = getEntitiesList({ doFilter: true });
|
||||||
|
|
||||||
|
let currentScrollTop = $(listId).scrollTop();
|
||||||
|
|
||||||
|
if (fullRefresh) {
|
||||||
|
saveCharactersPage = 0;
|
||||||
|
currentScrollTop = 0;
|
||||||
|
await delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are actually always reprinting filters, as it "doesn't hurt", and this way they are always up to date
|
||||||
|
printTagFilters(tag_filter_types.character);
|
||||||
|
printTagFilters(tag_filter_types.group_member);
|
||||||
|
|
||||||
$('#rm_print_characters_pagination').pagination({
|
$('#rm_print_characters_pagination').pagination({
|
||||||
dataSource: entities,
|
dataSource: entities,
|
||||||
pageSize: Number(localStorage.getItem(storageKey)) || per_page_default,
|
pageSize: Number(localStorage.getItem(storageKey)) || per_page_default,
|
||||||
@ -1340,7 +1361,7 @@ async function printCharacters(fullRefresh = false) {
|
|||||||
saveCharactersPage = e;
|
saveCharactersPage = e;
|
||||||
},
|
},
|
||||||
afterRender: function () {
|
afterRender: function () {
|
||||||
$(listId).scrollTop(0);
|
$(listId).scrollTop(currentScrollTop);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
characterGroupOverlay,
|
||||||
callPopup,
|
callPopup,
|
||||||
characters,
|
characters,
|
||||||
deleteCharacter,
|
deleteCharacter,
|
||||||
@ -9,9 +10,9 @@ import {
|
|||||||
getCharacters,
|
getCharacters,
|
||||||
getPastCharacterChats,
|
getPastCharacterChats,
|
||||||
getRequestHeaders,
|
getRequestHeaders,
|
||||||
printCharacters,
|
|
||||||
buildAvatarList,
|
buildAvatarList,
|
||||||
characterToEntity,
|
characterToEntity,
|
||||||
|
printCharactersDebounced,
|
||||||
} from '../script.js';
|
} from '../script.js';
|
||||||
|
|
||||||
import { favsToHotswap } from './RossAscends-mods.js';
|
import { favsToHotswap } from './RossAscends-mods.js';
|
||||||
@ -31,7 +32,7 @@ class CharacterContextMenu {
|
|||||||
* @param {Array<number>} selectedCharacters
|
* @param {Array<number>} selectedCharacters
|
||||||
*/
|
*/
|
||||||
static tag = (selectedCharacters) => {
|
static tag = (selectedCharacters) => {
|
||||||
BulkTagPopupHandler.show(selectedCharacters);
|
characterGroupOverlay.bulkTagPopupHandler.show(selectedCharacters);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,18 +187,36 @@ class CharacterContextMenu {
|
|||||||
* Represents a tag control not bound to a single character
|
* Represents a tag control not bound to a single character
|
||||||
*/
|
*/
|
||||||
class BulkTagPopupHandler {
|
class BulkTagPopupHandler {
|
||||||
|
/**
|
||||||
|
* The characters for this popup
|
||||||
|
* @type {number[]}
|
||||||
|
*/
|
||||||
|
characterIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A storage of the current mutual tags, as calculated by getMutualTags()
|
||||||
|
* @type {object[]}
|
||||||
|
*/
|
||||||
|
currentMutualTags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the bulk popup menu handler for the given overlay.
|
||||||
|
*
|
||||||
|
* Characters can be passed in with the show() call.
|
||||||
|
*/
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the HTML as a string that is going to be the popup for the bulk tag edit
|
* Gets the HTML as a string that is going to be the popup for the bulk tag edit
|
||||||
*
|
*
|
||||||
* @param {Array<number>} characterIds - The characters that are shown inside the popup
|
|
||||||
* @returns String containing the html for the popup
|
* @returns String containing the html for the popup
|
||||||
*/
|
*/
|
||||||
static #getHtml = (characterIds) => {
|
#getHtml = () => {
|
||||||
const characterData = JSON.stringify({ characterIds: characterIds });
|
const characterData = JSON.stringify({ characterIds: this.characterIds });
|
||||||
return `<div id="bulk_tag_shadow_popup">
|
return `<div id="bulk_tag_shadow_popup">
|
||||||
<div id="bulk_tag_popup">
|
<div id="bulk_tag_popup">
|
||||||
<div id="bulk_tag_popup_holder">
|
<div id="bulk_tag_popup_holder">
|
||||||
<h3 class="marginBot5">Modify tags of ${characterIds.length} characters</h3>
|
<h3 class="marginBot5">Modify tags of ${this.characterIds.length} characters</h3>
|
||||||
<small class="bulk_tags_desc m-b-1">Add or remove the mutual tags of all selected characters.</small>
|
<small class="bulk_tags_desc m-b-1">Add or remove the mutual tags of all selected characters.</small>
|
||||||
<div id="bulk_tags_avatars_block" class="avatars_inline avatars_inline_small tags tags_inline"></div>
|
<div id="bulk_tags_avatars_block" class="avatars_inline avatars_inline_small tags tags_inline"></div>
|
||||||
<br>
|
<br>
|
||||||
@ -227,93 +246,91 @@ class BulkTagPopupHandler {
|
|||||||
/**
|
/**
|
||||||
* Append and show the tag control
|
* Append and show the tag control
|
||||||
*
|
*
|
||||||
* @param {Array<number>} characterIds - The characters assigned to this control
|
* @param {number[]} characterIds - The characters that are shown inside the popup
|
||||||
*/
|
*/
|
||||||
static show(characterIds) {
|
show(characterIds) {
|
||||||
if (characterIds.length == 0) {
|
// shallow copy character ids persistently into this tooltip
|
||||||
|
this.characterIds = characterIds.slice();
|
||||||
|
|
||||||
|
if (this.characterIds.length == 0) {
|
||||||
console.log('No characters selected for bulk edit tags.');
|
console.log('No characters selected for bulk edit tags.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.insertAdjacentHTML('beforeend', this.#getHtml(characterIds));
|
document.body.insertAdjacentHTML('beforeend', this.#getHtml());
|
||||||
|
|
||||||
const entities = characterIds.map(id => characterToEntity(characters[id], id)).filter(entity => entity.item !== undefined);
|
const entities = this.characterIds.map(id => characterToEntity(characters[id], id)).filter(entity => entity.item !== undefined);
|
||||||
buildAvatarList($('#bulk_tags_avatars_block'), entities);
|
buildAvatarList($('#bulk_tags_avatars_block'), entities);
|
||||||
|
|
||||||
// Print the tag list with all mutuable tags, marking them as removable. That is the initial fill
|
// Print the tag list with all mutuable tags, marking them as removable. That is the initial fill
|
||||||
printTagList($('#bulkTagList'), { tags: () => this.getMutualTags(characterIds), tagOptions: { removable: true } });
|
printTagList($('#bulkTagList'), { tags: () => this.getMutualTags(), tagOptions: { removable: true } });
|
||||||
|
|
||||||
// Tag input with resolvable list for the mutual tags to get redrawn, so that newly added tags get sorted correctly
|
// Tag input with resolvable list for the mutual tags to get redrawn, so that newly added tags get sorted correctly
|
||||||
createTagInput('#bulkTagInput', '#bulkTagList', { tags: () => this.getMutualTags(characterIds), tagOptions: { removable: true }});
|
createTagInput('#bulkTagInput', '#bulkTagList', { tags: () => this.getMutualTags(), tagOptions: { removable: true }});
|
||||||
|
|
||||||
document.querySelector('#bulk_tag_popup_reset').addEventListener('click', this.resetTags.bind(this, characterIds));
|
document.querySelector('#bulk_tag_popup_reset').addEventListener('click', this.resetTags.bind(this));
|
||||||
document.querySelector('#bulk_tag_popup_remove_mutual').addEventListener('click', this.removeMutual.bind(this, characterIds));
|
document.querySelector('#bulk_tag_popup_remove_mutual').addEventListener('click', this.removeMutual.bind(this));
|
||||||
document.querySelector('#bulk_tag_popup_cancel').addEventListener('click', this.hide.bind(this));
|
document.querySelector('#bulk_tag_popup_cancel').addEventListener('click', this.hide.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a list of all tags that the provided characters have in common.
|
* Builds a list of all tags that the provided characters have in common.
|
||||||
*
|
*
|
||||||
* @param {Array<number>} characterIds - The characters to find mutual tags for
|
|
||||||
* @returns {Array<object>} A list of mutual tags
|
* @returns {Array<object>} A list of mutual tags
|
||||||
*/
|
*/
|
||||||
static getMutualTags(characterIds) {
|
getMutualTags() {
|
||||||
if (characterIds.length == 0) {
|
if (this.characterIds.length == 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (characterIds.length === 1) {
|
if (this.characterIds.length === 1) {
|
||||||
// Just use tags of the single character
|
// Just use tags of the single character
|
||||||
return getTagsList(getTagKeyForEntity(characterIds[0]));
|
return getTagsList(getTagKeyForEntity(this.characterIds[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find mutual tags for multiple characters
|
// Find mutual tags for multiple characters
|
||||||
const allTags = characterIds.map(cid => getTagsList(getTagKeyForEntity(cid)));
|
const allTags = this.characterIds.map(cid => getTagsList(getTagKeyForEntity(cid)));
|
||||||
const mutualTags = allTags.reduce((mutual, characterTags) =>
|
const mutualTags = allTags.reduce((mutual, characterTags) =>
|
||||||
mutual.filter(tag => characterTags.some(cTag => cTag.id === tag.id))
|
mutual.filter(tag => characterTags.some(cTag => cTag.id === tag.id))
|
||||||
);
|
);
|
||||||
|
|
||||||
this.mutualTags = mutualTags.sort(compareTagsForSort);
|
this.currentMutualTags = mutualTags.sort(compareTagsForSort);
|
||||||
return this.mutualTags;
|
return this.currentMutualTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide and remove the tag control
|
* Hide and remove the tag control
|
||||||
*/
|
*/
|
||||||
static hide() {
|
hide() {
|
||||||
let popupElement = document.querySelector('#bulk_tag_shadow_popup');
|
let popupElement = document.querySelector('#bulk_tag_shadow_popup');
|
||||||
if (popupElement) {
|
if (popupElement) {
|
||||||
document.body.removeChild(popupElement);
|
document.body.removeChild(popupElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
printCharacters(true);
|
// No need to redraw here, all tags actions were redrawn when they happened
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty the tag map for the given characters
|
* Empty the tag map for the given characters
|
||||||
*
|
|
||||||
* @param {Array<number>} characterIds
|
|
||||||
*/
|
*/
|
||||||
static resetTags(characterIds) {
|
resetTags() {
|
||||||
for (const characterId of characterIds) {
|
for (const characterId of this.characterIds) {
|
||||||
const key = getTagKeyForEntity(characterId);
|
const key = getTagKeyForEntity(characterId);
|
||||||
if (key) tag_map[key] = [];
|
if (key) tag_map[key] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#bulkTagList').empty();
|
$('#bulkTagList').empty();
|
||||||
|
|
||||||
printCharacters(true);
|
printCharactersDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the mutual tags for all given characters
|
* Remove the mutual tags for all given characters
|
||||||
*
|
|
||||||
* @param {Array<number>} characterIds
|
|
||||||
*/
|
*/
|
||||||
static removeMutual(characterIds) {
|
removeMutual() {
|
||||||
const mutualTags = this.getMutualTags(characterIds);
|
const mutualTags = this.getMutualTags();
|
||||||
|
|
||||||
for (const characterId of characterIds) {
|
for (const characterId of this.characterIds) {
|
||||||
for(const tag of mutualTags) {
|
for(const tag of mutualTags) {
|
||||||
removeTagFromMap(tag.id, characterId);
|
removeTagFromMap(tag.id, characterId);
|
||||||
}
|
}
|
||||||
@ -321,7 +338,7 @@ class BulkTagPopupHandler {
|
|||||||
|
|
||||||
$('#bulkTagList').empty();
|
$('#bulkTagList').empty();
|
||||||
|
|
||||||
printCharacters(true);
|
printCharactersDebounced();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,6 +381,7 @@ class BulkEditOverlay {
|
|||||||
#longPress = false;
|
#longPress = false;
|
||||||
#stateChangeCallbacks = [];
|
#stateChangeCallbacks = [];
|
||||||
#selectedCharacters = [];
|
#selectedCharacters = [];
|
||||||
|
#bulkTagPopupHandler = new BulkTagPopupHandler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {object} LastSelected - An object noting the last selected character and its state.
|
* @typedef {object} LastSelected - An object noting the last selected character and its state.
|
||||||
@ -429,6 +447,15 @@ class BulkEditOverlay {
|
|||||||
return this.#selectedCharacters;
|
return this.#selectedCharacters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The instance of the bulk tag popup handler that handles tagging of all selected characters
|
||||||
|
*
|
||||||
|
* @returns {BulkTagPopupHandler}
|
||||||
|
*/
|
||||||
|
get bulkTagPopupHandler() {
|
||||||
|
return this.#bulkTagPopupHandler;
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (bulkEditOverlayInstance instanceof BulkEditOverlay)
|
if (bulkEditOverlayInstance instanceof BulkEditOverlay)
|
||||||
return bulkEditOverlayInstance;
|
return bulkEditOverlayInstance;
|
||||||
|
@ -30,7 +30,7 @@ const toggleBulkEditMode = (isBulkEdit) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(new BulkEditOverlay()).addStateChangeCallback((state) => {
|
characterGroupOverlay.addStateChangeCallback((state) => {
|
||||||
if (state === BulkEditOverlayState.select) enableBulkEdit();
|
if (state === BulkEditOverlayState.select) enableBulkEdit();
|
||||||
if (state === BulkEditOverlayState.browse) disableBulkEdit();
|
if (state === BulkEditOverlayState.browse) disableBulkEdit();
|
||||||
});
|
});
|
||||||
@ -52,7 +52,7 @@ function onSelectAllButtonClick() {
|
|||||||
let atLeastOneSelected = false;
|
let atLeastOneSelected = false;
|
||||||
for (const character of characters) {
|
for (const character of characters) {
|
||||||
const checked = $(character).find('.bulk_select_checkbox:checked').length > 0;
|
const checked = $(character).find('.bulk_select_checkbox:checked').length > 0;
|
||||||
if (!checked) {
|
if (!checked && character instanceof HTMLElement) {
|
||||||
characterGroupOverlay.toggleSingleCharacter(character);
|
characterGroupOverlay.toggleSingleCharacter(character);
|
||||||
atLeastOneSelected = true;
|
atLeastOneSelected = true;
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ function onSelectAllButtonClick() {
|
|||||||
// If none was selected, trigger click on all to deselect all of them
|
// If none was selected, trigger click on all to deselect all of them
|
||||||
for(const character of characters) {
|
for(const character of characters) {
|
||||||
const checked = $(character).find('.bulk_select_checkbox:checked') ?? false;
|
const checked = $(character).find('.bulk_select_checkbox:checked') ?? false;
|
||||||
if (checked) {
|
if (checked && character instanceof HTMLElement) {
|
||||||
characterGroupOverlay.toggleSingleCharacter(character);
|
characterGroupOverlay.toggleSingleCharacter(character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
eventSource,
|
eventSource,
|
||||||
event_types,
|
event_types,
|
||||||
getCurrentChatId,
|
getCurrentChatId,
|
||||||
printCharacters,
|
printCharactersDebounced,
|
||||||
setCharacterId,
|
setCharacterId,
|
||||||
setEditedMessageId,
|
setEditedMessageId,
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
@ -1288,7 +1288,7 @@ async function applyTheme(name) {
|
|||||||
key: 'bogus_folders',
|
key: 'bogus_folders',
|
||||||
action: async () => {
|
action: async () => {
|
||||||
$('#bogus_folders').prop('checked', power_user.bogus_folders);
|
$('#bogus_folders').prop('checked', power_user.bogus_folders);
|
||||||
await printCharacters(true);
|
printCharactersDebounced();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -3045,7 +3045,7 @@ $(document).ready(() => {
|
|||||||
|
|
||||||
$('#show_card_avatar_urls').on('input', function () {
|
$('#show_card_avatar_urls').on('input', function () {
|
||||||
power_user.show_card_avatar_urls = !!$(this).prop('checked');
|
power_user.show_card_avatar_urls = !!$(this).prop('checked');
|
||||||
printCharacters();
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3068,7 +3068,7 @@ $(document).ready(() => {
|
|||||||
power_user.sort_field = $(this).find(':selected').data('field');
|
power_user.sort_field = $(this).find(':selected').data('field');
|
||||||
power_user.sort_order = $(this).find(':selected').data('order');
|
power_user.sort_order = $(this).find(':selected').data('order');
|
||||||
power_user.sort_rule = $(this).find(':selected').data('rule');
|
power_user.sort_rule = $(this).find(':selected').data('rule');
|
||||||
printCharacters();
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3365,15 +3365,15 @@ $(document).ready(() => {
|
|||||||
$('#bogus_folders').on('input', function () {
|
$('#bogus_folders').on('input', function () {
|
||||||
const value = !!$(this).prop('checked');
|
const value = !!$(this).prop('checked');
|
||||||
power_user.bogus_folders = value;
|
power_user.bogus_folders = value;
|
||||||
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
printCharacters(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#aux_field').on('change', function () {
|
$('#aux_field').on('change', function () {
|
||||||
const value = $(this).find(':selected').val();
|
const value = $(this).find(':selected').val();
|
||||||
power_user.aux_field = String(value);
|
power_user.aux_field = String(value);
|
||||||
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
printCharacters(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#restore_user_input').on('input', function () {
|
$('#restore_user_input').on('input', function () {
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
getCharacters,
|
getCharacters,
|
||||||
entitiesFilter,
|
entitiesFilter,
|
||||||
printCharacters,
|
printCharacters,
|
||||||
|
printCharactersDebounced,
|
||||||
buildAvatarList,
|
buildAvatarList,
|
||||||
eventSource,
|
eventSource,
|
||||||
event_types,
|
event_types,
|
||||||
@ -48,12 +49,6 @@ function getFilterHelper(listSelector) {
|
|||||||
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
|
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
const redrawCharsAndFiltersDebounced = debounce(() => {
|
|
||||||
printCharacters(false);
|
|
||||||
printTagFilters(tag_filter_types.character);
|
|
||||||
printTagFilters(tag_filter_types.group_member);
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
export const tag_filter_types = {
|
export const tag_filter_types = {
|
||||||
character: 0,
|
character: 0,
|
||||||
group_member: 1,
|
group_member: 1,
|
||||||
@ -406,10 +401,11 @@ function findTag(request, resolve, listSelector) {
|
|||||||
* @param {*} event - The event that fired on autocomplete select
|
* @param {*} event - The event that fired on autocomplete select
|
||||||
* @param {*} ui - An Object with label and value properties for the selected option
|
* @param {*} ui - An Object with label and value properties for the selected option
|
||||||
* @param {*} listSelector - The selector of the list to print/add to
|
* @param {*} listSelector - The selector of the list to print/add to
|
||||||
* @param {PrintTagListOptions} [tagListOptions] - Optional parameters for printing the tag list. Can be set to be consistent with the expected behavior of tags in the list that was defined before.
|
* @param {object} param1 - Optional parameters for this method call
|
||||||
|
* @param {PrintTagListOptions} [param1.tagListOptions] - Optional parameters for printing the tag list. Can be set to be consistent with the expected behavior of tags in the list that was defined before.
|
||||||
* @returns {boolean} <c>false</c>, to keep the input clear
|
* @returns {boolean} <c>false</c>, to keep the input clear
|
||||||
*/
|
*/
|
||||||
function selectTag(event, ui, listSelector, tagListOptions = {}) {
|
function selectTag(event, ui, listSelector, { tagListOptions = {} } = {}) {
|
||||||
let tagName = ui.item.value;
|
let tagName = ui.item.value;
|
||||||
let tag = tags.find(t => t.name === tagName);
|
let tag = tags.find(t => t.name === tagName);
|
||||||
|
|
||||||
@ -431,6 +427,7 @@ function selectTag(event, ui, listSelector, tagListOptions = {}) {
|
|||||||
addTagToMap(tag.id);
|
addTagToMap(tag.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
// We should manually add the selected tag to the print tag function, so we cover places where the tag list did not automatically include it
|
// We should manually add the selected tag to the print tag function, so we cover places where the tag list did not automatically include it
|
||||||
@ -443,9 +440,6 @@ function selectTag(event, ui, listSelector, tagListOptions = {}) {
|
|||||||
printTagList($(inlineSelector), tagListOptions);
|
printTagList($(inlineSelector), tagListOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
printTagFilters(tag_filter_types.character);
|
|
||||||
printTagFilters(tag_filter_types.group_member);
|
|
||||||
|
|
||||||
// need to return false to keep the input clear
|
// need to return false to keep the input clear
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -493,10 +487,11 @@ async function importTags(imported_char) {
|
|||||||
console.debug('added tag to map', tag, imported_char.name);
|
console.debug('added tag to map', tag, imported_char.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
|
// Await the character list, which will automatically reprint it and all tag filters
|
||||||
await getCharacters();
|
await getCharacters();
|
||||||
printTagFilters(tag_filter_types.character);
|
|
||||||
printTagFilters(tag_filter_types.group_member);
|
|
||||||
|
|
||||||
// need to return false to keep the input clear
|
// need to return false to keep the input clear
|
||||||
return false;
|
return false;
|
||||||
@ -767,8 +762,7 @@ function onTagRemoveClick(event) {
|
|||||||
|
|
||||||
$(`${getInlineListSelector()} .tag[id="${tagId}"]`).remove();
|
$(`${getInlineListSelector()} .tag[id="${tagId}"]`).remove();
|
||||||
|
|
||||||
printTagFilters(tag_filter_types.character);
|
printCharactersDebounced();
|
||||||
printTagFilters(tag_filter_types.group_member);
|
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
|
|
||||||
@ -818,7 +812,7 @@ export function createTagInput(inputSelector, listSelector, tagListOptions = {})
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
.autocomplete({
|
.autocomplete({
|
||||||
source: (i, o) => findTag(i, o, listSelector),
|
source: (i, o) => findTag(i, o, listSelector),
|
||||||
select: (e, u) => selectTag(e, u, listSelector, tagListOptions),
|
select: (e, u) => selectTag(e, u, listSelector, { tagListOptions: tagListOptions }),
|
||||||
minLength: 0,
|
minLength: 0,
|
||||||
})
|
})
|
||||||
.focus(onTagInputFocus); // <== show tag list on click
|
.focus(onTagInputFocus); // <== show tag list on click
|
||||||
@ -900,10 +894,9 @@ function makeTagListDraggable(tagContainer) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
saveSettingsDebounced();
|
|
||||||
|
|
||||||
// If the order of tags in display has changed, we need to redraw some UI elements. Do it debounced so it doesn't block and you can drag multiple tags.
|
// If the order of tags in display has changed, we need to redraw some UI elements. Do it debounced so it doesn't block and you can drag multiple tags.
|
||||||
redrawCharsAndFiltersDebounced();
|
printCharactersDebounced();
|
||||||
|
saveSettingsDebounced();
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -1003,8 +996,9 @@ async function onTagRestoreFileSelect(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$('#tag_view_restore_input').val('');
|
$('#tag_view_restore_input').val('');
|
||||||
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
printCharacters(true);
|
|
||||||
onViewTagsListClick();
|
onViewTagsListClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1029,7 +1023,8 @@ function onTagsBackupClick() {
|
|||||||
function onTagCreateClick() {
|
function onTagCreateClick() {
|
||||||
const tag = createNewTag('New Tag');
|
const tag = createNewTag('New Tag');
|
||||||
appendViewTagToList($('#tag_view_list .tag_view_list_tags'), tag, []);
|
appendViewTagToList($('#tag_view_list .tag_view_list_tags'), tag, []);
|
||||||
printCharacters(false);
|
|
||||||
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1098,7 +1093,7 @@ function onTagAsFolderClick() {
|
|||||||
updateDrawTagFolder(element, tag);
|
updateDrawTagFolder(element, tag);
|
||||||
|
|
||||||
// If folder display has changed, we have to redraw the character list, otherwise this folders state would not change
|
// If folder display has changed, we have to redraw the character list, otherwise this folders state would not change
|
||||||
printCharacters(true);
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1133,7 +1128,8 @@ function onTagDeleteClick() {
|
|||||||
tags.splice(index, 1);
|
tags.splice(index, 1);
|
||||||
$(`.tag[id="${id}"]`).remove();
|
$(`.tag[id="${id}"]`).remove();
|
||||||
$(`.tag_view_item[id="${id}"]`).remove();
|
$(`.tag_view_item[id="${id}"]`).remove();
|
||||||
printCharacters(false);
|
|
||||||
|
printCharactersDebounced();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user