Progress on move entry * Fixed header alignment * Building HTML with browser api instead of string. * jqueryElement.data(key, value) usages converted to jqueryElement.attr(data-key, value) * Logs simplified * Removed success toastry message
| @@ -1,4 +1,4 @@ | |||
| 1 | <div id="WIEntryHeaderTitlesPC" class="flex-container wide100p spaceBetween justifyCenter textAlignCenter" style="padding:0 4.5em;"> | 1 | <div id="WIEntryHeaderTitlesPC" class="flex-container wide100p spaceBetween justifyCenter textAlignCenter" style="padding:0 7.0em;"> |
| 2 | <small class="flex1" data-i18n="Title/Memo">Title/Memo</small> | 2 | <small class="flex1" data-i18n="Title/Memo">Title/Memo</small> |
| 3 | <small style="width: calc(3.5em + 10px)" data-i18n="Strategy">Strategy</small> | 3 | <small style="width: calc(3.5em + 10px)" data-i18n="Strategy">Strategy</small> |
| 4 | <small style="width: calc(3.5em + 20px)" data-i18n="Position">Position</small> | 4 | <small style="width: calc(3.5em + 20px)" data-i18n="Position">Position</small> |
| @@ -2208,7 +2208,7 @@ function verifyWorldInfoSearchSortRule() { | |||
| 2208 | * Use `originalWIDataKeyMap` to find the correct value to be set. | 2208 | * Use `originalWIDataKeyMap` to find the correct value to be set. |
| 2209 | * | 2209 | * |
| 2210 | * @param {object} data - The data object containing the original data entries. | 2210 | * @param {object} data - The data object containing the original data entries. |
| 2211 | * @param {string} uid - The unique identifier of the data entry. | 2211 | * @param {number} uid - The unique identifier of the data entry. |
| 2212 | * @param {string} key - The key of the value to be set. | 2212 | * @param {string} key - The key of the value to be set. |
| 2213 | * @param {any} value - The value to be set. | 2213 | * @param {any} value - The value to be set. |
| 2214 | */ | 2214 | */ |
| @@ -3141,21 +3141,38 @@ export async function getWorldEntry(name, data, entry) { | |||
| 3141 | 3141 | ||
| 3142 | // move button | 3142 | // move button |
| 3143 | const moveButton = template.find('.move_entry_button'); | 3143 | const moveButton = template.find('.move_entry_button'); |
| 3144 | moveButton.data('uid', entry.uid); | 3144 | moveButton.attr('data-uid', entry.uid); |
| 3145 | moveButton.data('current-world', name); | 3145 | moveButton.attr('data-current-world', name); |
| 3146 | moveButton.on('click', async function (e) { | 3146 | moveButton.on('click', async function (e) { |
| 3147 | e.stopPropagation(); | 3147 | e.stopPropagation(); |
| 3148 | const sourceUid = $(this).data('uid'); | 3148 | const sourceUid = $(this).data('uid'); |
| 3149 | const sourceWorld = $(this).data('current-world'); | 3149 | const sourceWorld = $(this).data('current-world'); |
| 3150 | // Loading world info is bad, do we have cache variable? | 3150 | const sourceWorldInfo = await loadWorldInfo(sourceWorld); |
| 3151 | const sourceName = (await loadWorldInfo(sourceWorld)).entries[sourceUid].comment; | 3151 | if (!sourceWorldInfo) { |
| 3152 | return; | ||
| 3153 | } | ||
| 3154 | const sourceName = sourceWorldInfo.entries[sourceUid]?.comment; | ||
| 3155 | if (sourceName === undefined) { | ||
| 3156 | return; | ||
| 3157 | } | ||
| 3158 | |||
| 3159 | const select = document.createElement('select'); | ||
| 3160 | select.id = 'move_entry_target_select'; | ||
| 3161 | select.classList.add('text_pole', 'wide100p', 'margin-top'); | ||
| 3162 | |||
| 3163 | const defaultOption = document.createElement('option'); | ||
| 3164 | defaultOption.value = ''; | ||
| 3165 | defaultOption.textContent = `-- ${t`Select Target Lorebook`} --`; | ||
| 3166 | select.appendChild(defaultOption); | ||
| 3152 | 3167 | ||
| 3153 | let optionsHtml = `<option value="">-- ${t`Select Target Lorebook`} --</option>`; | ||
| 3154 | let selectableWorldCount = 0; | 3168 | let selectableWorldCount = 0; |
| 3155 | world_names.forEach(worldName => { | 3169 | world_names.forEach(worldName => { |
| 3156 | if (worldName !== sourceWorld) { // Exclude the current world | 3170 | if (worldName !== sourceWorld) { // Exclude current world |
| 3157 | optionsHtml += `<option value="${world_names.indexOf(worldName)}">${worldName}</option>`; | 3171 | const option = document.createElement('option'); |
| 3158 | selectableWorldCount += 1; | 3172 | option.value = world_names.indexOf(worldName).toString(); |
| 3173 | option.textContent = worldName; | ||
| 3174 | select.appendChild(option); | ||
| 3175 | selectableWorldCount++; | ||
| 3159 | } | 3176 | } |
| 3160 | }); | 3177 | }); |
| 3161 | 3178 | ||
| @@ -3164,27 +3181,24 @@ export async function getWorldEntry(name, data, entry) { | |||
| 3164 | return; | 3181 | return; |
| 3165 | } | 3182 | } |
| 3166 | 3183 | ||
| 3167 | const content = ` | 3184 | // Create wrapper div |
| 3168 | <div>${t`Move ${sourceName} to:`}</div> | 3185 | const wrapper = document.createElement('div'); |
| 3169 | <select id="move_entry_target_select" class="text_pole wide100p margin-top"> | 3186 | wrapper.textContent = t`Move ${sourceName} to:`; |
| 3170 | ${optionsHtml} | ||
| 3171 | </select> | ||
| 3172 | `; | ||
| 3173 | 3187 | ||
| 3174 | const popupPromise = callGenericPopup(content, POPUP_TYPE.CONFIRM, '', { | 3188 | // Create container and append elements |
| 3175 | okButton: t`Move`, | 3189 | const container = document.createElement('div'); |
| 3176 | cancelButton: t`Cancel`, | 3190 | container.appendChild(wrapper); |
| 3177 | }); | 3191 | container.appendChild(select); |
| 3178 | 3192 | ||
| 3179 | let selectedWorldIndex = -1; | 3193 | let selectedWorldIndex = -1; |
| 3180 | $('#move_entry_target_select').on('change', function () { | 3194 | select.addEventListener('change', function() { |
| 3181 | /** @type {string} */ | 3195 | selectedWorldIndex = this.value === '' ? -1 : Number(this.value); |
| 3182 | // @ts-ignore | ||
| 3183 | const value = $(this).val(); | ||
| 3184 | selectedWorldIndex = value === '' ? -1 : Number(value); | ||
| 3185 | }); | 3196 | }); |
| 3186 | 3197 | ||
| 3187 | const popupConfirm = await popupPromise; | 3198 | const popupConfirm = await callGenericPopup(container, POPUP_TYPE.CONFIRM, '', { |
| 3199 | okButton: t`Move`, | ||
| 3200 | cancelButton: t`Cancel`, | ||
| 3201 | }); | ||
| 3188 | if (!popupConfirm) { | 3202 | if (!popupConfirm) { |
| 3189 | return; | 3203 | return; |
| 3190 | } | 3204 | } |
| @@ -5337,19 +5351,11 @@ jQuery(() => { | |||
| 5337 | * | 5351 | * |
| 5338 | * @param {string} sourceName - The name of the source lorebook file. | 5352 | * @param {string} sourceName - The name of the source lorebook file. |
| 5339 | * @param {string} targetName - The name of the target lorebook file. | 5353 | * @param {string} targetName - The name of the target lorebook file. |
| 5340 | * @param {number|string} uid - The UID of the entry to move from the source lorebook. | 5354 | * @param {number} uid - The UID of the entry to move from the source lorebook. |
| 5341 | * @returns {Promise<boolean>} True if the move was successful, false otherwise. | 5355 | * @returns {Promise<boolean>} True if the move was successful, false otherwise. |
| 5342 | */ | 5356 | */ |
| 5343 | export async function moveWorldInfoEntry(sourceName, targetName, uid) { | 5357 | export async function moveWorldInfoEntry(sourceName, targetName, uid) { |
| 5344 | console.log(`[WI] Attempting to move entry UID ${uid} from '${sourceName}' to '${targetName}'`); | ||
| 5345 | |||
| 5346 | if (!sourceName || !targetName || uid === undefined || uid === null) { | ||
| 5347 | console.error('[WI Move] Missing required arguments.'); | ||
| 5348 | return false; | ||
| 5349 | } | ||
| 5350 | |||
| 5351 | if (sourceName === targetName) { | 5358 | if (sourceName === targetName) { |
| 5352 | toastr.warning(t`Source and target lorebooks cannot be the same.`); | ||
| 5353 | return false; | 5359 | return false; |
| 5354 | } | 5360 | } |
| 5355 | 5361 | ||
| @@ -5407,20 +5413,19 @@ export async function moveWorldInfoEntry(sourceName, targetName, uid) { | |||
| 5407 | targetData.entries[newUid] = entryToMove; | 5413 | targetData.entries[newUid] = entryToMove; |
| 5408 | 5414 | ||
| 5409 | delete sourceData.entries[entryUidString]; | 5415 | delete sourceData.entries[entryUidString]; |
| 5410 | // Remove from originalData if it exists, using the original UID | 5416 | // Remove from originalData if it exists |
| 5411 | deleteWIOriginalDataValue(sourceData, entryUidString); | 5417 | deleteWIOriginalDataValue(sourceData, entryUidString); |
| 5418 | // TODO: setWIOriginalDataValue | ||
| 5412 | console.debug(`[WI Move] Removed entry UID ${entryUidString} from source '${sourceName}'.`); | 5419 | console.debug(`[WI Move] Removed entry UID ${entryUidString} from source '${sourceName}'.`); |
| 5413 | 5420 | ||
| 5414 | 5421 | ||
| 5415 | // Save immediately to reduce chances of inconsistency if the browser is closed | 5422 | await saveWorldInfo(targetName, targetData); |
| 5416 | // Note: This is not truly atomic. If one save fails, state could be inconsistent. | ||
| 5417 | await saveWorldInfo(targetName, targetData, true); | ||
| 5418 | console.debug(`[WI Move] Saved target lorebook '${targetName}'.`); | 5423 | console.debug(`[WI Move] Saved target lorebook '${targetName}'.`); |
| 5419 | await saveWorldInfo(sourceName, sourceData, true); | 5424 | await saveWorldInfo(sourceName, sourceData); |
| 5420 | console.debug(`[WI Move] Saved source lorebook '${sourceName}'.`); | 5425 | console.debug(`[WI Move] Saved source lorebook '${sourceName}'.`); |
| 5421 | 5426 | ||
| 5422 | 5427 | ||
| 5423 | toastr.success(t`${entryToMove.comment} moved successfully!`); | 5428 | console.log(`[WI Move] ${entryToMove.comment} moved successfully to '${targetName}'.`); |
| 5424 | 5429 | ||
| 5425 | // Check if the currently viewed book in the editor is the source or target and reload it | 5430 | // Check if the currently viewed book in the editor is the source or target and reload it |
| 5426 | const currentEditorBookIndex = Number($('#world_editor_select').val()); | 5431 | const currentEditorBookIndex = Number($('#world_editor_select').val()); |