fix(inventory): preserve form state across re-renders

Fixes bug where expanding an existing storage location would close
the "Add Location" form that was currently open. This happened
because renderInventory() recreated all HTML from scratch, resetting
all inline forms to hidden state.

Solution:
- Track open form states in inventoryActions module
- Restore form visibility after each re-render
- Applies to all inline forms: add location, add items (on person,
  stored, assets)

This also fixes the related issue where switching tabs would close
open forms.

Fixes: Location disappears when expanding while adding new location
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-20 07:06:04 +11:00
parent d7c1db4fb1
commit 0991c30fc9
2 changed files with 90 additions and 1 deletions
@@ -24,6 +24,17 @@ let currentActiveSubTab = 'onPerson';
*/ */
let collapsedLocations = []; let collapsedLocations = [];
/**
* Tracks which inline forms are currently open
* @type {Object}
*/
let openForms = {
addLocation: false,
addItemOnPerson: false,
addItemStored: {}, // { [locationName]: true/false }
addItemAssets: false
};
/** /**
* Updates lastGeneratedData.userStats to include current inventory in text format. * Updates lastGeneratedData.userStats to include current inventory in text format.
* This ensures the AI context stays synced with manual edits. * This ensures the AI context stays synced with manual edits.
@@ -56,9 +67,18 @@ export function showAddItemForm(field, location) {
const locationId = location.replace(/\s+/g, '-'); const locationId = location.replace(/\s+/g, '-');
formId = `rpg-add-item-form-stored-${locationId}`; formId = `rpg-add-item-form-stored-${locationId}`;
inputId = `.rpg-location-item-input[data-location="${location}"]`; inputId = `.rpg-location-item-input[data-location="${location}"]`;
// Track in state
if (!openForms.addItemStored) openForms.addItemStored = {};
openForms.addItemStored[location] = true;
} else { } else {
formId = `rpg-add-item-form-${field}`; formId = `rpg-add-item-form-${field}`;
inputId = `#rpg-new-item-${field}`; inputId = `#rpg-new-item-${field}`;
// Track in state
if (field === 'onPerson') {
openForms.addItemOnPerson = true;
} else if (field === 'assets') {
openForms.addItemAssets = true;
}
} }
const form = $(`#${formId}`); const form = $(`#${formId}`);
@@ -81,9 +101,19 @@ export function hideAddItemForm(field, location) {
const locationId = location.replace(/\s+/g, '-'); const locationId = location.replace(/\s+/g, '-');
formId = `rpg-add-item-form-stored-${locationId}`; formId = `rpg-add-item-form-stored-${locationId}`;
inputId = `.rpg-location-item-input[data-location="${location}"]`; inputId = `.rpg-location-item-input[data-location="${location}"]`;
// Clear from state
if (openForms.addItemStored && openForms.addItemStored[location]) {
delete openForms.addItemStored[location];
}
} else { } else {
formId = `rpg-add-item-form-${field}`; formId = `rpg-add-item-form-${field}`;
inputId = `#rpg-new-item-${field}`; inputId = `#rpg-new-item-${field}`;
// Clear from state
if (field === 'onPerson') {
openForms.addItemOnPerson = false;
} else if (field === 'assets') {
openForms.addItemAssets = false;
}
} }
const form = $(`#${formId}`); const form = $(`#${formId}`);
@@ -189,6 +219,9 @@ export function showAddLocationForm() {
const form = $('#rpg-add-location-form'); const form = $('#rpg-add-location-form');
const input = $('#rpg-new-location-name'); const input = $('#rpg-new-location-name');
// Track in state
openForms.addLocation = true;
form.show(); form.show();
input.val('').focus(); input.val('').focus();
} }
@@ -200,6 +233,9 @@ export function hideAddLocationForm() {
const form = $('#rpg-add-location-form'); const form = $('#rpg-add-location-form');
const input = $('#rpg-new-location-name'); const input = $('#rpg-new-location-name');
// Clear from state
openForms.addLocation = false;
form.hide(); form.hide();
input.val(''); input.val('');
} }
@@ -482,3 +518,50 @@ export function getInventoryRenderOptions() {
collapsedLocations collapsedLocations
}; };
} }
/**
* Restores the state of inline forms after re-rendering.
* This ensures forms that were open before re-render are shown again.
*/
export function restoreFormStates() {
// Restore add location form
if (openForms.addLocation) {
const form = $('#rpg-add-location-form');
const input = $('#rpg-new-location-name');
if (form.length > 0) {
form.show();
// Don't refocus to avoid disrupting user interaction
}
}
// Restore add item on person form
if (openForms.addItemOnPerson) {
const form = $('#rpg-add-item-form-onPerson');
const input = $('#rpg-new-item-onPerson');
if (form.length > 0) {
form.show();
}
}
// Restore add item assets form
if (openForms.addItemAssets) {
const form = $('#rpg-add-item-form-assets');
const input = $('#rpg-new-item-assets');
if (form.length > 0) {
form.show();
}
}
// Restore add item stored forms (for each location)
if (openForms.addItemStored && typeof openForms.addItemStored === 'object') {
for (const location in openForms.addItemStored) {
if (openForms.addItemStored[location]) {
const locationId = location.replace(/\s+/g, '-');
const form = $(`#rpg-add-item-form-stored-${locationId}`);
if (form.length > 0) {
form.show();
}
}
}
}
}
+7 -1
View File
@@ -4,7 +4,7 @@
*/ */
import { extensionSettings, $inventoryContainer } from '../../core/state.js'; import { extensionSettings, $inventoryContainer } from '../../core/state.js';
import { getInventoryRenderOptions } from '../interaction/inventoryActions.js'; import { getInventoryRenderOptions, restoreFormStates } from '../interaction/inventoryActions.js';
import { parseItems } from '../../utils/itemParser.js'; import { parseItems } from '../../utils/itemParser.js';
// Type imports // Type imports
@@ -425,6 +425,9 @@ export function updateInventoryDisplay(containerId, options = {}) {
const inventory = extensionSettings.userStats.inventory; const inventory = extensionSettings.userStats.inventory;
const html = generateInventoryHTML(inventory, options); const html = generateInventoryHTML(inventory, options);
container.innerHTML = html; container.innerHTML = html;
// Restore form states after re-rendering
restoreFormStates();
} }
/** /**
@@ -447,6 +450,9 @@ export function renderInventory() {
// Generate HTML and update DOM // Generate HTML and update DOM
const html = generateInventoryHTML(inventory, options); const html = generateInventoryHTML(inventory, options);
$inventoryContainer.html(html); $inventoryContainer.html(html);
// Restore form states after re-rendering (fixes Bug #1)
restoreFormStates();
} }
/** /**