feat(inventory): add inline editing for inventory items
- Created inventoryEdit.js module with updateInventoryItem() function - Made all inventory item names editable with contenteditable (mobile-friendly) - Added rpg-editable class to 6 item rendering locations: * On Person (grid and list views) * Stored (grid and list views) * Assets (grid and list views) - Added blur event listener to save changes on edit - Validates and sanitizes edited names using sanitizeItemName() - Syncs changes to lastGeneratedData and committedTrackerData (AI-visible) - Shows full item text when editing (not truncated) - Consistent UX with other editable fields in extension (stats, character traits, etc.) - Re-renders inventory after successful edit or reverts on invalid input
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Inventory Item Editing Module
|
||||
* Handles inline editing of inventory item names
|
||||
*/
|
||||
|
||||
import { extensionSettings, lastGeneratedData, committedTrackerData } from '../../core/state.js';
|
||||
import { saveSettings, saveChatData, updateMessageSwipeData } from '../../core/persistence.js';
|
||||
import { buildInventorySummary } from '../generation/promptBuilder.js';
|
||||
import { renderInventory } from '../rendering/inventory.js';
|
||||
import { parseItems, serializeItems } from '../../utils/itemParser.js';
|
||||
import { sanitizeItemName } from '../../utils/security.js';
|
||||
|
||||
/**
|
||||
* Updates an existing inventory item's name.
|
||||
* Validates, sanitizes, and persists the change.
|
||||
*
|
||||
* @param {string} field - Field name ('onPerson', 'stored', 'assets')
|
||||
* @param {number} index - Index of item in the array
|
||||
* @param {string} newName - New name for the item
|
||||
* @param {string} [location] - Location name (required for 'stored' field)
|
||||
*/
|
||||
export function updateInventoryItem(field, index, newName, location) {
|
||||
const inventory = extensionSettings.userStats.inventory;
|
||||
|
||||
// Validate and sanitize the new item name
|
||||
const sanitizedName = sanitizeItemName(newName);
|
||||
if (!sanitizedName) {
|
||||
console.warn('[RPG Companion] Invalid item name, reverting change');
|
||||
// Re-render to revert the change in UI
|
||||
renderInventory();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current items for the field
|
||||
let currentString;
|
||||
if (field === 'stored') {
|
||||
if (!location) {
|
||||
console.error('[RPG Companion] Location required for stored items');
|
||||
return;
|
||||
}
|
||||
currentString = inventory.stored[location] || 'None';
|
||||
} else {
|
||||
currentString = inventory[field] || 'None';
|
||||
}
|
||||
|
||||
// Parse current items
|
||||
const items = parseItems(currentString);
|
||||
|
||||
// Validate index
|
||||
if (index < 0 || index >= items.length) {
|
||||
console.error(`[RPG Companion] Invalid item index: ${index}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the item at this index
|
||||
items[index] = sanitizedName;
|
||||
|
||||
// Serialize back to string
|
||||
const newItemString = serializeItems(items);
|
||||
|
||||
// Update the inventory
|
||||
if (field === 'stored') {
|
||||
inventory.stored[location] = newItemString;
|
||||
} else {
|
||||
inventory[field] = newItemString;
|
||||
}
|
||||
|
||||
// Update lastGeneratedData and committedTrackerData with new inventory
|
||||
updateLastGeneratedDataInventory();
|
||||
|
||||
// Save changes
|
||||
saveSettings();
|
||||
saveChatData();
|
||||
updateMessageSwipeData();
|
||||
|
||||
// Re-render inventory
|
||||
renderInventory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates lastGeneratedData.userStats AND committedTrackerData.userStats to include
|
||||
* current inventory in text format.
|
||||
* This ensures manual edits are immediately visible to AI in next generation.
|
||||
* @private
|
||||
*/
|
||||
function updateLastGeneratedDataInventory() {
|
||||
const stats = extensionSettings.userStats;
|
||||
const inventorySummary = buildInventorySummary(stats.inventory);
|
||||
|
||||
// Rebuild the userStats text format
|
||||
const statsText =
|
||||
`Health: ${stats.health}%\n` +
|
||||
`Satiety: ${stats.satiety}%\n` +
|
||||
`Energy: ${stats.energy}%\n` +
|
||||
`Hygiene: ${stats.hygiene}%\n` +
|
||||
`Arousal: ${stats.arousal}%\n` +
|
||||
`${stats.mood}: ${stats.conditions}\n` +
|
||||
`${inventorySummary}`;
|
||||
|
||||
// Update BOTH lastGeneratedData AND committedTrackerData
|
||||
// This makes manual edits immediately visible to AI
|
||||
lastGeneratedData.userStats = statsText;
|
||||
committedTrackerData.userStats = statsText;
|
||||
}
|
||||
Reference in New Issue
Block a user