Merge pull request #3915 from SillyTavern/feat/refactor-wi-init Refactor WI init to init function for more consistent startup

dafc4e8098a1732562844f28fb5ffec460434fc5

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
3 files changed, +104 -103Ignore whitespace
public/script.js+2 -0
@@ -50,6 +50,7 @@ import {
5050 importWorldInfo,
5151 wi_anchor_position,
5252 world_info_include_names,
53+ initWorldInfo,
5354} from './scripts/world-info.js';
5455
5556import {
@@ -992,6 +993,7 @@ async function firstLoadInit() {
992993 initBackgrounds();
993994 initAuthorsNote();
994995 await initPersonas();
996+ initWorldInfo();
995997 initRossMods();
996998 initStats();
997999 initCfg();
public/scripts/utils.js+1 -1
@@ -1047,7 +1047,7 @@ export function getImageSizeFromDataURL(dataUrl) {
10471047
10481048/**
10491049 * Gets the filename of the character avatar without extension
10501050 * @param {string|number?} [chid=null] - Character ID. If not provided, uses the current character ID
10511051 * @param {object} [options={}] - Options arguments
10521052 * @param {string?} [options.manualAvatarKey=null] - Manually take the following avatar key, instead of using the chid to determine the name
10531053 * @returns {string?} The filename of the character avatar without extension, or null if the character ID is invalid
public/scripts/world-info.js+101 -102
@@ -966,7 +966,7 @@ function registerWorldInfoSlashCommands() {
966966 /**
967967 * Gets the name of the character-bound lorebook.
968968 * @param {import('./slash-commands/SlashCommand.js').NamedArguments} args Named arguments
969969 * @param {import('./slash-commands/SlashCommand.js').UnnamedArgumentsstring} name Character name
970970 * @returns {string} The name of the character-bound lorebook, a JSON string of the character's lorebooks, or an empty string
971971 */
972972 function getCharBookCallback({ type }, name) {
@@ -3443,7 +3443,7 @@ function createEntryInputAutocomplete(input, callback, { allowMultiple = false }
34433443 });
34443444
34453445 $(input).on('focus click', function () {
34463446 $(input).autocomplete('search', allowMultiple ? String($(input).val()).split(/,\s*/).pop() : String($(input).val()));
34473447 });
34483448}
34493449
@@ -5118,7 +5118,7 @@ export function openWorldInfoEditor(worldName) {
51185118
51195119/**
51205120 * Assigns a lorebook to the current chat.
51215121 * @param {PointerEventJQuery.ClickEvent<Document, undefined, any, any>} event Pointer event
51225122 * @returns {Promise<void>}
51235123 */
51245124export async function assignLorebookToChat(event) {
@@ -5157,11 +5157,106 @@ export async function assignLorebookToChat(event) {
51575157 saveMetadata();
51585158 });
51595159
51605160 returnawait callGenericPopup(template, POPUP_TYPE.TEXT);
51615161}
51625162
5163-jQuery(() => {
5163+/**
5164+ * Moves a World Info entry from a source lorebook to a target lorebook.
5165+ *
5166+ * @param {string} sourceName - The name of the source lorebook file.
5167+ * @param {string} targetName - The name of the target lorebook file.
5168+ * @param {string|number} uid - The UID of the entry to move from the source lorebook.
5169+ * @returns {Promise<boolean>} True if the move was successful, false otherwise.
5170+ */
5171+export async function moveWorldInfoEntry(sourceName, targetName, uid) {
5172+ if (sourceName === targetName) {
5173+ return false;
5174+ }
5175+
5176+ if (!world_names.includes(sourceName)) {
5177+ toastr.error(t`Source lorebook '${sourceName}' not found.`);
5178+ console.error(`[WI Move] Source lorebook '${sourceName}' does not exist.`);
5179+ return false;
5180+ }
5181+
5182+ if (!world_names.includes(targetName)) {
5183+ toastr.error(t`Target lorebook '${targetName}' not found.`);
5184+ console.error(`[WI Move] Target lorebook '${targetName}' does not exist.`);
5185+ return false;
5186+ }
5187+
5188+ const entryUidString = String(uid);
5189+
5190+ try {
5191+ const sourceData = await loadWorldInfo(sourceName);
5192+ const targetData = await loadWorldInfo(targetName);
5193+
5194+ if (!sourceData || !sourceData.entries) {
5195+ toastr.error(t`Failed to load data for source lorebook '${sourceName}'.`);
5196+ console.error(`[WI Move] Could not load source data for '${sourceName}'.`);
5197+ return false;
5198+ }
5199+ if (!targetData || !targetData.entries) {
5200+ toastr.error(t`Failed to load data for target lorebook '${targetName}'.`);
5201+ console.error(`[WI Move] Could not load target data for '${targetName}'.`);
5202+ return false;
5203+ }
5204+
5205+ if (!sourceData.entries[entryUidString]) {
5206+ toastr.error(t`Entry not found in source lorebook '${sourceName}'.`);
5207+ console.error(`[WI Move] Entry UID ${entryUidString} not found in '${sourceName}'.`);
5208+ return false;
5209+ }
5210+
5211+ const entryToMove = structuredClone(sourceData.entries[entryUidString]);
5212+
5213+
5214+ const newUid = getFreeWorldEntryUid(targetData);
5215+ if (newUid === null) {
5216+ console.error(`[WI Move] Failed to get a free UID in '${targetName}'.`);
5217+ return false;
5218+ }
5219+
5220+ entryToMove.uid = newUid;
5221+ // Place the entry at the end of the target lorebook
5222+ const maxDisplayIndex = Object.values(targetData.entries).reduce((max, entry) => Math.max(max, entry.displayIndex ?? -1), -1);
5223+ entryToMove.displayIndex = maxDisplayIndex + 1;
5224+
5225+ targetData.entries[newUid] = entryToMove;
5226+
5227+ delete sourceData.entries[entryUidString];
5228+ // Remove from originalData if it exists
5229+ deleteWIOriginalDataValue(sourceData, entryUidString);
5230+ // TODO: setWIOriginalDataValue
5231+ console.debug(`[WI Move] Removed entry UID ${entryUidString} from source '${sourceName}'.`);
5232+
5233+
5234+ await saveWorldInfo(targetName, targetData, true);
5235+ console.debug(`[WI Move] Saved target lorebook '${targetName}'.`);
5236+ await saveWorldInfo(sourceName, sourceData, true);
5237+ console.debug(`[WI Move] Saved source lorebook '${sourceName}'.`);
5238+
5239+
5240+ console.log(`[WI Move] ${entryToMove.comment} moved successfully to '${targetName}'.`);
5241+
5242+ // Check if the currently viewed book in the editor is the source or target and reload it
5243+ const currentEditorBookIndex = Number($('#world_editor_select').val());
5244+ if (!isNaN(currentEditorBookIndex)) {
5245+ const currentEditorBookName = world_names[currentEditorBookIndex];
5246+ if (currentEditorBookName === sourceName || currentEditorBookName === targetName) {
5247+ reloadEditor(currentEditorBookName);
5248+ }
5249+ }
5250+
5251+ return true;
5252+ } catch (error) {
5253+ toastr.error(t`An unexpected error occurred while moving the entry: ${error.message}`);
5254+ console.error('[WI Move] Unexpected error:', error);
5255+ return false;
5256+ }
5257+}
51645258
5259+export function initWorldInfo() {
51655260 $('#world_info').on('mousedown change', async function (e) {
51665261 // If there's no world names, don't do anything
51675262 if (world_names.length === 0) {
@@ -5348,7 +5443,7 @@ jQuery(() => {
53485443 if (!isMobile()) {
53495444 $('#world_info').select2({
53505445 width: '100%',
53515446 placeholder: 't`No Worlds active. Click here to select.'`,
53525447 allowClear: true,
53535448 closeOnSelect: false,
53545449 });
@@ -5373,100 +5468,4 @@ jQuery(() => {
53735468 }
53745469 });
53755470 });
5376-});
5377-
5378-/**
5379- * Moves a World Info entry from a source lorebook to a target lorebook.
5380- *
5381- * @param {string} sourceName - The name of the source lorebook file.
5382- * @param {string} targetName - The name of the target lorebook file.
5383- * @param {string|number} uid - The UID of the entry to move from the source lorebook.
5384- * @returns {Promise<boolean>} True if the move was successful, false otherwise.
5385- */
5386-export async function moveWorldInfoEntry(sourceName, targetName, uid) {
5387- if (sourceName === targetName) {
5388- return false;
5389- }
5390-
5391- if (!world_names.includes(sourceName)) {
5392- toastr.error(t`Source lorebook '${sourceName}' not found.`);
5393- console.error(`[WI Move] Source lorebook '${sourceName}' does not exist.`);
5394- return false;
5395- }
5396-
5397- if (!world_names.includes(targetName)) {
5398- toastr.error(t`Target lorebook '${targetName}' not found.`);
5399- console.error(`[WI Move] Target lorebook '${targetName}' does not exist.`);
5400- return false;
5401- }
5402-
5403- const entryUidString = String(uid);
5404-
5405- try {
5406- const sourceData = await loadWorldInfo(sourceName);
5407- const targetData = await loadWorldInfo(targetName);
5408-
5409- if (!sourceData || !sourceData.entries) {
5410- toastr.error(t`Failed to load data for source lorebook '${sourceName}'.`);
5411- console.error(`[WI Move] Could not load source data for '${sourceName}'.`);
5412- return false;
5413- }
5414- if (!targetData || !targetData.entries) {
5415- toastr.error(t`Failed to load data for target lorebook '${targetName}'.`);
5416- console.error(`[WI Move] Could not load target data for '${targetName}'.`);
5417- return false;
5418- }
5419-
5420- if (!sourceData.entries[entryUidString]) {
5421- toastr.error(t`Entry not found in source lorebook '${sourceName}'.`);
5422- console.error(`[WI Move] Entry UID ${entryUidString} not found in '${sourceName}'.`);
5423- return false;
5424- }
5425-
5426- const entryToMove = structuredClone(sourceData.entries[entryUidString]);
5427-
5428-
5429- const newUid = getFreeWorldEntryUid(targetData);
5430- if (newUid === null) {
5431- console.error(`[WI Move] Failed to get a free UID in '${targetName}'.`);
5432- return false;
5433- }
5434-
5435- entryToMove.uid = newUid;
5436- // Place the entry at the end of the target lorebook
5437- const maxDisplayIndex = Object.values(targetData.entries).reduce((max, entry) => Math.max(max, entry.displayIndex ?? -1), -1);
5438- entryToMove.displayIndex = maxDisplayIndex + 1;
5439-
5440- targetData.entries[newUid] = entryToMove;
5441-
5442- delete sourceData.entries[entryUidString];
5443- // Remove from originalData if it exists
5444- deleteWIOriginalDataValue(sourceData, entryUidString);
5445- // TODO: setWIOriginalDataValue
5446- console.debug(`[WI Move] Removed entry UID ${entryUidString} from source '${sourceName}'.`);
5447-
5448-
5449- await saveWorldInfo(targetName, targetData, true);
5450- console.debug(`[WI Move] Saved target lorebook '${targetName}'.`);
5451- await saveWorldInfo(sourceName, sourceData, true);
5452- console.debug(`[WI Move] Saved source lorebook '${sourceName}'.`);
5453-
5454-
5455- console.log(`[WI Move] ${entryToMove.comment} moved successfully to '${targetName}'.`);
5456-
5457- // Check if the currently viewed book in the editor is the source or target and reload it
5458- const currentEditorBookIndex = Number($('#world_editor_select').val());
5459- if (!isNaN(currentEditorBookIndex)) {
5460- const currentEditorBookName = world_names[currentEditorBookIndex];
5461- if (currentEditorBookName === sourceName || currentEditorBookName === targetName) {
5462- reloadEditor(currentEditorBookName);
5463- }
5464- }
5465-
5466- return true;
5467- } catch (error) {
5468- toastr.error(t`An unexpected error occurred while moving the entry: ${error.message}`);
5469- console.error('[WI Move] Unexpected error:', error);
5470- return false;
5471- }
54725471}