mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge pull request #3915 from SillyTavern/feat/refactor-wi-init
Refactor WI init to init function for more consistent startup
This commit is contained in:
@@ -50,6 +50,7 @@ import {
|
|||||||
importWorldInfo,
|
importWorldInfo,
|
||||||
wi_anchor_position,
|
wi_anchor_position,
|
||||||
world_info_include_names,
|
world_info_include_names,
|
||||||
|
initWorldInfo,
|
||||||
} from './scripts/world-info.js';
|
} from './scripts/world-info.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -992,6 +993,7 @@ async function firstLoadInit() {
|
|||||||
initBackgrounds();
|
initBackgrounds();
|
||||||
initAuthorsNote();
|
initAuthorsNote();
|
||||||
await initPersonas();
|
await initPersonas();
|
||||||
|
initWorldInfo();
|
||||||
initRossMods();
|
initRossMods();
|
||||||
initStats();
|
initStats();
|
||||||
initCfg();
|
initCfg();
|
||||||
|
@@ -1047,7 +1047,7 @@ export function getImageSizeFromDataURL(dataUrl) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the filename of the character avatar without extension
|
* Gets the filename of the character avatar without extension
|
||||||
* @param {number?} [chid=null] - Character ID. If not provided, uses the current character ID
|
* @param {string|number?} [chid=null] - Character ID. If not provided, uses the current character ID
|
||||||
* @param {object} [options={}] - Options arguments
|
* @param {object} [options={}] - Options arguments
|
||||||
* @param {string?} [options.manualAvatarKey=null] - Manually take the following avatar key, instead of using the chid to determine the name
|
* @param {string?} [options.manualAvatarKey=null] - Manually take the following avatar key, instead of using the chid to determine the name
|
||||||
* @returns {string?} The filename of the character avatar without extension, or null if the character ID is invalid
|
* @returns {string?} The filename of the character avatar without extension, or null if the character ID is invalid
|
||||||
|
@@ -966,7 +966,7 @@ function registerWorldInfoSlashCommands() {
|
|||||||
/**
|
/**
|
||||||
* Gets the name of the character-bound lorebook.
|
* Gets the name of the character-bound lorebook.
|
||||||
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} args Named arguments
|
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} args Named arguments
|
||||||
* @param {import('./slash-commands/SlashCommand.js').UnnamedArguments} name Character name
|
* @param {string} name Character name
|
||||||
* @returns {string} The name of the character-bound lorebook, a JSON string of the character's lorebooks, or an empty string
|
* @returns {string} The name of the character-bound lorebook, a JSON string of the character's lorebooks, or an empty string
|
||||||
*/
|
*/
|
||||||
function getCharBookCallback({ type }, name) {
|
function getCharBookCallback({ type }, name) {
|
||||||
@@ -3443,7 +3443,7 @@ function createEntryInputAutocomplete(input, callback, { allowMultiple = false }
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(input).on('focus click', function () {
|
$(input).on('focus click', function () {
|
||||||
$(input).autocomplete('search', allowMultiple ? String($(input).val()).split(/,\s*/).pop() : $(input).val());
|
$(input).autocomplete('search', allowMultiple ? String($(input).val()).split(/,\s*/).pop() : String($(input).val()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5118,7 +5118,7 @@ export function openWorldInfoEditor(worldName) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns a lorebook to the current chat.
|
* Assigns a lorebook to the current chat.
|
||||||
* @param {PointerEvent} event Pointer event
|
* @param {JQuery.ClickEvent<Document, undefined, any, any>} event Pointer event
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export async function assignLorebookToChat(event) {
|
export async function assignLorebookToChat(event) {
|
||||||
@@ -5157,11 +5157,106 @@ export async function assignLorebookToChat(event) {
|
|||||||
saveMetadata();
|
saveMetadata();
|
||||||
});
|
});
|
||||||
|
|
||||||
return callGenericPopup(template, POPUP_TYPE.TEXT);
|
await callGenericPopup(template, POPUP_TYPE.TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery(() => {
|
/**
|
||||||
|
* Moves a World Info entry from a source lorebook to a target lorebook.
|
||||||
|
*
|
||||||
|
* @param {string} sourceName - The name of the source lorebook file.
|
||||||
|
* @param {string} targetName - The name of the target lorebook file.
|
||||||
|
* @param {string|number} uid - The UID of the entry to move from the source lorebook.
|
||||||
|
* @returns {Promise<boolean>} True if the move was successful, false otherwise.
|
||||||
|
*/
|
||||||
|
export async function moveWorldInfoEntry(sourceName, targetName, uid) {
|
||||||
|
if (sourceName === targetName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!world_names.includes(sourceName)) {
|
||||||
|
toastr.error(t`Source lorebook '${sourceName}' not found.`);
|
||||||
|
console.error(`[WI Move] Source lorebook '${sourceName}' does not exist.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!world_names.includes(targetName)) {
|
||||||
|
toastr.error(t`Target lorebook '${targetName}' not found.`);
|
||||||
|
console.error(`[WI Move] Target lorebook '${targetName}' does not exist.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entryUidString = String(uid);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const sourceData = await loadWorldInfo(sourceName);
|
||||||
|
const targetData = await loadWorldInfo(targetName);
|
||||||
|
|
||||||
|
if (!sourceData || !sourceData.entries) {
|
||||||
|
toastr.error(t`Failed to load data for source lorebook '${sourceName}'.`);
|
||||||
|
console.error(`[WI Move] Could not load source data for '${sourceName}'.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!targetData || !targetData.entries) {
|
||||||
|
toastr.error(t`Failed to load data for target lorebook '${targetName}'.`);
|
||||||
|
console.error(`[WI Move] Could not load target data for '${targetName}'.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sourceData.entries[entryUidString]) {
|
||||||
|
toastr.error(t`Entry not found in source lorebook '${sourceName}'.`);
|
||||||
|
console.error(`[WI Move] Entry UID ${entryUidString} not found in '${sourceName}'.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entryToMove = structuredClone(sourceData.entries[entryUidString]);
|
||||||
|
|
||||||
|
|
||||||
|
const newUid = getFreeWorldEntryUid(targetData);
|
||||||
|
if (newUid === null) {
|
||||||
|
console.error(`[WI Move] Failed to get a free UID in '${targetName}'.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
entryToMove.uid = newUid;
|
||||||
|
// Place the entry at the end of the target lorebook
|
||||||
|
const maxDisplayIndex = Object.values(targetData.entries).reduce((max, entry) => Math.max(max, entry.displayIndex ?? -1), -1);
|
||||||
|
entryToMove.displayIndex = maxDisplayIndex + 1;
|
||||||
|
|
||||||
|
targetData.entries[newUid] = entryToMove;
|
||||||
|
|
||||||
|
delete sourceData.entries[entryUidString];
|
||||||
|
// Remove from originalData if it exists
|
||||||
|
deleteWIOriginalDataValue(sourceData, entryUidString);
|
||||||
|
// TODO: setWIOriginalDataValue
|
||||||
|
console.debug(`[WI Move] Removed entry UID ${entryUidString} from source '${sourceName}'.`);
|
||||||
|
|
||||||
|
|
||||||
|
await saveWorldInfo(targetName, targetData, true);
|
||||||
|
console.debug(`[WI Move] Saved target lorebook '${targetName}'.`);
|
||||||
|
await saveWorldInfo(sourceName, sourceData, true);
|
||||||
|
console.debug(`[WI Move] Saved source lorebook '${sourceName}'.`);
|
||||||
|
|
||||||
|
|
||||||
|
console.log(`[WI Move] ${entryToMove.comment} moved successfully to '${targetName}'.`);
|
||||||
|
|
||||||
|
// Check if the currently viewed book in the editor is the source or target and reload it
|
||||||
|
const currentEditorBookIndex = Number($('#world_editor_select').val());
|
||||||
|
if (!isNaN(currentEditorBookIndex)) {
|
||||||
|
const currentEditorBookName = world_names[currentEditorBookIndex];
|
||||||
|
if (currentEditorBookName === sourceName || currentEditorBookName === targetName) {
|
||||||
|
reloadEditor(currentEditorBookName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
toastr.error(t`An unexpected error occurred while moving the entry: ${error.message}`);
|
||||||
|
console.error('[WI Move] Unexpected error:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initWorldInfo() {
|
||||||
$('#world_info').on('mousedown change', async function (e) {
|
$('#world_info').on('mousedown change', async function (e) {
|
||||||
// If there's no world names, don't do anything
|
// If there's no world names, don't do anything
|
||||||
if (world_names.length === 0) {
|
if (world_names.length === 0) {
|
||||||
@@ -5348,7 +5443,7 @@ jQuery(() => {
|
|||||||
if (!isMobile()) {
|
if (!isMobile()) {
|
||||||
$('#world_info').select2({
|
$('#world_info').select2({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
placeholder: 'No Worlds active. Click here to select.',
|
placeholder: t`No Worlds active. Click here to select.`,
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
closeOnSelect: false,
|
closeOnSelect: false,
|
||||||
});
|
});
|
||||||
@@ -5373,100 +5468,4 @@ jQuery(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves a World Info entry from a source lorebook to a target lorebook.
|
|
||||||
*
|
|
||||||
* @param {string} sourceName - The name of the source lorebook file.
|
|
||||||
* @param {string} targetName - The name of the target lorebook file.
|
|
||||||
* @param {string|number} uid - The UID of the entry to move from the source lorebook.
|
|
||||||
* @returns {Promise<boolean>} True if the move was successful, false otherwise.
|
|
||||||
*/
|
|
||||||
export async function moveWorldInfoEntry(sourceName, targetName, uid) {
|
|
||||||
if (sourceName === targetName) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!world_names.includes(sourceName)) {
|
|
||||||
toastr.error(t`Source lorebook '${sourceName}' not found.`);
|
|
||||||
console.error(`[WI Move] Source lorebook '${sourceName}' does not exist.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!world_names.includes(targetName)) {
|
|
||||||
toastr.error(t`Target lorebook '${targetName}' not found.`);
|
|
||||||
console.error(`[WI Move] Target lorebook '${targetName}' does not exist.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const entryUidString = String(uid);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const sourceData = await loadWorldInfo(sourceName);
|
|
||||||
const targetData = await loadWorldInfo(targetName);
|
|
||||||
|
|
||||||
if (!sourceData || !sourceData.entries) {
|
|
||||||
toastr.error(t`Failed to load data for source lorebook '${sourceName}'.`);
|
|
||||||
console.error(`[WI Move] Could not load source data for '${sourceName}'.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!targetData || !targetData.entries) {
|
|
||||||
toastr.error(t`Failed to load data for target lorebook '${targetName}'.`);
|
|
||||||
console.error(`[WI Move] Could not load target data for '${targetName}'.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sourceData.entries[entryUidString]) {
|
|
||||||
toastr.error(t`Entry not found in source lorebook '${sourceName}'.`);
|
|
||||||
console.error(`[WI Move] Entry UID ${entryUidString} not found in '${sourceName}'.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const entryToMove = structuredClone(sourceData.entries[entryUidString]);
|
|
||||||
|
|
||||||
|
|
||||||
const newUid = getFreeWorldEntryUid(targetData);
|
|
||||||
if (newUid === null) {
|
|
||||||
console.error(`[WI Move] Failed to get a free UID in '${targetName}'.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
entryToMove.uid = newUid;
|
|
||||||
// Place the entry at the end of the target lorebook
|
|
||||||
const maxDisplayIndex = Object.values(targetData.entries).reduce((max, entry) => Math.max(max, entry.displayIndex ?? -1), -1);
|
|
||||||
entryToMove.displayIndex = maxDisplayIndex + 1;
|
|
||||||
|
|
||||||
targetData.entries[newUid] = entryToMove;
|
|
||||||
|
|
||||||
delete sourceData.entries[entryUidString];
|
|
||||||
// Remove from originalData if it exists
|
|
||||||
deleteWIOriginalDataValue(sourceData, entryUidString);
|
|
||||||
// TODO: setWIOriginalDataValue
|
|
||||||
console.debug(`[WI Move] Removed entry UID ${entryUidString} from source '${sourceName}'.`);
|
|
||||||
|
|
||||||
|
|
||||||
await saveWorldInfo(targetName, targetData, true);
|
|
||||||
console.debug(`[WI Move] Saved target lorebook '${targetName}'.`);
|
|
||||||
await saveWorldInfo(sourceName, sourceData, true);
|
|
||||||
console.debug(`[WI Move] Saved source lorebook '${sourceName}'.`);
|
|
||||||
|
|
||||||
|
|
||||||
console.log(`[WI Move] ${entryToMove.comment} moved successfully to '${targetName}'.`);
|
|
||||||
|
|
||||||
// Check if the currently viewed book in the editor is the source or target and reload it
|
|
||||||
const currentEditorBookIndex = Number($('#world_editor_select').val());
|
|
||||||
if (!isNaN(currentEditorBookIndex)) {
|
|
||||||
const currentEditorBookName = world_names[currentEditorBookIndex];
|
|
||||||
if (currentEditorBookName === sourceName || currentEditorBookName === targetName) {
|
|
||||||
reloadEditor(currentEditorBookName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
toastr.error(t`An unexpected error occurred while moving the entry: ${error.message}`);
|
|
||||||
console.error('[WI Move] Unexpected error:', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user