mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-02 10:57:45 +01:00
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">
|
<h4 data-i18n="Character Handling">
|
||||||
Character Handling
|
Character Handling
|
||||||
</h4>
|
</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>
|
<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="Character Version" value="character_version">Character Version</option>
|
||||||
<option data-i18n="Created by" value="creator">Created by</option>
|
<option data-i18n="Created by" value="creator">Created by</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</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">
|
<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" />
|
<input id="fuzzy_search_checkbox" type="checkbox" />
|
||||||
<small data-i18n="Advanced Character Search">Advanced Character Search</small>
|
<small data-i18n="Advanced Character Search">Advanced Character Search</small>
|
||||||
@ -3950,10 +3959,6 @@
|
|||||||
<input id="show_card_avatar_urls" type="checkbox" />
|
<input id="show_card_avatar_urls" type="checkbox" />
|
||||||
<small data-i18n="Show avatar filenames">Show avatar filenames</small>
|
<small data-i18n="Show avatar filenames">Show avatar filenames</small>
|
||||||
</label>
|
</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">
|
<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" />
|
<input id="spoiler_free_mode" type="checkbox" />
|
||||||
<small data-i18n="Spoiler Free Mode">Spoiler Free Mode</small>
|
<small data-i18n="Spoiler Free Mode">Spoiler Free Mode</small>
|
||||||
|
@ -175,11 +175,12 @@ import {
|
|||||||
createTagMapFromList,
|
createTagMapFromList,
|
||||||
renameTagKey,
|
renameTagKey,
|
||||||
importTags,
|
importTags,
|
||||||
tag_filter_types,
|
tag_filter_type,
|
||||||
compareTagsForSort,
|
compareTagsForSort,
|
||||||
initTags,
|
initTags,
|
||||||
applyTagsOnCharacterSelect,
|
applyTagsOnCharacterSelect,
|
||||||
applyTagsOnGroupSelect,
|
applyTagsOnGroupSelect,
|
||||||
|
tag_import_setting,
|
||||||
} from './scripts/tags.js';
|
} from './scripts/tags.js';
|
||||||
import {
|
import {
|
||||||
SECRET_KEYS,
|
SECRET_KEYS,
|
||||||
@ -1346,8 +1347,8 @@ export async function printCharacters(fullRefresh = false) {
|
|||||||
verifyCharactersSearchSortRule();
|
verifyCharactersSearchSortRule();
|
||||||
|
|
||||||
// We are actually always reprinting filters, as it "doesn't hurt", and this way they are always up to date
|
// 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_type.character);
|
||||||
printTagFilters(tag_filter_types.group_member);
|
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
|
// We are also always reprinting the lists on character/group edit window, as these ones doesn't get updated otherwise
|
||||||
applyTagsOnCharacterSelect();
|
applyTagsOnCharacterSelect();
|
||||||
@ -8474,7 +8475,7 @@ async function importCharacter(file, preserveFileName = false) {
|
|||||||
|
|
||||||
await getCharacters();
|
await getCharacters();
|
||||||
select_rm_info('char_import', data.file_name, oldSelectedChar);
|
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 currentContext = getContext();
|
||||||
let avatarFileName = `${data.file_name}.png`;
|
let avatarFileName = `${data.file_name}.png`;
|
||||||
let importedCharacter = currentContext.characters.find(character => character.avatar === avatarFileName);
|
let importedCharacter = currentContext.characters.find(character => character.avatar === avatarFileName);
|
||||||
@ -10609,7 +10610,7 @@ jQuery(async function () {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case 'import_tags': {
|
case 'import_tags': {
|
||||||
await importTags(characters[this_chid]);
|
await importTags(characters[this_chid], { forceShow: true });
|
||||||
} break;
|
} break;
|
||||||
/*case 'delete_button':
|
/*case 'delete_button':
|
||||||
popup_type = "del_ch";
|
popup_type = "del_ch";
|
||||||
|
@ -28,6 +28,8 @@ export const POPUP_RESULT = {
|
|||||||
* @property {boolean?} [allowVerticalScrolling] - Whether to allow vertical scrolling in the popup
|
* @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 {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 {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 {POPUP_RESULT|number?} */ defaultResult;
|
||||||
/** @type {CustomPopupButton[]|string[]?} */ customButtons;
|
/** @type {CustomPopupButton[]|string[]?} */ customButtons;
|
||||||
|
|
||||||
|
/** @type {(popup: Popup) => boolean?} */ onClosing;
|
||||||
|
/** @type {(popup: Popup) => void?} */ onClose;
|
||||||
|
|
||||||
/** @type {POPUP_RESULT|number} */ result;
|
/** @type {POPUP_RESULT|number} */ result;
|
||||||
/** @type {any} */ value;
|
/** @type {any} */ value;
|
||||||
|
|
||||||
@ -94,13 +99,17 @@ export class Popup {
|
|||||||
* @param {string} [inputValue=''] - The initial value of the input field
|
* @param {string} [inputValue=''] - The initial value of the input field
|
||||||
* @param {PopupOptions} [options={}] - Additional options for the popup
|
* @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);
|
Popup.util.popups.push(this);
|
||||||
|
|
||||||
// Make this popup uniquely identifiable
|
// Make this popup uniquely identifiable
|
||||||
this.id = uuidv4();
|
this.id = uuidv4();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
||||||
|
// Utilize event handlers being passed in
|
||||||
|
this.onClosing = onClosing;
|
||||||
|
this.onClose = onClose;
|
||||||
|
|
||||||
/**@type {HTMLTemplateElement}*/
|
/**@type {HTMLTemplateElement}*/
|
||||||
const template = document.querySelector('#popup_template');
|
const template = document.querySelector('#popup_template');
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -317,6 +326,12 @@ export class Popup {
|
|||||||
|
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
|
|
||||||
|
if (this.onClosing) {
|
||||||
|
const shouldClose = this.onClosing(this);
|
||||||
|
if (!shouldClose) return;
|
||||||
|
}
|
||||||
|
|
||||||
Popup.util.lastResult = { value, result };
|
Popup.util.lastResult = { value, result };
|
||||||
this.hide();
|
this.hide();
|
||||||
}
|
}
|
||||||
@ -337,6 +352,11 @@ export class Popup {
|
|||||||
// Call the close on the dialog
|
// Call the close on the dialog
|
||||||
this.dlg.close();
|
this.dlg.close();
|
||||||
|
|
||||||
|
// Run a possible custom handler right before DOM removal
|
||||||
|
if (this.onClose) {
|
||||||
|
this.onClose(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove it from the dom
|
// Remove it from the dom
|
||||||
this.dlg.remove();
|
this.dlg.remove();
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ import {
|
|||||||
selectInstructPreset,
|
selectInstructPreset,
|
||||||
} from './instruct-mode.js';
|
} 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 { tokenizers } from './tokenizers.js';
|
||||||
import { BIAS_CACHE } from './logit-bias.js';
|
import { BIAS_CACHE } from './logit-bias.js';
|
||||||
import { renderTemplateAsync } from './templates.js';
|
import { renderTemplateAsync } from './templates.js';
|
||||||
@ -198,6 +198,7 @@ let power_user = {
|
|||||||
trim_spaces: true,
|
trim_spaces: true,
|
||||||
relaxed_api_urls: false,
|
relaxed_api_urls: false,
|
||||||
world_import_dialog: true,
|
world_import_dialog: true,
|
||||||
|
tag_import_setting: tag_import_setting.ASK,
|
||||||
disable_group_trimming: false,
|
disable_group_trimming: false,
|
||||||
single_line: false,
|
single_line: false,
|
||||||
|
|
||||||
@ -1562,6 +1563,12 @@ function loadPowerUserSettings(settings, data) {
|
|||||||
power_user.tokenizer = tokenizers.GPT2;
|
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);
|
$('#single_line').prop('checked', power_user.single_line);
|
||||||
$('#relaxed_api_urls').prop('checked', power_user.relaxed_api_urls);
|
$('#relaxed_api_urls').prop('checked', power_user.relaxed_api_urls);
|
||||||
$('#world_import_dialog').prop('checked', power_user.world_import_dialog);
|
$('#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);
|
$('#zoomed_avatar_magnification').prop('checked', power_user.zoomed_avatar_magnification);
|
||||||
$(`#tokenizer option[value="${power_user.tokenizer}"]`).attr('selected', true);
|
$(`#tokenizer option[value="${power_user.tokenizer}"]`).attr('selected', true);
|
||||||
$(`#send_on_enter option[value=${power_user.send_on_enter}]`).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);
|
$('#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);
|
$('#spoiler_free_mode').prop('checked', power_user.spoiler_free_mode);
|
||||||
$('#collapse-newlines-checkbox').prop('checked', power_user.collapse_newlines);
|
$('#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);
|
$('#chat_width_slider').val(power_user.chat_width);
|
||||||
$('#token_padding').val(power_user.token_padding);
|
$('#token_padding').val(power_user.token_padding);
|
||||||
$('#aux_field').val(power_user.aux_field);
|
$('#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_autocomplete_autoHide').prop('checked', power_user.stscript.autocomplete.autoHide ?? false).trigger('input');
|
||||||
$('#stscript_matching').val(power_user.stscript.matching ?? 'fuzzy');
|
$('#stscript_matching').val(power_user.stscript.matching ?? 'fuzzy');
|
||||||
@ -3516,11 +3523,6 @@ $(document).ready(() => {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#import_card_tags').on('input', function () {
|
|
||||||
power_user.import_card_tags = !!$(this).prop('checked');
|
|
||||||
saveSettingsDebounced();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#confirm_message_delete').on('input', function () {
|
$('#confirm_message_delete').on('input', function () {
|
||||||
power_user.confirm_message_delete = !!$(this).prop('checked');
|
power_user.confirm_message_delete = !!$(this).prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
@ -3759,6 +3761,12 @@ $(document).ready(() => {
|
|||||||
saveSettingsDebounced();
|
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 () {
|
$('#stscript_autocomplete_autoHide').on('input', function () {
|
||||||
power_user.stscript.autocomplete.autoHide = !!$(this).prop('checked');
|
power_user.stscript.autocomplete.autoHide = !!$(this).prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
@ -2,7 +2,6 @@ import {
|
|||||||
characters,
|
characters,
|
||||||
saveSettingsDebounced,
|
saveSettingsDebounced,
|
||||||
this_chid,
|
this_chid,
|
||||||
callPopup,
|
|
||||||
menu_type,
|
menu_type,
|
||||||
entitiesFilter,
|
entitiesFilter,
|
||||||
printCharactersDebounced,
|
printCharactersDebounced,
|
||||||
@ -21,11 +20,12 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
|||||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||||
import { isMobile } from './RossAscends-mods.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 { debounce_timeout } from './constants.js';
|
||||||
import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
|
import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
|
||||||
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||||
import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js';
|
import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js';
|
||||||
|
import { renderTemplateAsync } from './templates.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
TAG_FOLDER_TYPES,
|
TAG_FOLDER_TYPES,
|
||||||
@ -62,11 +62,20 @@ function getFilterHelper(listSelector) {
|
|||||||
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
|
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tag_filter_types = {
|
/** @enum {number} */
|
||||||
|
export const tag_filter_type = {
|
||||||
character: 0,
|
character: 0,
|
||||||
group_member: 1,
|
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 }}
|
* @type {{ FAV: Tag, GROUP: Tag, FOLDER: Tag, VIEW: Tag, HINT: Tag, UNFILTER: Tag }}
|
||||||
* A collection of global actional tags for the filter panel
|
* 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
|
* @returns {boolean} If currently viewing a folder
|
||||||
*/
|
*/
|
||||||
function isBogusFolderOpen() {
|
function isBogusFolderOpen() {
|
||||||
const anyIsFolder = entitiesFilter.getFilterData(FILTER_TYPES.TAG)?.selected
|
return getOpenBogusFolders().length > 0;
|
||||||
.map(tagId => tags.find(x => x.id === tagId))
|
|
||||||
.some(isBogusFolder);
|
|
||||||
|
|
||||||
return !!anyIsFolder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -662,15 +678,6 @@ function getExistingTags(newTags) {
|
|||||||
return existingTags;
|
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 IMPORT_EXLCUDED_TAGS = ['ROOT', 'TAVERN'];
|
||||||
const ANTI_TROLL_MAX_TAGS = 15;
|
const ANTI_TROLL_MAX_TAGS = 15;
|
||||||
|
|
||||||
@ -678,11 +685,13 @@ const ANTI_TROLL_MAX_TAGS = 15;
|
|||||||
* Imports tags for a given character
|
* Imports tags for a given character
|
||||||
*
|
*
|
||||||
* @param {Character} character - The 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
|
* @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
|
// Gather the tags to import based on the selected setting
|
||||||
const tagNamesToImport = await handleTagImport(character);
|
const tagNamesToImport = await handleTagImport(character, { forceShow });
|
||||||
if (!tagNamesToImport?.length) {
|
if (!tagNamesToImport?.length) {
|
||||||
toastr.info('No tags imported', 'Importing Tags');
|
toastr.info('No tags imported', 'Importing Tags');
|
||||||
return;
|
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
|
* Handles the import of tags for a given character and returns the resulting list of tags to add
|
||||||
*
|
*
|
||||||
* @param {Character} character - The character
|
* @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
|
* @returns {Promise<string[]>} Array of strings representing the tags to import
|
||||||
*/
|
*/
|
||||||
async function handleTagImport(character) {
|
async function handleTagImport(character, { forceShow = false } = {}) {
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
const importTags = character.tags.map(t => t.trim()).filter(t => t)
|
const importTags = character.tags.map(t => t.trim()).filter(t => t)
|
||||||
.filter(t => !IMPORT_EXLCUDED_TAGS.includes(t))
|
.filter(t => !IMPORT_EXLCUDED_TAGS.includes(t))
|
||||||
@ -710,17 +721,22 @@ async function handleTagImport(character) {
|
|||||||
const existingTags = getExistingTags(importTags);
|
const existingTags = getExistingTags(importTags);
|
||||||
const newTags = importTags.filter(t => !existingTags.some(existingTag => existingTag.name.toLowerCase() === t.toLowerCase()))
|
const newTags = importTags.filter(t => !existingTags.some(existingTag => existingTag.name.toLowerCase() === t.toLowerCase()))
|
||||||
.map(newTag);
|
.map(newTag);
|
||||||
|
const folderTags = getOpenBogusFolders();
|
||||||
|
|
||||||
switch (globalTagImportSetting) {
|
// Choose the setting for this dialog. If from settings, verify the setting really exists, otherwise take "ASK".
|
||||||
case tagImportSettings.ALWAYS_IMPORT_ALL:
|
const setting = forceShow ? tag_import_setting.ASK
|
||||||
return existingTags.concat(newTags).map(t => t.name);
|
: Object.values(tag_import_setting).find(setting => setting === power_user.tag_import_setting) ?? tag_import_setting.ASK;
|
||||||
case tagImportSettings.ONLY_IMPORT_EXISTING:
|
|
||||||
return existingTags.map(t => t.name);
|
switch (setting) {
|
||||||
case tagImportSettings.ASK:
|
case tag_import_setting.ALL:
|
||||||
return await showTagImportPopup(character, existingTags, newTags);
|
return [...existingTags, ...newTags, ...folderTags].map(t => t.name);
|
||||||
case tagImportSettings.IMPORT_NONE:
|
case tag_import_setting.ONLY_EXISTING:
|
||||||
default:
|
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 [];
|
return [];
|
||||||
|
default: throw new Error(`Invalid tag import setting: ${setting}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,63 +746,55 @@ async function handleTagImport(character) {
|
|||||||
* @param {Character} character - The character
|
* @param {Character} character - The character
|
||||||
* @param {Tag[]} existingTags - List of existing tags
|
* @param {Tag[]} existingTags - List of existing tags
|
||||||
* @param {Tag[]} newTags - List of new 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
|
* @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}} */
|
/** @type {{[key: string]: import('./popup.js').CustomPopupButton}} */
|
||||||
const importButtons = {
|
const importButtons = {
|
||||||
EXISTING: { result: 2, text: 'Import Existing' },
|
NONE: { result: 2, text: 'Import None', },
|
||||||
ALL: { result: 3, text: 'Import All' },
|
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 popupContent = $(await renderTemplateAsync('charTagImport', { charName: character.name }));
|
||||||
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>`);
|
|
||||||
|
|
||||||
// Print tags after popup is shown, so that events can be added
|
// 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_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_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) {
|
if (!result) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 1:
|
case POPUP_RESULT.AFFIRMATIVE: // Default 'Import' option where it imports all selected
|
||||||
case true:
|
case importButtons.ALL.result:
|
||||||
case importButtons.ALL.result: // Default 'Import' option where it imports all selected
|
return [...existingTags, ...newTags, ...folderTags].map(t => t.name);
|
||||||
return existingTags.concat(newTags).map(t => t.name);
|
|
||||||
case importButtons.EXISTING.result:
|
case importButtons.EXISTING.result:
|
||||||
return existingTags.map(t => t.name);
|
return [...existingTags, ...folderTags].map(t => t.name);
|
||||||
case importButtons.NONE.result:
|
case importButtons.NONE.result:
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
@ -1115,8 +1123,8 @@ function runTagFilters(listElement) {
|
|||||||
filterHelper.setFilterData(FILTER_TYPES.TAG, { excluded: excludedTagIds, selected: tagIds });
|
filterHelper.setFilterData(FILTER_TYPES.TAG, { excluded: excludedTagIds, selected: tagIds });
|
||||||
}
|
}
|
||||||
|
|
||||||
function printTagFilters(type = tag_filter_types.character) {
|
function printTagFilters(type = tag_filter_type.character) {
|
||||||
const FILTER_SELECTOR = type === tag_filter_types.character ? CHARACTER_FILTER_SELECTOR : GROUP_FILTER_SELECTOR;
|
const FILTER_SELECTOR = type === tag_filter_type.character ? CHARACTER_FILTER_SELECTOR : GROUP_FILTER_SELECTOR;
|
||||||
$(FILTER_SELECTOR).empty();
|
$(FILTER_SELECTOR).empty();
|
||||||
|
|
||||||
// Print all action tags. (Rework 'Folder' button to some kind of onboarding if no folders are enabled yet)
|
// 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');
|
const bogusDrilldown = $(FILTER_SELECTOR).siblings('.rm_tag_bogus_drilldown');
|
||||||
bogusDrilldown.empty();
|
bogusDrilldown.empty();
|
||||||
if (power_user.bogus_folders && bogusDrilldown.length > 0) {
|
if (power_user.bogus_folders && bogusDrilldown.length > 0) {
|
||||||
const filterData = structuredClone(entitiesFilter.getFilterData(FILTER_TYPES.TAG));
|
const navigatedTags = getOpenBogusFolders();
|
||||||
const navigatedTags = filterData.selected.map(x => tags.find(t => t.id == x)).filter(x => isBogusFolder(x));
|
|
||||||
|
|
||||||
printTagList(bogusDrilldown, { tags: navigatedTags, tagOptions: { removable: true } });
|
printTagList(bogusDrilldown, { tags: navigatedTags, tagOptions: { removable: true } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
public/scripts/templates/charTagImport.html
Normal file
35
public/scripts/templates/charTagImport.html
Normal file
@ -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…
x
Reference in New Issue
Block a user