Merge pull request #2405 from SillyTavern/tag-import-setting
Tag import setting
This commit is contained in:
commit
0f92c90b71
|
@ -3923,13 +3923,22 @@
|
|||
<h4 data-i18n="Character Handling">
|
||||
Character Handling
|
||||
</h4>
|
||||
<div title="If set in the advanced character definitions, this field will be displayed in the characters list." data-i18n="[title]If set in the advanced character definitions, this field will be displayed in the characters list.">
|
||||
<div class="flex-container alignitemscenter" title="If set in the advanced character definitions, this field will be displayed in the characters list." data-i18n="[title]If set in the advanced character definitions, this field will be displayed in the characters list.">
|
||||
<label for="aux_field"><small data-i18n="Char List Subheader">Char List Subheader</small></label>
|
||||
<select id="aux_field">
|
||||
<select id="aux_field" class="widthNatural flex1 margin0">
|
||||
<option data-i18n="Character Version" value="character_version">Character Version</option>
|
||||
<option data-i18n="Created by" value="creator">Created by</option>
|
||||
</select>
|
||||
</div>
|
||||
<div data-newbie-hidden class="flex-container alignitemscenter" title="Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog." data-i18n="[title]Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.">
|
||||
<label for="tag_import_setting"><small data-i18n="Import Card Tags">Import Card Tags</small></label>
|
||||
<select id="tag_import_setting" class="widthNatural flex1 margin0">
|
||||
<option data-i18n="Ask" value="1">Ask</option>
|
||||
<option data-i18n="None" value="2">None</option>
|
||||
<option data-i18n="All" value="3">All</option>
|
||||
<option data-i18n="Existing" value="4">Existing</option>
|
||||
</select>
|
||||
</div>
|
||||
<label data-newbie-hidden class="checkbox_label" for="fuzzy_search_checkbox" title="Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring." data-i18n="[title]Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring">
|
||||
<input id="fuzzy_search_checkbox" type="checkbox" />
|
||||
<small data-i18n="Advanced Character Search">Advanced Character Search</small>
|
||||
|
@ -3950,10 +3959,6 @@
|
|||
<input id="show_card_avatar_urls" type="checkbox" />
|
||||
<small data-i18n="Show avatar filenames">Show avatar filenames</small>
|
||||
</label>
|
||||
<label data-newbie-hidden class="checkbox_label" for="import_card_tags" title="Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored." data-i18n="[title]Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored">
|
||||
<input id="import_card_tags" type="checkbox" />
|
||||
<small data-i18n="Import Card Tags">Import Card Tags</small>
|
||||
</label>
|
||||
<label data-newbie-hidden class="checkbox_label" for="spoiler_free_mode" title="Hide character definitions from the editor panel behind a spoiler button." data-i18n="[title]Hide character definitions from the editor panel behind a spoiler button">
|
||||
<input id="spoiler_free_mode" type="checkbox" />
|
||||
<small data-i18n="Spoiler Free Mode">Spoiler Free Mode</small>
|
||||
|
|
|
@ -175,11 +175,12 @@ import {
|
|||
createTagMapFromList,
|
||||
renameTagKey,
|
||||
importTags,
|
||||
tag_filter_types,
|
||||
tag_filter_type,
|
||||
compareTagsForSort,
|
||||
initTags,
|
||||
applyTagsOnCharacterSelect,
|
||||
applyTagsOnGroupSelect,
|
||||
tag_import_setting,
|
||||
} from './scripts/tags.js';
|
||||
import {
|
||||
SECRET_KEYS,
|
||||
|
@ -1346,8 +1347,8 @@ export async function printCharacters(fullRefresh = false) {
|
|||
verifyCharactersSearchSortRule();
|
||||
|
||||
// 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);
|
||||
printTagFilters(tag_filter_type.character);
|
||||
printTagFilters(tag_filter_type.group_member);
|
||||
|
||||
// We are also always reprinting the lists on character/group edit window, as these ones doesn't get updated otherwise
|
||||
applyTagsOnCharacterSelect();
|
||||
|
@ -8474,7 +8475,7 @@ async function importCharacter(file, preserveFileName = false) {
|
|||
|
||||
await getCharacters();
|
||||
select_rm_info('char_import', data.file_name, oldSelectedChar);
|
||||
if (power_user.import_card_tags) {
|
||||
if (power_user.tag_import_setting !== tag_import_setting.NONE) {
|
||||
let currentContext = getContext();
|
||||
let avatarFileName = `${data.file_name}.png`;
|
||||
let importedCharacter = currentContext.characters.find(character => character.avatar === avatarFileName);
|
||||
|
@ -10609,7 +10610,7 @@ jQuery(async function () {
|
|||
}
|
||||
} break;
|
||||
case 'import_tags': {
|
||||
await importTags(characters[this_chid]);
|
||||
await importTags(characters[this_chid], { forceShow: true });
|
||||
} break;
|
||||
/*case 'delete_button':
|
||||
popup_type = "del_ch";
|
||||
|
|
|
@ -28,6 +28,8 @@ export const POPUP_RESULT = {
|
|||
* @property {boolean?} [allowVerticalScrolling] - Whether to allow vertical scrolling in the popup
|
||||
* @property {POPUP_RESULT|number?} [defaultResult] - The default result of this popup when Enter is pressed. Can be changed from `POPUP_RESULT.AFFIRMATIVE`.
|
||||
* @property {CustomPopupButton[]|string[]?} [customButtons] - Custom buttons to add to the popup. If only strings are provided, the buttons will be added with default options, and their result will be in order from `2` onward.
|
||||
* @property {(popup: Popup) => boolean?} [onClosing] - Handler called before the popup closes, return `false` to cancel the close
|
||||
* @property {(popup: Popup) => void?} [onClose] - Handler called after the popup closes, but before the DOM is cleaned up
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -78,6 +80,9 @@ export class Popup {
|
|||
/** @type {POPUP_RESULT|number?} */ defaultResult;
|
||||
/** @type {CustomPopupButton[]|string[]?} */ customButtons;
|
||||
|
||||
/** @type {(popup: Popup) => boolean?} */ onClosing;
|
||||
/** @type {(popup: Popup) => void?} */ onClose;
|
||||
|
||||
/** @type {POPUP_RESULT|number} */ result;
|
||||
/** @type {any} */ value;
|
||||
|
||||
|
@ -94,13 +99,17 @@ export class Popup {
|
|||
* @param {string} [inputValue=''] - The initial value of the input field
|
||||
* @param {PopupOptions} [options={}] - Additional options for the popup
|
||||
*/
|
||||
constructor(content, type, inputValue = '', { okButton = null, cancelButton = null, rows = 1, wide = false, wider = false, large = false, allowHorizontalScrolling = false, allowVerticalScrolling = false, defaultResult = POPUP_RESULT.AFFIRMATIVE, customButtons = null } = {}) {
|
||||
constructor(content, type, inputValue = '', { okButton = null, cancelButton = null, rows = 1, wide = false, wider = false, large = false, allowHorizontalScrolling = false, allowVerticalScrolling = false, defaultResult = POPUP_RESULT.AFFIRMATIVE, customButtons = null, onClosing = null, onClose = null } = {}) {
|
||||
Popup.util.popups.push(this);
|
||||
|
||||
// Make this popup uniquely identifiable
|
||||
this.id = uuidv4();
|
||||
this.type = type;
|
||||
|
||||
// Utilize event handlers being passed in
|
||||
this.onClosing = onClosing;
|
||||
this.onClose = onClose;
|
||||
|
||||
/**@type {HTMLTemplateElement}*/
|
||||
const template = document.querySelector('#popup_template');
|
||||
// @ts-ignore
|
||||
|
@ -317,6 +326,12 @@ export class Popup {
|
|||
|
||||
this.value = value;
|
||||
this.result = result;
|
||||
|
||||
if (this.onClosing) {
|
||||
const shouldClose = this.onClosing(this);
|
||||
if (!shouldClose) return;
|
||||
}
|
||||
|
||||
Popup.util.lastResult = { value, result };
|
||||
this.hide();
|
||||
}
|
||||
|
@ -337,6 +352,11 @@ export class Popup {
|
|||
// Call the close on the dialog
|
||||
this.dlg.close();
|
||||
|
||||
// Run a possible custom handler right before DOM removal
|
||||
if (this.onClose) {
|
||||
this.onClose(this);
|
||||
}
|
||||
|
||||
// Remove it from the dom
|
||||
this.dlg.remove();
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ import {
|
|||
selectInstructPreset,
|
||||
} from './instruct-mode.js';
|
||||
|
||||
import { getTagsList, tag_map, tags } from './tags.js';
|
||||
import { getTagsList, tag_import_setting, tag_map, tags } from './tags.js';
|
||||
import { tokenizers } from './tokenizers.js';
|
||||
import { BIAS_CACHE } from './logit-bias.js';
|
||||
import { renderTemplateAsync } from './templates.js';
|
||||
|
@ -198,6 +198,7 @@ let power_user = {
|
|||
trim_spaces: true,
|
||||
relaxed_api_urls: false,
|
||||
world_import_dialog: true,
|
||||
tag_import_setting: tag_import_setting.ASK,
|
||||
disable_group_trimming: false,
|
||||
single_line: false,
|
||||
|
||||
|
@ -1562,6 +1563,12 @@ function loadPowerUserSettings(settings, data) {
|
|||
power_user.tokenizer = tokenizers.GPT2;
|
||||
}
|
||||
|
||||
// Clean up old/legacy settings
|
||||
if (power_user.import_card_tags !== undefined) {
|
||||
power_user.tag_import_setting = power_user.import_card_tags ? tag_import_setting.ASK : tag_import_setting.NONE;
|
||||
delete power_user.import_card_tags;
|
||||
}
|
||||
|
||||
$('#single_line').prop('checked', power_user.single_line);
|
||||
$('#relaxed_api_urls').prop('checked', power_user.relaxed_api_urls);
|
||||
$('#world_import_dialog').prop('checked', power_user.world_import_dialog);
|
||||
|
@ -1590,7 +1597,6 @@ function loadPowerUserSettings(settings, data) {
|
|||
$('#zoomed_avatar_magnification').prop('checked', power_user.zoomed_avatar_magnification);
|
||||
$(`#tokenizer option[value="${power_user.tokenizer}"]`).attr('selected', true);
|
||||
$(`#send_on_enter option[value=${power_user.send_on_enter}]`).attr('selected', true);
|
||||
$('#import_card_tags').prop('checked', power_user.import_card_tags);
|
||||
$('#confirm_message_delete').prop('checked', power_user.confirm_message_delete !== undefined ? !!power_user.confirm_message_delete : true);
|
||||
$('#spoiler_free_mode').prop('checked', power_user.spoiler_free_mode);
|
||||
$('#collapse-newlines-checkbox').prop('checked', power_user.collapse_newlines);
|
||||
|
@ -1632,6 +1638,7 @@ function loadPowerUserSettings(settings, data) {
|
|||
$('#chat_width_slider').val(power_user.chat_width);
|
||||
$('#token_padding').val(power_user.token_padding);
|
||||
$('#aux_field').val(power_user.aux_field);
|
||||
$('#tag_import_setting').val(power_user.tag_import_setting);
|
||||
|
||||
$('#stscript_autocomplete_autoHide').prop('checked', power_user.stscript.autocomplete.autoHide ?? false).trigger('input');
|
||||
$('#stscript_matching').val(power_user.stscript.matching ?? 'fuzzy');
|
||||
|
@ -3516,11 +3523,6 @@ $(document).ready(() => {
|
|||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#import_card_tags').on('input', function () {
|
||||
power_user.import_card_tags = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#confirm_message_delete').on('input', function () {
|
||||
power_user.confirm_message_delete = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
|
@ -3759,6 +3761,12 @@ $(document).ready(() => {
|
|||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#tag_import_setting').on('change', function () {
|
||||
const value = $(this).find(':selected').val();
|
||||
power_user.tag_import_setting = Number(value);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#stscript_autocomplete_autoHide').on('input', function () {
|
||||
power_user.stscript.autocomplete.autoHide = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
|
|
|
@ -2,7 +2,6 @@ import {
|
|||
characters,
|
||||
saveSettingsDebounced,
|
||||
this_chid,
|
||||
callPopup,
|
||||
menu_type,
|
||||
entitiesFilter,
|
||||
printCharactersDebounced,
|
||||
|
@ -21,11 +20,12 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
|||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||
import { isMobile } from './RossAscends-mods.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
|
||||
import { debounce_timeout } from './constants.js';
|
||||
import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
|
||||
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js';
|
||||
import { renderTemplateAsync } from './templates.js';
|
||||
|
||||
export {
|
||||
TAG_FOLDER_TYPES,
|
||||
|
@ -62,11 +62,20 @@ function getFilterHelper(listSelector) {
|
|||
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
|
||||
}
|
||||
|
||||
export const tag_filter_types = {
|
||||
/** @enum {number} */
|
||||
export const tag_filter_type = {
|
||||
character: 0,
|
||||
group_member: 1,
|
||||
};
|
||||
|
||||
/** @enum {number} */
|
||||
export const tag_import_setting = {
|
||||
ASK: 1,
|
||||
NONE: 2,
|
||||
ALL: 3,
|
||||
ONLY_EXISTING: 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {{ FAV: Tag, GROUP: Tag, FOLDER: Tag, VIEW: Tag, HINT: Tag, UNFILTER: Tag }}
|
||||
* A collection of global actional tags for the filter panel
|
||||
|
@ -242,16 +251,23 @@ function isBogusFolder(tag) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a user is currently in a bogus folder.
|
||||
* Retrieves all currently open bogus folders
|
||||
*
|
||||
* @return {Tag[]} An array of open bogus folders
|
||||
*/
|
||||
function getOpenBogusFolders() {
|
||||
return entitiesFilter.getFilterData(FILTER_TYPES.TAG)?.selected
|
||||
.map(tagId => tags.find(x => x.id === tagId))
|
||||
.filter(isBogusFolder) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a user is currently in a bogus folder
|
||||
*
|
||||
* @returns {boolean} If currently viewing a folder
|
||||
*/
|
||||
function isBogusFolderOpen() {
|
||||
const anyIsFolder = entitiesFilter.getFilterData(FILTER_TYPES.TAG)?.selected
|
||||
.map(tagId => tags.find(x => x.id === tagId))
|
||||
.some(isBogusFolder);
|
||||
|
||||
return !!anyIsFolder;
|
||||
return getOpenBogusFolders().length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -662,15 +678,6 @@ function getExistingTags(newTags) {
|
|||
return existingTags;
|
||||
}
|
||||
|
||||
const tagImportSettings = {
|
||||
ALWAYS_IMPORT_ALL: 1,
|
||||
ONLY_IMPORT_EXISTING: 2,
|
||||
IMPORT_NONE: 3,
|
||||
ASK: 4,
|
||||
};
|
||||
|
||||
let globalTagImportSetting = tagImportSettings.ASK; // Default setting
|
||||
|
||||
const IMPORT_EXLCUDED_TAGS = ['ROOT', 'TAVERN'];
|
||||
const ANTI_TROLL_MAX_TAGS = 15;
|
||||
|
||||
|
@ -678,11 +685,13 @@ const ANTI_TROLL_MAX_TAGS = 15;
|
|||
* Imports tags for a given character
|
||||
*
|
||||
* @param {Character} character - The character
|
||||
* @param {object} [options] - Options
|
||||
* @param {boolean} [options.forceShow=false] - Whether to force showing the import dialog
|
||||
* @returns {Promise<boolean>} Boolean indicating whether any tag was imported
|
||||
*/
|
||||
async function importTags(character) {
|
||||
async function importTags(character, { forceShow = false } = {}) {
|
||||
// Gather the tags to import based on the selected setting
|
||||
const tagNamesToImport = await handleTagImport(character);
|
||||
const tagNamesToImport = await handleTagImport(character, { forceShow });
|
||||
if (!tagNamesToImport?.length) {
|
||||
toastr.info('No tags imported', 'Importing Tags');
|
||||
return;
|
||||
|
@ -700,9 +709,11 @@ async function importTags(character) {
|
|||
* Handles the import of tags for a given character and returns the resulting list of tags to add
|
||||
*
|
||||
* @param {Character} character - The character
|
||||
* @param {object} [options] - Options
|
||||
* @param {boolean} [options.forceShow=false] - Whether to force showing the import dialog
|
||||
* @returns {Promise<string[]>} Array of strings representing the tags to import
|
||||
*/
|
||||
async function handleTagImport(character) {
|
||||
async function handleTagImport(character, { forceShow = false } = {}) {
|
||||
/** @type {string[]} */
|
||||
const importTags = character.tags.map(t => t.trim()).filter(t => t)
|
||||
.filter(t => !IMPORT_EXLCUDED_TAGS.includes(t))
|
||||
|
@ -710,17 +721,22 @@ async function handleTagImport(character) {
|
|||
const existingTags = getExistingTags(importTags);
|
||||
const newTags = importTags.filter(t => !existingTags.some(existingTag => existingTag.name.toLowerCase() === t.toLowerCase()))
|
||||
.map(newTag);
|
||||
const folderTags = getOpenBogusFolders();
|
||||
|
||||
switch (globalTagImportSetting) {
|
||||
case tagImportSettings.ALWAYS_IMPORT_ALL:
|
||||
return existingTags.concat(newTags).map(t => t.name);
|
||||
case tagImportSettings.ONLY_IMPORT_EXISTING:
|
||||
return existingTags.map(t => t.name);
|
||||
case tagImportSettings.ASK:
|
||||
return await showTagImportPopup(character, existingTags, newTags);
|
||||
case tagImportSettings.IMPORT_NONE:
|
||||
default:
|
||||
// Choose the setting for this dialog. If from settings, verify the setting really exists, otherwise take "ASK".
|
||||
const setting = forceShow ? tag_import_setting.ASK
|
||||
: Object.values(tag_import_setting).find(setting => setting === power_user.tag_import_setting) ?? tag_import_setting.ASK;
|
||||
|
||||
switch (setting) {
|
||||
case tag_import_setting.ALL:
|
||||
return [...existingTags, ...newTags, ...folderTags].map(t => t.name);
|
||||
case tag_import_setting.ONLY_EXISTING:
|
||||
return [...existingTags, ...folderTags].map(t => t.name);
|
||||
case tag_import_setting.ASK:
|
||||
return await showTagImportPopup(character, existingTags, newTags, folderTags);
|
||||
case tag_import_setting.NONE:
|
||||
return [];
|
||||
default: throw new Error(`Invalid tag import setting: ${setting}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -730,63 +746,55 @@ async function handleTagImport(character) {
|
|||
* @param {Character} character - The character
|
||||
* @param {Tag[]} existingTags - List of existing tags
|
||||
* @param {Tag[]} newTags - List of new tags
|
||||
* @param {Tag[]} folderTags - List of tags in the current folder
|
||||
* @returns {Promise<string[]>} Array of strings representing the tags to import
|
||||
*/
|
||||
async function showTagImportPopup(character, existingTags, newTags) {
|
||||
async function showTagImportPopup(character, existingTags, newTags, folderTags) {
|
||||
/** @type {{[key: string]: import('./popup.js').CustomPopupButton}} */
|
||||
const importButtons = {
|
||||
EXISTING: { result: 2, text: 'Import Existing' },
|
||||
NONE: { result: 2, text: 'Import None', },
|
||||
ALL: { result: 3, text: 'Import All' },
|
||||
NONE: { result: 4, text: 'Import None' },
|
||||
EXISTING: { result: 4, text: 'Import Existing' },
|
||||
};
|
||||
const buttonSettingsMap = {
|
||||
[POPUP_RESULT.AFFIRMATIVE]: tag_import_setting.ASK,
|
||||
[importButtons.NONE.result]: tag_import_setting.NONE,
|
||||
[importButtons.ALL.result]: tag_import_setting.ALL,
|
||||
[importButtons.EXISTING.result]: tag_import_setting.ONLY_EXISTING,
|
||||
};
|
||||
|
||||
const customButtonsCaptions = Object.values(importButtons).map(button => `"${button.text}"`);
|
||||
const customButtonsString = customButtonsCaptions.slice(0, -1).join(', ') + ' or ' + customButtonsCaptions.slice(-1);
|
||||
|
||||
const popupContent = $(`
|
||||
<h3>Import Tags For ${character.name}</h3>
|
||||
<div class="import_avatar_placeholder"></div>
|
||||
<div class="import_tags_content justifyLeft">
|
||||
<small>
|
||||
Click remove on any tag to remove it from this import.<br />
|
||||
Select one of the import options to finish importing the tags.
|
||||
</small>
|
||||
|
||||
<h4 class="m-t-1">Existing Tags</h4>
|
||||
<div id="import_existing_tags_list" class="tags"></div>
|
||||
|
||||
<h4 class="m-t-1">New Tags</h4>
|
||||
<div id="import_new_tags_list" class="tags"></div>
|
||||
|
||||
<small>
|
||||
<label class="checkbox flex-container alignitemscenter flexNoGap m-t-3" for="import_remember_option">
|
||||
<input type="checkbox" id="import_remember_option" name="import_remember_option" />
|
||||
<span data-i18n="Remember my choice">
|
||||
Remember my choice
|
||||
<div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Remember the chosen import option\nIf ${customButtonsString} is selected, this dialog will not show up anymore.\nTo change this, go to the settings and modify "Tag Import Option".\n\nIf the "Import" option is chosen, the global setting will stay on "Ask"."
|
||||
title="Remember the chosen import option\nIf ${customButtonsString} is selected, this dialog will not show up anymore.\nTo change this, go to the settings and modify "Tag Import Option".\n\nIf the "Import" option is chosen, the global setting will stay on "Ask".">
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
</small>
|
||||
</div>`);
|
||||
const popupContent = $(await renderTemplateAsync('charTagImport', { charName: character.name }));
|
||||
|
||||
// Print tags after popup is shown, so that events can be added
|
||||
printTagList(popupContent.find('#import_existing_tags_list'), { tags: existingTags, tagOptions: { removable: true, removeAction: tag => removeFromArray(existingTags, tag) } });
|
||||
printTagList(popupContent.find('#import_new_tags_list'), { tags: newTags, tagOptions: { removable: true, removeAction: tag => removeFromArray(newTags, tag) } });
|
||||
printTagList(popupContent.find('#import_folder_tags_list'), { tags: folderTags, tagOptions: { removable: true, removeAction: tag => removeFromArray(folderTags, tag) } });
|
||||
|
||||
const result = await callGenericPopup(popupContent, POPUP_TYPE.TEXT, null, { wider: true, okButton: 'Import', cancelButton: true, customButtons: Object.values(importButtons) });
|
||||
if (folderTags.length === 0) popupContent.find('#folder_tags_block').hide();
|
||||
|
||||
function onCloseRemember(/** @type {Popup} */ popup) {
|
||||
const rememberCheckbox = document.getElementById('import_remember_option');
|
||||
if (rememberCheckbox instanceof HTMLInputElement && rememberCheckbox.checked) {
|
||||
const setting = buttonSettingsMap[popup.result];
|
||||
if (!setting) return;
|
||||
power_user.tag_import_setting = setting;
|
||||
$('#tag_import_setting').val(power_user.tag_import_setting);
|
||||
saveSettingsDebounced();
|
||||
console.log('Remembered tag import setting:', Object.entries(tag_import_setting).find(x => x[1] === setting)[0], setting);
|
||||
}
|
||||
}
|
||||
|
||||
const result = await callGenericPopup(popupContent, POPUP_TYPE.TEXT, null, { wider: true, okButton: 'Import', cancelButton: true, customButtons: Object.values(importButtons), onClose: onCloseRemember });
|
||||
if (!result) {
|
||||
return [];
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case 1:
|
||||
case true:
|
||||
case importButtons.ALL.result: // Default 'Import' option where it imports all selected
|
||||
return existingTags.concat(newTags).map(t => t.name);
|
||||
case POPUP_RESULT.AFFIRMATIVE: // Default 'Import' option where it imports all selected
|
||||
case importButtons.ALL.result:
|
||||
return [...existingTags, ...newTags, ...folderTags].map(t => t.name);
|
||||
case importButtons.EXISTING.result:
|
||||
return existingTags.map(t => t.name);
|
||||
return [...existingTags, ...folderTags].map(t => t.name);
|
||||
case importButtons.NONE.result:
|
||||
default:
|
||||
return [];
|
||||
|
@ -1115,8 +1123,8 @@ function runTagFilters(listElement) {
|
|||
filterHelper.setFilterData(FILTER_TYPES.TAG, { excluded: excludedTagIds, selected: tagIds });
|
||||
}
|
||||
|
||||
function printTagFilters(type = tag_filter_types.character) {
|
||||
const FILTER_SELECTOR = type === tag_filter_types.character ? CHARACTER_FILTER_SELECTOR : GROUP_FILTER_SELECTOR;
|
||||
function printTagFilters(type = tag_filter_type.character) {
|
||||
const FILTER_SELECTOR = type === tag_filter_type.character ? CHARACTER_FILTER_SELECTOR : GROUP_FILTER_SELECTOR;
|
||||
$(FILTER_SELECTOR).empty();
|
||||
|
||||
// Print all action tags. (Rework 'Folder' button to some kind of onboarding if no folders are enabled yet)
|
||||
|
@ -1135,9 +1143,7 @@ function printTagFilters(type = tag_filter_types.character) {
|
|||
const bogusDrilldown = $(FILTER_SELECTOR).siblings('.rm_tag_bogus_drilldown');
|
||||
bogusDrilldown.empty();
|
||||
if (power_user.bogus_folders && bogusDrilldown.length > 0) {
|
||||
const filterData = structuredClone(entitiesFilter.getFilterData(FILTER_TYPES.TAG));
|
||||
const navigatedTags = filterData.selected.map(x => tags.find(t => t.id == x)).filter(x => isBogusFolder(x));
|
||||
|
||||
const navigatedTags = getOpenBogusFolders();
|
||||
printTagList(bogusDrilldown, { tags: navigatedTags, tagOptions: { removable: true } });
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<h3>Import Tags For {{charName}}</h3>
|
||||
<div class="import_avatar_placeholder"></div>
|
||||
<div class="import_tags_content justifyLeft">
|
||||
<small data-i18n="Click remove on any tag to remove it from this import.<br />Select one of the import options to finish importing the tags.">
|
||||
Click remove on any tag to remove it from this import.<br />
|
||||
Select one of the import options to finish importing the tags.
|
||||
</small>
|
||||
|
||||
<h4 class="m-t-1" data-i18n="Existing Tags">Existing Tags</h4>
|
||||
<div id="import_existing_tags_list" class="tags" style="min-height: 20px;"></div>
|
||||
|
||||
<h4 class="m-t-1" data-i18n="New Tags">New Tags</h4>
|
||||
<div id="import_new_tags_list" class="tags" style="min-height: 20px;"></div>
|
||||
|
||||
<div id="folder_tags_block" class="m-t-1">
|
||||
<h4 data-i18n="Folder Tags">Folder Tags</h4>
|
||||
<small data-i18n="The following tags will be auto-imported based on the currently selected folders">
|
||||
The following tags will be auto-imported based on the currently selected folders
|
||||
</small>
|
||||
<div id="import_folder_tags_list" class="tags" style="margin-top: 5px;"></div>
|
||||
</div>
|
||||
|
||||
<small>
|
||||
<label class="checkbox flex-container alignitemscenter flexNoGap m-t-3" for="import_remember_option">
|
||||
<input type="checkbox" id="import_remember_option" name="import_remember_option" />
|
||||
<span data-i18n="Remember my choice">
|
||||
Remember my choice
|
||||
<div class="fa-solid fa-circle-info opacity50p"
|
||||
data-i18n="[title]Remember the chosen import option
If anything besides 'Cancel' is selected, this dialog will not show up anymore.
To change this, go to the settings and modify "Tag Import Option".

If the "Import" option is chosen, the global setting will stay on "Ask"."
|
||||
title="Remember the chosen import option
If anything besides 'Cancel' is selected, this dialog will not show up anymore.
To change this, go to the settings and modify "Tag Import Option".

If the "Import" option is chosen, the global setting will stay on "Ask".">
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
</small>
|
||||
</div>
|
Loading…
Reference in New Issue