Add French translate
Add French translation and localize hardcoded strings :
Changes
1. Translation Files
Created
src/i18n/fr.json
: Contains all French translations for the extension.
Updated
src/i18n/en.json
: Added new keys for terms that were previously hardcoded (e.g., "Force", "Volonté", "Météo", "Locked", "Unlocked").
2. UI Updates
settings.html
: Added "Français" to the language selection dropdown.
3. Code Refactoring
src/systems/rendering/thoughts.js
: Replaced hardcoded strings ("Add Character", "Locked", "Click to edit") with i18n calls.
src/systems/rendering/userStats.js
: Replaced hardcoded tooltips and titles with i18n calls.
src/systems/rendering/infoBox.js
: Localized weather, location, and date widget texts.
src/systems/ui/trackerEditor.js
: Updated the "Reset to Defaults" logic to use localized names for stats (e.g., "Santé", "Force") based on the active language.
This commit is contained in:
+168
-168
@@ -159,171 +159,171 @@ export function renderInfoBox() {
|
||||
const lines = infoBoxData.split('\n');
|
||||
// console.log('[RPG Companion] Info Box split into lines:', lines);
|
||||
|
||||
// Track which fields we've already parsed to avoid duplicates from mixed formats
|
||||
const parsedFields = {
|
||||
date: false,
|
||||
temperature: false,
|
||||
time: false,
|
||||
location: false,
|
||||
weather: false
|
||||
};
|
||||
// Track which fields we've already parsed to avoid duplicates from mixed formats
|
||||
const parsedFields = {
|
||||
date: false,
|
||||
temperature: false,
|
||||
time: false,
|
||||
location: false,
|
||||
weather: false
|
||||
};
|
||||
|
||||
for (const line of lines) {
|
||||
// console.log('[RPG Companion] Processing line:', line);
|
||||
for (const line of lines) {
|
||||
// console.log('[RPG Companion] Processing line:', line);
|
||||
|
||||
// Support both new text format (Date:) and legacy emoji format (🗓️:)
|
||||
// Prioritize text format over emoji format
|
||||
if (line.startsWith('Date:')) {
|
||||
if (!parsedFields.date) {
|
||||
// console.log('[RPG Companion] → Matched DATE (text format)');
|
||||
const dateStr = line.replace('Date:', '').trim();
|
||||
const dateParts = dateStr.split(',').map(p => p.trim());
|
||||
data.weekday = dateParts[0] || '';
|
||||
data.month = dateParts[1] || '';
|
||||
data.year = dateParts[2] || '';
|
||||
data.date = dateStr;
|
||||
parsedFields.date = true;
|
||||
}
|
||||
} else if (line.includes('🗓️:')) {
|
||||
if (!parsedFields.date) {
|
||||
// console.log('[RPG Companion] → Matched DATE (emoji format)');
|
||||
const dateStr = line.replace('🗓️:', '').trim();
|
||||
const dateParts = dateStr.split(',').map(p => p.trim());
|
||||
data.weekday = dateParts[0] || '';
|
||||
data.month = dateParts[1] || '';
|
||||
data.year = dateParts[2] || '';
|
||||
data.date = dateStr;
|
||||
parsedFields.date = true;
|
||||
}
|
||||
} else if (line.startsWith('Temperature:')) {
|
||||
if (!parsedFields.temperature) {
|
||||
// console.log('[RPG Companion] → Matched TEMPERATURE (text format)');
|
||||
const tempStr = line.replace('Temperature:', '').trim();
|
||||
data.temperature = tempStr;
|
||||
const tempMatch = tempStr.match(/(-?\d+)/);
|
||||
if (tempMatch) {
|
||||
data.tempValue = parseInt(tempMatch[1]);
|
||||
// Support both new text format (Date:) and legacy emoji format (🗓️:)
|
||||
// Prioritize text format over emoji format
|
||||
if (line.startsWith('Date:')) {
|
||||
if (!parsedFields.date) {
|
||||
// console.log('[RPG Companion] → Matched DATE (text format)');
|
||||
const dateStr = line.replace('Date:', '').trim();
|
||||
const dateParts = dateStr.split(',').map(p => p.trim());
|
||||
data.weekday = dateParts[0] || '';
|
||||
data.month = dateParts[1] || '';
|
||||
data.year = dateParts[2] || '';
|
||||
data.date = dateStr;
|
||||
parsedFields.date = true;
|
||||
}
|
||||
parsedFields.temperature = true;
|
||||
}
|
||||
} else if (line.includes('🌡️:')) {
|
||||
if (!parsedFields.temperature) {
|
||||
// console.log('[RPG Companion] → Matched TEMPERATURE (emoji format)');
|
||||
const tempStr = line.replace('🌡️:', '').trim();
|
||||
data.temperature = tempStr;
|
||||
const tempMatch = tempStr.match(/(-?\d+)/);
|
||||
if (tempMatch) {
|
||||
data.tempValue = parseInt(tempMatch[1]);
|
||||
} else if (line.includes('🗓️:')) {
|
||||
if (!parsedFields.date) {
|
||||
// console.log('[RPG Companion] → Matched DATE (emoji format)');
|
||||
const dateStr = line.replace('🗓️:', '').trim();
|
||||
const dateParts = dateStr.split(',').map(p => p.trim());
|
||||
data.weekday = dateParts[0] || '';
|
||||
data.month = dateParts[1] || '';
|
||||
data.year = dateParts[2] || '';
|
||||
data.date = dateStr;
|
||||
parsedFields.date = true;
|
||||
}
|
||||
parsedFields.temperature = true;
|
||||
}
|
||||
} else if (line.startsWith('Time:')) {
|
||||
if (!parsedFields.time) {
|
||||
// console.log('[RPG Companion] → Matched TIME (text format)');
|
||||
const timeStr = line.replace('Time:', '').trim();
|
||||
data.time = timeStr;
|
||||
const timeParts = timeStr.split('→').map(t => t.trim());
|
||||
data.timeStart = timeParts[0] || '';
|
||||
data.timeEnd = timeParts[1] || '';
|
||||
parsedFields.time = true;
|
||||
}
|
||||
} else if (line.includes('🕒:')) {
|
||||
if (!parsedFields.time) {
|
||||
// console.log('[RPG Companion] → Matched TIME (emoji format)');
|
||||
const timeStr = line.replace('🕒:', '').trim();
|
||||
data.time = timeStr;
|
||||
const timeParts = timeStr.split('→').map(t => t.trim());
|
||||
data.timeStart = timeParts[0] || '';
|
||||
data.timeEnd = timeParts[1] || '';
|
||||
parsedFields.time = true;
|
||||
}
|
||||
} else if (line.startsWith('Location:')) {
|
||||
if (!parsedFields.location) {
|
||||
// console.log('[RPG Companion] → Matched LOCATION (text format)');
|
||||
data.location = line.replace('Location:', '').trim();
|
||||
parsedFields.location = true;
|
||||
}
|
||||
} else if (line.includes('🗺️:')) {
|
||||
if (!parsedFields.location) {
|
||||
// console.log('[RPG Companion] → Matched LOCATION (emoji format)');
|
||||
data.location = line.replace('🗺️:', '').trim();
|
||||
parsedFields.location = true;
|
||||
}
|
||||
} else if (line.startsWith('Weather:')) {
|
||||
if (!parsedFields.weather) {
|
||||
// New text format: Weather: [Emoji], [Forecast] OR Weather: [Emoji][Forecast] (no separator - FIXED)
|
||||
const weatherStr = line.replace('Weather:', '').trim();
|
||||
const { emoji, text } = separateEmojiFromText(weatherStr);
|
||||
|
||||
if (emoji && text) {
|
||||
data.weatherEmoji = emoji;
|
||||
data.weatherForecast = text;
|
||||
} else if (weatherStr.includes(',')) {
|
||||
// Fallback to comma split if emoji detection failed - split only on FIRST comma
|
||||
const firstCommaIndex = weatherStr.indexOf(',');
|
||||
data.weatherEmoji = weatherStr.substring(0, firstCommaIndex).trim();
|
||||
data.weatherForecast = weatherStr.substring(firstCommaIndex + 1).trim();
|
||||
} else {
|
||||
// No clear separation - assume it's all forecast text
|
||||
data.weatherEmoji = '🌤️'; // Default emoji
|
||||
data.weatherForecast = weatherStr;
|
||||
} else if (line.startsWith('Temperature:')) {
|
||||
if (!parsedFields.temperature) {
|
||||
// console.log('[RPG Companion] → Matched TEMPERATURE (text format)');
|
||||
const tempStr = line.replace('Temperature:', '').trim();
|
||||
data.temperature = tempStr;
|
||||
const tempMatch = tempStr.match(/(-?\d+)/);
|
||||
if (tempMatch) {
|
||||
data.tempValue = parseInt(tempMatch[1]);
|
||||
}
|
||||
parsedFields.temperature = true;
|
||||
}
|
||||
} else if (line.includes('🌡️:')) {
|
||||
if (!parsedFields.temperature) {
|
||||
// console.log('[RPG Companion] → Matched TEMPERATURE (emoji format)');
|
||||
const tempStr = line.replace('🌡️:', '').trim();
|
||||
data.temperature = tempStr;
|
||||
const tempMatch = tempStr.match(/(-?\d+)/);
|
||||
if (tempMatch) {
|
||||
data.tempValue = parseInt(tempMatch[1]);
|
||||
}
|
||||
parsedFields.temperature = true;
|
||||
}
|
||||
} else if (line.startsWith('Time:')) {
|
||||
if (!parsedFields.time) {
|
||||
// console.log('[RPG Companion] → Matched TIME (text format)');
|
||||
const timeStr = line.replace('Time:', '').trim();
|
||||
data.time = timeStr;
|
||||
const timeParts = timeStr.split('→').map(t => t.trim());
|
||||
data.timeStart = timeParts[0] || '';
|
||||
data.timeEnd = timeParts[1] || '';
|
||||
parsedFields.time = true;
|
||||
}
|
||||
} else if (line.includes('🕒:')) {
|
||||
if (!parsedFields.time) {
|
||||
// console.log('[RPG Companion] → Matched TIME (emoji format)');
|
||||
const timeStr = line.replace('🕒:', '').trim();
|
||||
data.time = timeStr;
|
||||
const timeParts = timeStr.split('→').map(t => t.trim());
|
||||
data.timeStart = timeParts[0] || '';
|
||||
data.timeEnd = timeParts[1] || '';
|
||||
parsedFields.time = true;
|
||||
}
|
||||
} else if (line.startsWith('Location:')) {
|
||||
if (!parsedFields.location) {
|
||||
// console.log('[RPG Companion] → Matched LOCATION (text format)');
|
||||
data.location = line.replace('Location:', '').trim();
|
||||
parsedFields.location = true;
|
||||
}
|
||||
} else if (line.includes('🗺️:')) {
|
||||
if (!parsedFields.location) {
|
||||
// console.log('[RPG Companion] → Matched LOCATION (emoji format)');
|
||||
data.location = line.replace('🗺️:', '').trim();
|
||||
parsedFields.location = true;
|
||||
}
|
||||
} else if (line.startsWith('Weather:')) {
|
||||
if (!parsedFields.weather) {
|
||||
// New text format: Weather: [Emoji], [Forecast] OR Weather: [Emoji][Forecast] (no separator - FIXED)
|
||||
const weatherStr = line.replace('Weather:', '').trim();
|
||||
const { emoji, text } = separateEmojiFromText(weatherStr);
|
||||
|
||||
parsedFields.weather = true;
|
||||
}
|
||||
} else {
|
||||
// Check if it's a legacy weather line (emoji format)
|
||||
// Only parse if we haven't already found weather in text format
|
||||
if (!parsedFields.weather) {
|
||||
// Since \p{Emoji} doesn't work reliably, use a simpler approach
|
||||
const hasColon = line.includes(':');
|
||||
const notInfoBox = !line.includes('Info Box');
|
||||
const notDivider = !line.includes('---');
|
||||
const notCodeFence = !line.trim().startsWith('```');
|
||||
if (emoji && text) {
|
||||
data.weatherEmoji = emoji;
|
||||
data.weatherForecast = text;
|
||||
} else if (weatherStr.includes(',')) {
|
||||
// Fallback to comma split if emoji detection failed - split only on FIRST comma
|
||||
const firstCommaIndex = weatherStr.indexOf(',');
|
||||
data.weatherEmoji = weatherStr.substring(0, firstCommaIndex).trim();
|
||||
data.weatherForecast = weatherStr.substring(firstCommaIndex + 1).trim();
|
||||
} else {
|
||||
// No clear separation - assume it's all forecast text
|
||||
data.weatherEmoji = '🌤️'; // Default emoji
|
||||
data.weatherForecast = weatherStr;
|
||||
}
|
||||
|
||||
// console.log('[RPG Companion] → Checking weather conditions:', {
|
||||
// line: line,
|
||||
// hasColon: hasColon,
|
||||
// notInfoBox: notInfoBox,
|
||||
// notDivider: notDivider
|
||||
// });
|
||||
parsedFields.weather = true;
|
||||
}
|
||||
} else {
|
||||
// Check if it's a legacy weather line (emoji format)
|
||||
// Only parse if we haven't already found weather in text format
|
||||
if (!parsedFields.weather) {
|
||||
// Since \p{Emoji} doesn't work reliably, use a simpler approach
|
||||
const hasColon = line.includes(':');
|
||||
const notInfoBox = !line.includes('Info Box');
|
||||
const notDivider = !line.includes('---');
|
||||
const notCodeFence = !line.trim().startsWith('```');
|
||||
|
||||
if (hasColon && notInfoBox && notDivider && notCodeFence && line.trim().length > 0) {
|
||||
// Match format: [Weather Emoji]: [Forecast]
|
||||
// Capture everything before colon as emoji, everything after as forecast
|
||||
// console.log('[RPG Companion] → Testing WEATHER match for:', line);
|
||||
const weatherMatch = line.match(/^\s*([^:]+):\s*(.+)$/);
|
||||
if (weatherMatch) {
|
||||
const potentialEmoji = weatherMatch[1].trim();
|
||||
const forecast = weatherMatch[2].trim();
|
||||
// console.log('[RPG Companion] → Checking weather conditions:', {
|
||||
// line: line,
|
||||
// hasColon: hasColon,
|
||||
// notInfoBox: notInfoBox,
|
||||
// notDivider: notDivider
|
||||
// });
|
||||
|
||||
// If the first part is short (likely emoji), treat as weather
|
||||
if (potentialEmoji.length <= 5) {
|
||||
data.weatherEmoji = potentialEmoji;
|
||||
data.weatherForecast = forecast;
|
||||
parsedFields.weather = true;
|
||||
// console.log('[RPG Companion] ✓ Weather parsed:', data.weatherEmoji, data.weatherForecast);
|
||||
if (hasColon && notInfoBox && notDivider && notCodeFence && line.trim().length > 0) {
|
||||
// Match format: [Weather Emoji]: [Forecast]
|
||||
// Capture everything before colon as emoji, everything after as forecast
|
||||
// console.log('[RPG Companion] → Testing WEATHER match for:', line);
|
||||
const weatherMatch = line.match(/^\s*([^:]+):\s*(.+)$/);
|
||||
if (weatherMatch) {
|
||||
const potentialEmoji = weatherMatch[1].trim();
|
||||
const forecast = weatherMatch[2].trim();
|
||||
|
||||
// If the first part is short (likely emoji), treat as weather
|
||||
if (potentialEmoji.length <= 5) {
|
||||
data.weatherEmoji = potentialEmoji;
|
||||
data.weatherForecast = forecast;
|
||||
parsedFields.weather = true;
|
||||
// console.log('[RPG Companion] ✓ Weather parsed:', data.weatherEmoji, data.weatherForecast);
|
||||
} else {
|
||||
// console.log('[RPG Companion] ✗ First part too long for emoji:', potentialEmoji);
|
||||
}
|
||||
} else {
|
||||
// console.log('[RPG Companion] ✗ First part too long for emoji:', potentialEmoji);
|
||||
// console.log('[RPG Companion] ✗ Weather regex did not match');
|
||||
}
|
||||
} else {
|
||||
// console.log('[RPG Companion] ✗ Weather regex did not match');
|
||||
// console.log('[RPG Companion] → No match for this line');
|
||||
}
|
||||
} else {
|
||||
// console.log('[RPG Companion] → No match for this line');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('[RPG Companion] Parsed Info Box data:', {
|
||||
// date: data.date,
|
||||
// weatherEmoji: data.weatherEmoji,
|
||||
// weatherForecast: data.weatherForecast,
|
||||
// temperature: data.temperature,
|
||||
// timeStart: data.timeStart,
|
||||
// location: data.location
|
||||
// });
|
||||
// console.log('[RPG Companion] Parsed Info Box data:', {
|
||||
// date: data.date,
|
||||
// weatherEmoji: data.weatherEmoji,
|
||||
// weatherForecast: data.weatherForecast,
|
||||
// temperature: data.temperature,
|
||||
// timeStart: data.timeStart,
|
||||
// location: data.location
|
||||
// });
|
||||
}
|
||||
|
||||
// Get tracker configuration
|
||||
@@ -363,9 +363,9 @@ export function renderInfoBox() {
|
||||
row1Widgets.push(`
|
||||
<div class="rpg-dashboard-widget rpg-calendar-widget">
|
||||
${dateLockIconHtml}
|
||||
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" data-full-value="${data.month || ''}" title="Click to edit">${monthDisplay}</div>
|
||||
<div class="rpg-calendar-day" title="Click to edit"><span class="rpg-calendar-day-text rpg-editable" contenteditable="true" data-field="weekday" data-full-value="${data.weekday || ''}">${weekdayDisplay}</span></div>
|
||||
<div class="rpg-calendar-year rpg-editable" contenteditable="true" data-field="year" data-full-value="${data.year || ''}" title="Click to edit">${yearDisplay}</div>
|
||||
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" data-full-value="${data.month || ''}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${monthDisplay}</div>
|
||||
<div class="rpg-calendar-day" title="${i18n.getTranslation('infoBox.clickToEdit')}"><span class="rpg-calendar-day-text rpg-editable" contenteditable="true" data-field="weekday" data-full-value="${data.weekday || ''}">${weekdayDisplay}</span></div>
|
||||
<div class="rpg-calendar-year rpg-editable" contenteditable="true" data-field="year" data-full-value="${data.year || ''}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${yearDisplay}</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
@@ -373,14 +373,14 @@ export function renderInfoBox() {
|
||||
// Weather widget - show if enabled
|
||||
if (config?.widgets?.weather?.enabled) {
|
||||
const weatherEmoji = data.weatherEmoji || '🌤️';
|
||||
const weatherForecast = data.weatherForecast || 'Weather';
|
||||
const weatherForecast = data.weatherForecast || i18n.getTranslation('infoBox.weatherFallback');
|
||||
const weatherLockIconHtml = getLockIconHtml('infoBox', 'weather');
|
||||
|
||||
row1Widgets.push(`
|
||||
<div class="rpg-dashboard-widget rpg-weather-widget">
|
||||
${weatherLockIconHtml}
|
||||
<div class="rpg-weather-icon rpg-editable" contenteditable="true" data-field="weatherEmoji" title="Click to edit emoji">${weatherEmoji}</div>
|
||||
<div class="rpg-weather-forecast rpg-editable" contenteditable="true" data-field="weatherForecast" title="Click to edit">${weatherForecast}</div>
|
||||
<div class="rpg-weather-icon rpg-editable" contenteditable="true" data-field="weatherEmoji" title="${i18n.getTranslation('userStats.clickToEditEmoji')}">${weatherEmoji}</div>
|
||||
<div class="rpg-weather-forecast rpg-editable" contenteditable="true" data-field="weatherForecast" title="${i18n.getTranslation('infoBox.clickToEdit')}">${weatherForecast}</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
@@ -399,12 +399,12 @@ export function renderInfoBox() {
|
||||
|
||||
if (preferredUnit === 'F' && isCelsius) {
|
||||
// Convert C to F
|
||||
const fahrenheit = Math.round((tempValue * 9/5) + 32);
|
||||
const fahrenheit = Math.round((tempValue * 9 / 5) + 32);
|
||||
tempDisplay = `${fahrenheit}°F`;
|
||||
tempValue = fahrenheit;
|
||||
} else if (preferredUnit === 'C' && isFahrenheit) {
|
||||
// Convert F to C
|
||||
const celsius = Math.round((tempValue - 32) * 5/9);
|
||||
const celsius = Math.round((tempValue - 32) * 5 / 9);
|
||||
tempDisplay = `${celsius}°C`;
|
||||
tempValue = celsius;
|
||||
}
|
||||
@@ -415,7 +415,7 @@ export function renderInfoBox() {
|
||||
}
|
||||
|
||||
// Calculate thermometer display (convert to Celsius for consistent thresholds)
|
||||
const tempInCelsius = preferredUnit === 'F' ? Math.round((tempValue - 32) * 5/9) : tempValue;
|
||||
const tempInCelsius = preferredUnit === 'F' ? Math.round((tempValue - 32) * 5 / 9) : tempValue;
|
||||
const tempPercent = Math.min(100, Math.max(0, ((tempInCelsius + 20) / 60) * 100));
|
||||
const tempColor = tempInCelsius < 10 ? '#4a90e2' : tempInCelsius < 25 ? '#67c23a' : '#e94560';
|
||||
const tempLockIconHtml = getLockIconHtml('infoBox', 'temperature');
|
||||
@@ -429,7 +429,7 @@ export function renderInfoBox() {
|
||||
<div class="rpg-thermometer-fill" style="height: ${tempPercent}%; background: ${tempColor}"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-temp-value rpg-editable" contenteditable="true" data-field="temperature" title="Click to edit">${tempDisplay}</div>
|
||||
<div class="rpg-temp-value rpg-editable" contenteditable="true" data-field="temperature" title="${i18n.getTranslation('infoBox.clickToEdit')}">${tempDisplay}</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
@@ -464,9 +464,9 @@ export function renderInfoBox() {
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-time-range">
|
||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeStart" title="Click to edit start time">${timeStartDisplay}</div>
|
||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeStart" title="${i18n.getTranslation('infoBox.clickToEdit')}">${timeStartDisplay}</div>
|
||||
<span class="rpg-time-separator">→</span>
|
||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeEnd" title="Click to edit end time">${timeEndDisplay}</div>
|
||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeEnd" title="${i18n.getTranslation('infoBox.clickToEdit')}">${timeEndDisplay}</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
@@ -481,7 +481,7 @@ export function renderInfoBox() {
|
||||
|
||||
// Row 2: Location widget (full width) - show if enabled
|
||||
if (config?.widgets?.location?.enabled) {
|
||||
const locationDisplay = data.location || 'Location';
|
||||
const locationDisplay = data.location || i18n.getTranslation('infoBox.locationFallback');
|
||||
const locationLockIconHtml = getLockIconHtml('infoBox', 'location');
|
||||
|
||||
html += `
|
||||
@@ -491,7 +491,7 @@ export function renderInfoBox() {
|
||||
<div class="rpg-map-bg">
|
||||
<div class="rpg-map-marker">📍</div>
|
||||
</div>
|
||||
<div class="rpg-location-text rpg-editable" contenteditable="true" data-field="location" title="Click to edit">${locationDisplay}</div>
|
||||
<div class="rpg-location-text rpg-editable" contenteditable="true" data-field="location" title="${i18n.getTranslation('infoBox.clickToEdit')}">${locationDisplay}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -550,7 +550,7 @@ export function renderInfoBox() {
|
||||
html += `
|
||||
<div class="rpg-notebook-line">
|
||||
<span class="rpg-bullet">•</span>
|
||||
<span class="rpg-event-text rpg-editable" contenteditable="true" data-field="event${i + 1}" title="Click to edit">${validEvents[i]}</span>
|
||||
<span class="rpg-event-text rpg-editable" contenteditable="true" data-field="event${i + 1}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${validEvents[i]}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -591,7 +591,7 @@ export function renderInfoBox() {
|
||||
}
|
||||
|
||||
// Add event handlers for editable Info Box fields
|
||||
$infoBoxContainer.find('.rpg-editable').on('blur', function() {
|
||||
$infoBoxContainer.find('.rpg-editable').on('blur', function () {
|
||||
const $this = $(this);
|
||||
const field = $this.data('field');
|
||||
const value = $this.text().trim();
|
||||
@@ -624,12 +624,12 @@ export function renderInfoBox() {
|
||||
});
|
||||
|
||||
// Update location size on input as well (real-time)
|
||||
$infoBoxContainer.find('[data-field="location"]').on('input', function() {
|
||||
$infoBoxContainer.find('[data-field="location"]').on('input', function () {
|
||||
updateLocationTextSize($(this));
|
||||
});
|
||||
|
||||
// For date fields, show full value on focus
|
||||
$infoBoxContainer.find('[data-field="month"], [data-field="weekday"], [data-field="year"]').on('focus', function() {
|
||||
$infoBoxContainer.find('[data-field="month"], [data-field="weekday"], [data-field="year"]').on('focus', function () {
|
||||
const fullValue = $(this).data('full-value');
|
||||
if (fullValue) {
|
||||
$(this).text(fullValue);
|
||||
@@ -637,7 +637,7 @@ export function renderInfoBox() {
|
||||
});
|
||||
|
||||
// Add event handler for lock icons (support both click and touch)
|
||||
$infoBoxContainer.find('.rpg-section-lock-icon').on('click touchend', function(e) {
|
||||
$infoBoxContainer.find('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const $lockIcon = $(this);
|
||||
@@ -652,7 +652,7 @@ export function renderInfoBox() {
|
||||
|
||||
// Update icon
|
||||
$lockIcon.text(newLockState ? '🔒' : '🔓');
|
||||
$lockIcon.attr('title', newLockState ? 'Locked - AI cannot change this' : 'Unlocked - AI can change this');
|
||||
$lockIcon.attr('title', newLockState ? i18n.getTranslation('infoBox.locked') : i18n.getTranslation('infoBox.unlocked'));
|
||||
$lockIcon.toggleClass('locked', newLockState);
|
||||
|
||||
// Save settings to persist lock state
|
||||
|
||||
+157
-156
@@ -14,6 +14,7 @@ import {
|
||||
FALLBACK_AVATAR_DATA_URI,
|
||||
addDebugLog
|
||||
} from '../../core/state.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
import { saveChatData, saveSettings } from '../../core/persistence.js';
|
||||
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
|
||||
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
|
||||
@@ -30,7 +31,7 @@ function getLockIconHtml(tracker, path) {
|
||||
|
||||
const isLocked = isItemLocked(tracker, path);
|
||||
const lockIcon = isLocked ? '🔒' : '🔓';
|
||||
const lockTitle = isLocked ? 'Locked' : 'Unlocked';
|
||||
const lockTitle = isLocked ? i18n.getTranslation('thoughts.locked') : i18n.getTranslation('thoughts.unlocked');
|
||||
const lockedClass = isLocked ? ' locked' : '';
|
||||
return `<span class="rpg-section-lock-icon${lockedClass}" data-tracker="${tracker}" data-path="${path}" title="${lockTitle}">${lockIcon}</span>`;
|
||||
}
|
||||
@@ -300,88 +301,88 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
debugLog('[RPG Thoughts] Split into lines count:', lines.length);
|
||||
debugLog('[RPG Thoughts] Lines:', lines);
|
||||
|
||||
// Parse new multi-line format:
|
||||
// - [Name]
|
||||
// Details: [Emoji] | [Field1] | [Field2] | ...
|
||||
// Relationship: [Relationship]
|
||||
// Stats: Stat1: X% | Stat2: X% | ...
|
||||
// Thoughts: [Description]
|
||||
let lineNumber = 0;
|
||||
let currentCharacter = null;
|
||||
// Parse new multi-line format:
|
||||
// - [Name]
|
||||
// Details: [Emoji] | [Field1] | [Field2] | ...
|
||||
// Relationship: [Relationship]
|
||||
// Stats: Stat1: X% | Stat2: X% | ...
|
||||
// Thoughts: [Description]
|
||||
let lineNumber = 0;
|
||||
let currentCharacter = null;
|
||||
|
||||
for (const line of lines) {
|
||||
lineNumber++;
|
||||
for (const line of lines) {
|
||||
lineNumber++;
|
||||
|
||||
// Skip empty lines, headers, dividers, and code fences
|
||||
if (!line.trim() ||
|
||||
line.includes('Present Characters') ||
|
||||
line.includes('---') ||
|
||||
line.trim().startsWith('```') ||
|
||||
line.trim() === '- …' ||
|
||||
line.includes('(Repeat the format')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debugLog(`[RPG Thoughts] Processing line ${lineNumber}:`, line);
|
||||
|
||||
// Check if this is a character name line (starts with "- ")
|
||||
if (line.trim().startsWith('- ')) {
|
||||
const name = line.trim().substring(2).trim();
|
||||
|
||||
if (name && name.toLowerCase() !== 'unavailable') {
|
||||
currentCharacter = { name };
|
||||
presentCharacters.push(currentCharacter);
|
||||
debugLog(`[RPG Thoughts] ✓ Started new character: ${name}`);
|
||||
} else {
|
||||
currentCharacter = null;
|
||||
debugLog(`[RPG Thoughts] ✗ Rejected character - name: "${name}" (unavailable or empty)`);
|
||||
}
|
||||
}
|
||||
// Check if this is a Details line
|
||||
else if (line.trim().startsWith('Details:') && currentCharacter) {
|
||||
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||
const parts = detailsContent.split('|').map(p => p.trim());
|
||||
|
||||
// First part is the emoji
|
||||
if (parts.length > 0) {
|
||||
currentCharacter.emoji = parts[0];
|
||||
debugLog(`[RPG Thoughts] Parsed emoji: ${parts[0]}`);
|
||||
// Skip empty lines, headers, dividers, and code fences
|
||||
if (!line.trim() ||
|
||||
line.includes('Present Characters') ||
|
||||
line.includes('---') ||
|
||||
line.trim().startsWith('```') ||
|
||||
line.trim() === '- …' ||
|
||||
line.includes('(Repeat the format')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remaining parts are custom fields
|
||||
for (let i = 0; i < enabledFields.length && i + 1 < parts.length; i++) {
|
||||
const fieldName = enabledFields[i].name;
|
||||
currentCharacter[fieldName] = parts[i + 1];
|
||||
debugLog(`[RPG Thoughts] Parsed field ${fieldName}: ${parts[i + 1]}`);
|
||||
}
|
||||
}
|
||||
// Check if this is a Relationship line
|
||||
else if (line.trim().startsWith('Relationship:') && currentCharacter) {
|
||||
const relationship = line.substring(line.indexOf(':') + 1).trim();
|
||||
currentCharacter.Relationship = relationship;
|
||||
debugLog(`[RPG Thoughts] Parsed relationship: ${relationship}`);
|
||||
}
|
||||
// Check if this is a Stats line
|
||||
else if (line.trim().startsWith('Stats:') && currentCharacter && enabledCharStats.length > 0) {
|
||||
const statsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||
const statParts = statsContent.split('|').map(p => p.trim());
|
||||
debugLog(`[RPG Thoughts] Processing line ${lineNumber}:`, line);
|
||||
|
||||
for (const statPart of statParts) {
|
||||
const statMatch = statPart.match(/^(.+?):\s*(\d+)%$/);
|
||||
if (statMatch) {
|
||||
const statName = statMatch[1].trim();
|
||||
const statValue = parseInt(statMatch[2]);
|
||||
currentCharacter[statName] = statValue;
|
||||
debugLog(`[RPG Thoughts] Parsed stat: ${statName} = ${statValue}%`);
|
||||
// Check if this is a character name line (starts with "- ")
|
||||
if (line.trim().startsWith('- ')) {
|
||||
const name = line.trim().substring(2).trim();
|
||||
|
||||
if (name && name.toLowerCase() !== 'unavailable') {
|
||||
currentCharacter = { name };
|
||||
presentCharacters.push(currentCharacter);
|
||||
debugLog(`[RPG Thoughts] ✓ Started new character: ${name}`);
|
||||
} else {
|
||||
currentCharacter = null;
|
||||
debugLog(`[RPG Thoughts] ✗ Rejected character - name: "${name}" (unavailable or empty)`);
|
||||
}
|
||||
}
|
||||
// Check if this is a Details line
|
||||
else if (line.trim().startsWith('Details:') && currentCharacter) {
|
||||
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||
const parts = detailsContent.split('|').map(p => p.trim());
|
||||
|
||||
// First part is the emoji
|
||||
if (parts.length > 0) {
|
||||
currentCharacter.emoji = parts[0];
|
||||
debugLog(`[RPG Thoughts] Parsed emoji: ${parts[0]}`);
|
||||
}
|
||||
|
||||
// Remaining parts are custom fields
|
||||
for (let i = 0; i < enabledFields.length && i + 1 < parts.length; i++) {
|
||||
const fieldName = enabledFields[i].name;
|
||||
currentCharacter[fieldName] = parts[i + 1];
|
||||
debugLog(`[RPG Thoughts] Parsed field ${fieldName}: ${parts[i + 1]}`);
|
||||
}
|
||||
}
|
||||
// Check if this is a Relationship line
|
||||
else if (line.trim().startsWith('Relationship:') && currentCharacter) {
|
||||
const relationship = line.substring(line.indexOf(':') + 1).trim();
|
||||
currentCharacter.Relationship = relationship;
|
||||
debugLog(`[RPG Thoughts] Parsed relationship: ${relationship}`);
|
||||
}
|
||||
// Check if this is a Stats line
|
||||
else if (line.trim().startsWith('Stats:') && currentCharacter && enabledCharStats.length > 0) {
|
||||
const statsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||
const statParts = statsContent.split('|').map(p => p.trim());
|
||||
|
||||
for (const statPart of statParts) {
|
||||
const statMatch = statPart.match(/^(.+?):\s*(\d+)%$/);
|
||||
if (statMatch) {
|
||||
const statName = statMatch[1].trim();
|
||||
const statValue = parseInt(statMatch[2]);
|
||||
currentCharacter[statName] = statValue;
|
||||
debugLog(`[RPG Thoughts] Parsed stat: ${statName} = ${statValue}%`);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if this is a Thoughts line (handled separately for thought bubbles)
|
||||
else if (line.trim().match(/^[A-Z][a-z]+:/) && currentCharacter) {
|
||||
// This could be Thoughts, Feelings, etc. - skip for now, handled in thought bubble rendering
|
||||
debugLog(`[RPG Thoughts] Skipping thoughts/feelings line (handled in bubble rendering)`);
|
||||
}
|
||||
}
|
||||
// Check if this is a Thoughts line (handled separately for thought bubbles)
|
||||
else if (line.trim().match(/^[A-Z][a-z]+:/) && currentCharacter) {
|
||||
// This could be Thoughts, Feelings, etc. - skip for now, handled in thought bubble rendering
|
||||
debugLog(`[RPG Thoughts] Skipping thoughts/feelings line (handled in bubble rendering)`);
|
||||
}
|
||||
}
|
||||
} // End of text format parsing
|
||||
|
||||
// Get relationship emojis from config (with fallback defaults)
|
||||
@@ -502,14 +503,14 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
html += `
|
||||
<div class="rpg-character-card" data-character-name="${char.name}">
|
||||
<div class="rpg-character-header-row">
|
||||
<div class="rpg-character-avatar rpg-avatar-upload" data-character="${char.name}" title="Click to upload avatar">
|
||||
<div class="rpg-character-avatar rpg-avatar-upload" data-character="${char.name}" title="${i18n.getTranslation('thoughts.clickToUpload')}">
|
||||
<img src="${characterPortrait}" alt="${char.name}" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
||||
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${relationshipFieldName}" title="Click to edit (use emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
||||
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${relationshipFieldName}" title="${i18n.getTranslation('thoughts.clickToEdit')} (emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
||||
</div>
|
||||
<div class="rpg-character-header">
|
||||
<span class="rpg-character-emoji rpg-editable" contenteditable="true" data-character="${char.name}" data-field="emoji" title="Click to edit emoji">${char.emoji}</span>
|
||||
<span class="rpg-character-name rpg-editable" contenteditable="true" data-character="${char.name}" data-field="name" title="Click to edit name">${char.name}</span>
|
||||
<button class="rpg-character-remove" data-character="${char.name}" title="Remove character">×</button>
|
||||
<span class="rpg-character-emoji rpg-editable" contenteditable="true" data-character="${char.name}" data-field="emoji" title="${i18n.getTranslation('thoughts.clickToEdit')}">${char.emoji}</span>
|
||||
<span class="rpg-character-name rpg-editable" contenteditable="true" data-character="${char.name}" data-field="name" title="${i18n.getTranslation('thoughts.clickToEdit')}">${char.name}</span>
|
||||
<button class="rpg-character-remove" data-character="${char.name}" title="${i18n.getTranslation('thoughts.removeCharacter')}">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-character-content">
|
||||
@@ -532,12 +533,12 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
html += `
|
||||
<div class="rpg-character-field rpg-character-${fieldId}" style="position: relative;">
|
||||
${lockIconHtml}
|
||||
<span class="rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="Click to edit ${field.name}" ${placeholder}>${fieldValue}</span>
|
||||
<span class="rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="${i18n.getTranslation('thoughts.clickToEdit')}" ${placeholder}>${fieldValue}</span>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
html += `
|
||||
<div class="rpg-character-field rpg-character-${fieldId} rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="Click to edit ${field.name}" ${placeholder}>${fieldValue}</div>
|
||||
<div class="rpg-character-field rpg-character-${fieldId} rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="${i18n.getTranslation('thoughts.clickToEdit')}" ${placeholder}>${fieldValue}</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -563,7 +564,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
);
|
||||
html += `
|
||||
<div class="rpg-character-stat">
|
||||
<span class="rpg-stat-name">${stat.name}: </span><span class="rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${stat.name}" style="color: ${statColor}" title="Click to edit ${stat.name}">${statValue}%</span>
|
||||
<span class="rpg-stat-name">${stat.name}: </span><span class="rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${stat.name}" style="color: ${statColor}" title="${i18n.getTranslation('thoughts.clickToEdit')}">${statValue}%</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -589,8 +590,8 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
// Add "Add Character" button if data exists (inside rpg-thoughts-content)
|
||||
if (presentCharacters.length > 0) {
|
||||
html += `
|
||||
<button class="rpg-add-character-btn" title="Add a new character">
|
||||
<i class="fa-solid fa-plus"></i> Add Character
|
||||
<button class="rpg-add-character-btn" title="${i18n.getTranslation('thoughts.addCharacter')}">
|
||||
<i class="fa-solid fa-plus"></i> ${i18n.getTranslation('thoughts.addCharacter')}
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
@@ -604,7 +605,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
debugLog('[RPG Thoughts] =======================================================');
|
||||
|
||||
// Add event handlers for editable character fields
|
||||
$thoughtsContainer.find('.rpg-editable').on('blur', function() {
|
||||
$thoughtsContainer.find('.rpg-editable').on('blur', function () {
|
||||
const character = $(this).data('character');
|
||||
const field = $(this).data('field');
|
||||
const value = $(this).text().trim();
|
||||
@@ -613,12 +614,12 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
});
|
||||
|
||||
// Prevent click events on editable elements from bubbling to avatar upload handler
|
||||
$thoughtsContainer.find('.rpg-editable').on('click mousedown', function(e) {
|
||||
$thoughtsContainer.find('.rpg-editable').on('click mousedown', function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// Add event listener for section lock icon clicks (support both click and touch)
|
||||
$thoughtsContainer.find('.rpg-section-lock-icon').on('click touchend', function(e) {
|
||||
$thoughtsContainer.find('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const $icon = $(this);
|
||||
@@ -643,7 +644,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
});
|
||||
|
||||
// Add event listener for character remove button
|
||||
$thoughtsContainer.find('.rpg-character-remove').on('click', function(e) {
|
||||
$thoughtsContainer.find('.rpg-character-remove').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -652,7 +653,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
});
|
||||
|
||||
// Add event listener for avatar upload clicks
|
||||
$thoughtsContainer.find('.rpg-avatar-upload').on('click', function(e) {
|
||||
$thoughtsContainer.find('.rpg-avatar-upload').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -661,13 +662,13 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
// Create hidden file input
|
||||
const fileInput = $('<input type="file" accept="image/*" style="display: none;">');
|
||||
|
||||
fileInput.on('change', function() {
|
||||
fileInput.on('change', function () {
|
||||
const file = this.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// Read file as data URL
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
reader.onload = function (e) {
|
||||
const imageUrl = e.target.result;
|
||||
|
||||
// Store in npcAvatars
|
||||
@@ -694,20 +695,20 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
||||
});
|
||||
|
||||
// Add event listener for "Add Character" button (support both click and touch for mobile)
|
||||
$thoughtsContainer.find('.rpg-add-character-btn').on('click touchend', function(e) {
|
||||
$thoughtsContainer.find('.rpg-add-character-btn').on('click touchend', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
addNewCharacter();
|
||||
});
|
||||
|
||||
// Handle empty field focus - remove placeholder styling on focus
|
||||
$thoughtsContainer.find('.rpg-editable.rpg-empty-field').on('focus', function() {
|
||||
$thoughtsContainer.find('.rpg-editable.rpg-empty-field').on('focus', function () {
|
||||
$(this).removeClass('rpg-empty-field');
|
||||
$(this).removeAttr('data-placeholder');
|
||||
});
|
||||
|
||||
// Restore placeholder if field becomes empty on blur (after the main blur handler)
|
||||
$thoughtsContainer.find('.rpg-editable').on('blur', function() {
|
||||
$thoughtsContainer.find('.rpg-editable').on('blur', function () {
|
||||
const $this = $(this);
|
||||
if (!$this.text().trim()) {
|
||||
const field = $this.data('field');
|
||||
@@ -1494,59 +1495,59 @@ export function updateChatThoughts() {
|
||||
if (thoughtsArray.length === 0) {
|
||||
const lines = lastGeneratedData.characterThoughts.split('\n');
|
||||
|
||||
// console.log('[RPG Companion] Parsing thoughts from lines:', lines);
|
||||
// console.log('[RPG Companion] Parsing thoughts from lines:', lines);
|
||||
|
||||
// Parse new format to build character map and thoughts
|
||||
let currentCharName = null;
|
||||
let currentCharEmoji = null;
|
||||
// Parse new format to build character map and thoughts
|
||||
let currentCharName = null;
|
||||
let currentCharEmoji = null;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
|
||||
if (!line ||
|
||||
line.includes('Present Characters') ||
|
||||
line.includes('---') ||
|
||||
line.startsWith('```') ||
|
||||
line.trim() === '- …' ||
|
||||
line.includes('(Repeat the format')) {
|
||||
continue;
|
||||
}
|
||||
if (!line ||
|
||||
line.includes('Present Characters') ||
|
||||
line.includes('---') ||
|
||||
line.startsWith('```') ||
|
||||
line.trim() === '- …' ||
|
||||
line.includes('(Repeat the format')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this is a character name line (starts with "- ")
|
||||
if (line.startsWith('- ')) {
|
||||
const name = line.substring(2).trim();
|
||||
if (name && name.toLowerCase() !== 'unavailable') {
|
||||
currentCharName = name;
|
||||
currentCharEmoji = null; // Reset emoji for new character
|
||||
} else {
|
||||
currentCharName = null;
|
||||
currentCharEmoji = null;
|
||||
// Check if this is a character name line (starts with "- ")
|
||||
if (line.startsWith('- ')) {
|
||||
const name = line.substring(2).trim();
|
||||
if (name && name.toLowerCase() !== 'unavailable') {
|
||||
currentCharName = name;
|
||||
currentCharEmoji = null; // Reset emoji for new character
|
||||
} else {
|
||||
currentCharName = null;
|
||||
currentCharEmoji = null;
|
||||
}
|
||||
}
|
||||
// Check if this is a Details line (contains the emoji)
|
||||
else if (line.startsWith('Details:') && currentCharName) {
|
||||
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||
const parts = detailsContent.split('|').map(p => p.trim());
|
||||
|
||||
// First part is the emoji
|
||||
if (parts.length > 0) {
|
||||
currentCharEmoji = parts[0];
|
||||
}
|
||||
}
|
||||
// Check if this is a Thoughts line
|
||||
else if (line.startsWith(thoughtsLabel + ':') && currentCharName && currentCharEmoji) {
|
||||
const thoughtContent = line.substring(thoughtsLabel.length + 1).trim();
|
||||
|
||||
// The thought content is just the text (no emoji prefix in new format)
|
||||
if (thoughtContent) {
|
||||
thoughtsArray.push({
|
||||
name: currentCharName.toLowerCase(),
|
||||
emoji: currentCharEmoji,
|
||||
thought: thoughtContent
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if this is a Details line (contains the emoji)
|
||||
else if (line.startsWith('Details:') && currentCharName) {
|
||||
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||
const parts = detailsContent.split('|').map(p => p.trim());
|
||||
|
||||
// First part is the emoji
|
||||
if (parts.length > 0) {
|
||||
currentCharEmoji = parts[0];
|
||||
}
|
||||
}
|
||||
// Check if this is a Thoughts line
|
||||
else if (line.startsWith(thoughtsLabel + ':') && currentCharName && currentCharEmoji) {
|
||||
const thoughtContent = line.substring(thoughtsLabel.length + 1).trim();
|
||||
|
||||
// The thought content is just the text (no emoji prefix in new format)
|
||||
if (thoughtContent) {
|
||||
thoughtsArray.push({
|
||||
name: currentCharName.toLowerCase(),
|
||||
emoji: currentCharEmoji,
|
||||
thought: thoughtContent
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} // End of text format parsing for thoughts bubbles
|
||||
|
||||
debugLog('[RPG Thoughts] Parsed thoughts:', thoughtsArray);
|
||||
@@ -1628,7 +1629,7 @@ function attachDragHandlersToIcon($icon) {
|
||||
$icon.off('.thoughtIconDrag');
|
||||
|
||||
// Test: add a simple click handler to verify events work
|
||||
$icon.on('click.thoughtIconDrag', function(e) {
|
||||
$icon.on('click.thoughtIconDrag', function (e) {
|
||||
// Check global flag set immediately after drag completes
|
||||
if (justFinishedDragging) {
|
||||
// console.log('[Thought Icon] CLICK blocked - just finished dragging');
|
||||
@@ -1641,7 +1642,7 @@ function attachDragHandlersToIcon($icon) {
|
||||
});
|
||||
|
||||
// Touch drag support - mobile only
|
||||
$icon.on('touchstart.thoughtIconDrag', function(e) {
|
||||
$icon.on('touchstart.thoughtIconDrag', function (e) {
|
||||
if (window.innerWidth > 1000) return;
|
||||
|
||||
// console.log('[Thought Icon] touchstart');
|
||||
@@ -1658,7 +1659,7 @@ function attachDragHandlersToIcon($icon) {
|
||||
isDragging = false;
|
||||
});
|
||||
|
||||
$icon.on('touchmove.thoughtIconDrag', function(e) {
|
||||
$icon.on('touchmove.thoughtIconDrag', function (e) {
|
||||
if (window.innerWidth > 1000) return;
|
||||
|
||||
if (!touchMoved) {
|
||||
@@ -1701,7 +1702,7 @@ function attachDragHandlersToIcon($icon) {
|
||||
}
|
||||
});
|
||||
|
||||
$icon.on('touchend.thoughtIconDrag', function(e) {
|
||||
$icon.on('touchend.thoughtIconDrag', function (e) {
|
||||
// console.log('[Thought Icon] touchend - isDragging:', isDragging, 'touchMoved:', touchMoved);
|
||||
|
||||
if (isDragging) {
|
||||
@@ -1756,7 +1757,7 @@ function attachDragHandlersToIcon($icon) {
|
||||
// Mouse drag support - mobile only
|
||||
let mouseDown = false;
|
||||
|
||||
$icon.on('mousedown.thoughtIconDrag', function(e) {
|
||||
$icon.on('mousedown.thoughtIconDrag', function (e) {
|
||||
if (window.innerWidth > 1000) return;
|
||||
|
||||
// console.log('[Thought Icon] mousedown');
|
||||
@@ -1775,7 +1776,7 @@ function attachDragHandlersToIcon($icon) {
|
||||
isDragging = false;
|
||||
});
|
||||
|
||||
$(document).on('mousemove.thoughtIconDrag', function(e) {
|
||||
$(document).on('mousemove.thoughtIconDrag', function (e) {
|
||||
if (!mouseDown || window.innerWidth > 1000) return;
|
||||
|
||||
if (!touchMoved) {
|
||||
@@ -1819,7 +1820,7 @@ function attachDragHandlersToIcon($icon) {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('mouseup.thoughtIconDrag', function(e) {
|
||||
$(document).on('mouseup.thoughtIconDrag', function (e) {
|
||||
if (!mouseDown) return;
|
||||
|
||||
// console.log('[Thought Icon] mouseup - isDragging:', isDragging, 'touchMoved:', touchMoved);
|
||||
@@ -2222,7 +2223,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
||||
});
|
||||
|
||||
// Close button functionality - support both click and touch
|
||||
$thoughtPanel.find('.rpg-thought-close').on('click touchend', function(e) {
|
||||
$thoughtPanel.find('.rpg-thought-close').on('click touchend', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -2230,7 +2231,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
||||
|
||||
if (isMobileView) {
|
||||
// Mobile: hide panel and show icon
|
||||
$thoughtPanel.fadeOut(200, function() {
|
||||
$thoughtPanel.fadeOut(200, function () {
|
||||
// Make sure icon is visible and clean state when panel closes (use selector, not variable)
|
||||
const $icon = $('#rpg-thought-icon');
|
||||
$icon.removeClass('rpg-hidden dragging');
|
||||
@@ -2252,14 +2253,14 @@ export function createThoughtPanel($message, thoughtsArray) {
|
||||
$icon.addClass('rpg-collapsed-desktop');
|
||||
|
||||
// Hide panel and show icon
|
||||
$thoughtPanel.fadeOut(200, function() {
|
||||
$thoughtPanel.fadeOut(200, function () {
|
||||
$icon.removeClass('rpg-hidden rpg-force-hide');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Icon click/tap to show panel
|
||||
const handleThoughtIconTap = function(e) {
|
||||
const handleThoughtIconTap = function (e) {
|
||||
const isMobileView = window.innerWidth <= 1000;
|
||||
const $icon = $('#rpg-thought-icon');
|
||||
|
||||
@@ -2303,7 +2304,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
||||
$thoughtIcon.on('click touchend', handleThoughtIconTap);
|
||||
|
||||
// Add event handlers for editable thoughts in the bubble
|
||||
$thoughtPanel.find('.rpg-editable').on('blur', function() {
|
||||
$thoughtPanel.find('.rpg-editable').on('blur', function () {
|
||||
const character = $(this).data('character');
|
||||
const field = $(this).data('field');
|
||||
const value = $(this).text().trim();
|
||||
@@ -2312,7 +2313,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
||||
});
|
||||
|
||||
// Add event listener for section lock icon clicks (support both click and touch)
|
||||
$thoughtPanel.find('.rpg-section-lock-icon').on('click touchend', function(e) {
|
||||
$thoughtPanel.find('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const $icon = $(this);
|
||||
@@ -2363,7 +2364,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
||||
// Position stays fixed at top-left
|
||||
|
||||
// Remove panel when clicking outside (mobile only)
|
||||
$(document).on('click.thoughtPanel', function(e) {
|
||||
$(document).on('click.thoughtPanel', function (e) {
|
||||
// Only hide on click outside in mobile view
|
||||
if (window.innerWidth <= 1000) {
|
||||
if (!$(e.target).closest('#rpg-thought-panel, #rpg-thought-icon').length) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
$userStatsContainer,
|
||||
FALLBACK_AVATAR_DATA_URI
|
||||
} from '../../core/state.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
import {
|
||||
saveSettings,
|
||||
saveChatData,
|
||||
@@ -273,7 +274,7 @@ export function renderUserStats() {
|
||||
// Check if stats bars section is locked
|
||||
const isStatsLocked = isItemLocked('userStats', 'stats');
|
||||
const lockIcon = isStatsLocked ? '🔒' : '🔓';
|
||||
const lockTitle = isStatsLocked ? 'Locked - AI cannot change stats' : 'Unlocked - AI can change stats';
|
||||
const lockTitle = isStatsLocked ? i18n.getTranslation('userStats.statsLocked') : i18n.getTranslation('userStats.statsUnlocked');
|
||||
const lockedClass = isStatsLocked ? ' locked' : '';
|
||||
|
||||
let html = '<div class="rpg-stats-content">';
|
||||
@@ -286,8 +287,8 @@ export function renderUserStats() {
|
||||
<img src="${userPortrait}" alt="${userName}" class="rpg-user-portrait" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
||||
<span class="rpg-user-name">${userName}</span>
|
||||
${showLevel ? `<span style="opacity: 0.5;">|</span>
|
||||
<span class="rpg-level-label">LVL</span>
|
||||
<span class="rpg-level-value rpg-editable" contenteditable="true" data-field="level" title="Click to edit level">${extensionSettings.level}</span>` : ''}
|
||||
<span class="rpg-level-label">${i18n.getTranslation('userStats.level')}</span>
|
||||
<span class="rpg-level-value rpg-editable" contenteditable="true" data-field="level" title="${i18n.getTranslation('userStats.clickToEditLevel')}">${extensionSettings.level}</span>` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -320,11 +321,11 @@ export function renderUserStats() {
|
||||
|
||||
html += `
|
||||
<div class="rpg-stat-row">
|
||||
<span class="rpg-stat-label rpg-editable-stat-name" contenteditable="true" data-field="${stat.id}" title="Click to edit stat name">${stat.name}:</span>
|
||||
<span class="rpg-stat-label rpg-editable-stat-name" contenteditable="true" data-field="${stat.id}" title="${i18n.getTranslation('userStats.clickToEditStatName')}">${stat.name}:</span>
|
||||
<div class="rpg-stat-bar" style="background: ${gradient}">
|
||||
<div class="rpg-stat-fill" style="width: ${100 - percentage}%"></div>
|
||||
</div>
|
||||
<span class="rpg-stat-value rpg-editable-stat" contenteditable="true" data-field="${stat.id}" data-max="${maxValue}" data-mode="${displayMode}" title="Click to edit">${displayValue}</span>
|
||||
<span class="rpg-stat-value rpg-editable-stat" contenteditable="true" data-field="${stat.id}" data-max="${maxValue}" data-mode="${displayMode}" title="${i18n.getTranslation('userStats.clickToEditStatValue')}">${displayValue}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -334,7 +335,7 @@ export function renderUserStats() {
|
||||
if (config.statusSection.enabled) {
|
||||
const isMoodLocked = isItemLocked('userStats', 'status');
|
||||
const moodLockIcon = isMoodLocked ? '🔒' : '🔓';
|
||||
const moodLockTitle = isMoodLocked ? 'Locked - AI cannot change mood' : 'Unlocked - AI can change mood';
|
||||
const moodLockTitle = isMoodLocked ? i18n.getTranslation('userStats.moodLocked') : i18n.getTranslation('userStats.moodUnlocked');
|
||||
const moodLockedClass = isMoodLocked ? ' locked' : '';
|
||||
html += '<div class="rpg-mood">';
|
||||
if (showLockIcons) {
|
||||
@@ -342,7 +343,7 @@ export function renderUserStats() {
|
||||
}
|
||||
|
||||
if (config.statusSection.showMoodEmoji) {
|
||||
html += `<div class="rpg-mood-emoji rpg-editable" contenteditable="true" data-field="mood" title="Click to edit emoji">${stats.mood}</div>`;
|
||||
html += `<div class="rpg-mood-emoji rpg-editable" contenteditable="true" data-field="mood" title="${i18n.getTranslation('userStats.clickToEditEmoji')}">${stats.mood}</div>`;
|
||||
}
|
||||
|
||||
// Render custom status fields
|
||||
@@ -368,7 +369,7 @@ export function renderUserStats() {
|
||||
if (config.skillsSection.enabled) {
|
||||
const isSkillsLocked = isItemLocked('userStats', 'skills');
|
||||
const skillsLockIcon = isSkillsLocked ? '🔒' : '🔓';
|
||||
const skillsLockTitle = isSkillsLocked ? 'Locked - AI cannot change skills' : 'Unlocked - AI can change skills';
|
||||
const skillsLockTitle = isSkillsLocked ? i18n.getTranslation('userStats.skillsLocked') : i18n.getTranslation('userStats.skillsUnlocked');
|
||||
const skillsLockedClass = isSkillsLocked ? ' locked' : '';
|
||||
let skillsValue = 'None';
|
||||
// Handle JSON array format: [{name: "Art"}, {name: "Coding"}]
|
||||
@@ -385,7 +386,7 @@ export function renderUserStats() {
|
||||
}
|
||||
html += `
|
||||
<span class="rpg-skills-label">${config.skillsSection.label}:</span>
|
||||
<div class="rpg-skills-value rpg-editable" contenteditable="true" data-field="skills" title="Click to edit skills">${skillsValue}</div>
|
||||
<div class="rpg-skills-value rpg-editable" contenteditable="true" data-field="skills" title="${i18n.getTranslation('userStats.clickToEditSkills')}">${skillsValue}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -409,15 +410,15 @@ export function renderUserStats() {
|
||||
const enabledAttributes = rpgAttributes.filter(attr => attr && attr.enabled && attr.name && attr.id);
|
||||
|
||||
if (enabledAttributes.length > 0) {
|
||||
html += `
|
||||
html += `
|
||||
<div class="rpg-stats-right">
|
||||
<div class="rpg-classic-stats">
|
||||
<div class="rpg-classic-stats-grid">
|
||||
`;
|
||||
|
||||
enabledAttributes.forEach(attr => {
|
||||
const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10;
|
||||
html += `
|
||||
enabledAttributes.forEach(attr => {
|
||||
const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10;
|
||||
html += `
|
||||
<div class="rpg-classic-stat" data-stat="${attr.id}">
|
||||
<span class="rpg-classic-stat-label">${attr.name}</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
@@ -427,9 +428,9 @@ export function renderUserStats() {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
});
|
||||
|
||||
html += `
|
||||
html += `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -448,7 +449,7 @@ export function renderUserStats() {
|
||||
// console.log('[RPG UserStats Render] ✓ HTML rendered to #rpg-user-stats container');
|
||||
|
||||
// Add event listeners for editable stat values
|
||||
$('.rpg-editable-stat').on('blur', function() {
|
||||
$('.rpg-editable-stat').on('blur', function () {
|
||||
const field = $(this).data('field');
|
||||
const mode = $(this).data('mode');
|
||||
const maxValue = parseInt($(this).data('max')) || 100;
|
||||
@@ -492,7 +493,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listeners for mood/conditions editing
|
||||
$('.rpg-mood-emoji.rpg-editable').on('blur', function() {
|
||||
$('.rpg-mood-emoji.rpg-editable').on('blur', function () {
|
||||
const value = $(this).text().trim();
|
||||
extensionSettings.userStats.mood = value || '😐';
|
||||
|
||||
@@ -504,7 +505,7 @@ export function renderUserStats() {
|
||||
updateMessageSwipeData();
|
||||
});
|
||||
|
||||
$('.rpg-mood-conditions.rpg-editable').on('blur', function() {
|
||||
$('.rpg-mood-conditions.rpg-editable').on('blur', function () {
|
||||
const value = $(this).text().trim();
|
||||
const fieldKey = $(this).data('field');
|
||||
extensionSettings.userStats[fieldKey] = value || 'None';
|
||||
@@ -518,7 +519,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listener for skills editing
|
||||
$('.rpg-skills-value.rpg-editable').on('blur', function() {
|
||||
$('.rpg-skills-value.rpg-editable').on('blur', function () {
|
||||
const value = $(this).text().trim();
|
||||
extensionSettings.userStats.skills = value || 'None';
|
||||
|
||||
@@ -531,7 +532,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listeners for stat name editing
|
||||
$('.rpg-editable-stat-name').on('blur', function() {
|
||||
$('.rpg-editable-stat-name').on('blur', function () {
|
||||
const field = $(this).data('field');
|
||||
const value = $(this).text().trim().replace(':', '');
|
||||
|
||||
@@ -555,7 +556,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listener for level editing
|
||||
$('.rpg-level-value.rpg-editable').on('blur', function() {
|
||||
$('.rpg-level-value.rpg-editable').on('blur', function () {
|
||||
let value = parseInt($(this).text().trim());
|
||||
if (isNaN(value) || value < 1) {
|
||||
value = 1;
|
||||
@@ -573,15 +574,15 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Prevent line breaks in level field
|
||||
$('.rpg-level-value.rpg-editable').on('keydown', function(e) {
|
||||
$('.rpg-level-value.rpg-editable').on('keydown', function (e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
$(this).blur();
|
||||
}
|
||||
});
|
||||
|
||||
// Add event listener for section lock icon clicks (support both click and touch)
|
||||
$('.rpg-section-lock-icon').on('click touchend', function(e) {
|
||||
// Add event listener for section lock icon clicks (support both click and touch)
|
||||
$('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const $icon = $(this);
|
||||
@@ -594,7 +595,7 @@ export function renderUserStats() {
|
||||
|
||||
// Update icon
|
||||
const newIcon = !currentlyLocked ? '🔒' : '🔓';
|
||||
const newTitle = !currentlyLocked ? 'Locked - AI cannot change this section' : 'Unlocked - AI can change this section';
|
||||
const newTitle = !currentlyLocked ? i18n.getTranslation('infoBox.locked') : i18n.getTranslation('infoBox.unlocked');
|
||||
$icon.text(newIcon);
|
||||
$icon.attr('title', newTitle);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export function initTrackerEditor() {
|
||||
}
|
||||
|
||||
// Tab switching
|
||||
$(document).on('click', '.rpg-editor-tab', function() {
|
||||
$(document).on('click', '.rpg-editor-tab', function () {
|
||||
$('.rpg-editor-tab').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
@@ -61,51 +61,51 @@ export function initTrackerEditor() {
|
||||
});
|
||||
|
||||
// Save button
|
||||
$(document).on('click', '#rpg-editor-save', function() {
|
||||
$(document).on('click', '#rpg-editor-save', function () {
|
||||
applyTrackerConfig();
|
||||
closeTrackerEditor();
|
||||
});
|
||||
|
||||
// Cancel button
|
||||
$(document).on('click', '#rpg-editor-cancel', function() {
|
||||
$(document).on('click', '#rpg-editor-cancel', function () {
|
||||
closeTrackerEditor();
|
||||
});
|
||||
|
||||
// Close X button
|
||||
$(document).on('click', '#rpg-close-tracker-editor', function() {
|
||||
$(document).on('click', '#rpg-close-tracker-editor', function () {
|
||||
closeTrackerEditor();
|
||||
});
|
||||
|
||||
// Reset button
|
||||
$(document).on('click', '#rpg-editor-reset', function() {
|
||||
$(document).on('click', '#rpg-editor-reset', function () {
|
||||
resetToDefaults();
|
||||
renderEditorUI();
|
||||
});
|
||||
|
||||
// Close on background click
|
||||
$(document).on('click', '#rpg-tracker-editor-popup', function(e) {
|
||||
$(document).on('click', '#rpg-tracker-editor-popup', function (e) {
|
||||
if (e.target.id === 'rpg-tracker-editor-popup') {
|
||||
closeTrackerEditor();
|
||||
}
|
||||
});
|
||||
|
||||
// Open button
|
||||
$(document).on('click', '#rpg-open-tracker-editor', function() {
|
||||
$(document).on('click', '#rpg-open-tracker-editor', function () {
|
||||
openTrackerEditor();
|
||||
});
|
||||
|
||||
// Export button
|
||||
$(document).on('click', '#rpg-editor-export', function() {
|
||||
$(document).on('click', '#rpg-editor-export', function () {
|
||||
exportTrackerPreset();
|
||||
});
|
||||
|
||||
// Import button
|
||||
$(document).on('click', '#rpg-editor-import', function() {
|
||||
$(document).on('click', '#rpg-editor-import', function () {
|
||||
importTrackerPreset();
|
||||
});
|
||||
|
||||
// Preset select change
|
||||
$(document).on('change', '#rpg-preset-select', function() {
|
||||
$(document).on('change', '#rpg-preset-select', function () {
|
||||
const presetId = $(this).val();
|
||||
if (presetId && presetId !== getActivePresetId()) {
|
||||
// Check if the current character had an association (either original or pending)
|
||||
@@ -139,7 +139,7 @@ export function initTrackerEditor() {
|
||||
});
|
||||
|
||||
// New preset button
|
||||
$(document).on('click', '#rpg-preset-new', function() {
|
||||
$(document).on('click', '#rpg-preset-new', function () {
|
||||
const name = prompt('Enter a name for the new preset:');
|
||||
if (name && name.trim()) {
|
||||
const newId = createPreset(name.trim());
|
||||
@@ -150,7 +150,7 @@ export function initTrackerEditor() {
|
||||
});
|
||||
|
||||
// Set as default preset button
|
||||
$(document).on('click', '#rpg-preset-default', function() {
|
||||
$(document).on('click', '#rpg-preset-default', function () {
|
||||
const currentPresetId = getActivePresetId();
|
||||
if (currentPresetId) {
|
||||
setDefaultPreset(currentPresetId);
|
||||
@@ -161,7 +161,7 @@ export function initTrackerEditor() {
|
||||
});
|
||||
|
||||
// Delete preset button
|
||||
$(document).on('click', '#rpg-preset-delete', function() {
|
||||
$(document).on('click', '#rpg-preset-delete', function () {
|
||||
const currentPresetId = getActivePresetId();
|
||||
const presets = getPresets();
|
||||
if (Object.keys(presets).length <= 1) {
|
||||
@@ -180,7 +180,7 @@ export function initTrackerEditor() {
|
||||
});
|
||||
|
||||
// Associate preset checkbox
|
||||
$(document).on('change', '#rpg-preset-associate', function() {
|
||||
$(document).on('change', '#rpg-preset-associate', function () {
|
||||
const activePresetId = getActivePresetId();
|
||||
const preset = getPreset(activePresetId);
|
||||
const entityName = getCurrentEntityName();
|
||||
@@ -334,20 +334,20 @@ function resetToDefaults() {
|
||||
extensionSettings.trackerConfig = {
|
||||
userStats: {
|
||||
customStats: [
|
||||
{ id: 'health', name: 'Health', enabled: true, persistInHistory: false },
|
||||
{ id: 'satiety', name: 'Satiety', enabled: true, persistInHistory: false },
|
||||
{ id: 'energy', name: 'Energy', enabled: true, persistInHistory: false },
|
||||
{ id: 'hygiene', name: 'Hygiene', enabled: true, persistInHistory: false },
|
||||
{ id: 'arousal', name: 'Arousal', enabled: true, persistInHistory: false }
|
||||
{ id: 'health', name: i18n.getTranslation('stats.health'), enabled: true, persistInHistory: false },
|
||||
{ id: 'satiety', name: i18n.getTranslation('stats.satiety'), enabled: true, persistInHistory: false },
|
||||
{ id: 'energy', name: i18n.getTranslation('stats.energy'), enabled: true, persistInHistory: false },
|
||||
{ id: 'hygiene', name: i18n.getTranslation('stats.hygiene'), enabled: true, persistInHistory: false },
|
||||
{ id: 'arousal', name: i18n.getTranslation('stats.arousal'), enabled: true, persistInHistory: false }
|
||||
],
|
||||
showRPGAttributes: true,
|
||||
rpgAttributes: [
|
||||
{ id: 'str', name: 'STR', enabled: true, persistInHistory: false },
|
||||
{ id: 'dex', name: 'DEX', enabled: true, persistInHistory: false },
|
||||
{ id: 'con', name: 'CON', enabled: true, persistInHistory: false },
|
||||
{ id: 'int', name: 'INT', enabled: true, persistInHistory: false },
|
||||
{ id: 'wis', name: 'WIS', enabled: true, persistInHistory: false },
|
||||
{ id: 'cha', name: 'CHA', enabled: true, persistInHistory: false }
|
||||
{ id: 'str', name: i18n.getTranslation('stats.str'), enabled: true, persistInHistory: false },
|
||||
{ id: 'dex', name: i18n.getTranslation('stats.dex'), enabled: true, persistInHistory: false },
|
||||
{ id: 'con', name: i18n.getTranslation('stats.con'), enabled: true, persistInHistory: false },
|
||||
{ id: 'int', name: i18n.getTranslation('stats.int'), enabled: true, persistInHistory: false },
|
||||
{ id: 'wis', name: i18n.getTranslation('stats.wis'), enabled: true, persistInHistory: false },
|
||||
{ id: 'cha', name: i18n.getTranslation('stats.cha'), enabled: true, persistInHistory: false }
|
||||
],
|
||||
statusSection: {
|
||||
enabled: true,
|
||||
@@ -408,8 +408,8 @@ function resetToDefaults() {
|
||||
characterStats: {
|
||||
enabled: false,
|
||||
customStats: [
|
||||
{ id: 'health', name: 'Health', enabled: true, colorLow: '#ff4444', colorHigh: '#44ff44' },
|
||||
{ id: 'energy', name: 'Energy', enabled: true, colorLow: '#ffaa00', colorHigh: '#44ffff' }
|
||||
{ id: 'health', name: i18n.getTranslation('stats.health'), enabled: true, colorLow: '#ff4444', colorHigh: '#44ff44' },
|
||||
{ id: 'energy', name: i18n.getTranslation('stats.energy'), enabled: true, colorLow: '#ffaa00', colorHigh: '#44ffff' }
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -854,7 +854,7 @@ function renderUserStatsTab() {
|
||||
*/
|
||||
function setupUserStatsListeners() {
|
||||
// Add stat
|
||||
$('#rpg-add-stat').off('click').on('click', function() {
|
||||
$('#rpg-add-stat').off('click').on('click', function () {
|
||||
const newId = 'custom_' + Date.now();
|
||||
extensionSettings.trackerConfig.userStats.customStats.push({
|
||||
id: newId,
|
||||
@@ -870,39 +870,39 @@ function setupUserStatsListeners() {
|
||||
});
|
||||
|
||||
// Remove stat
|
||||
$('.rpg-stat-remove').off('click').on('click', function() {
|
||||
$('.rpg-stat-remove').off('click').on('click', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.customStats.splice(index, 1);
|
||||
renderUserStatsTab();
|
||||
});
|
||||
|
||||
// Toggle stat
|
||||
$('.rpg-stat-toggle').off('change').on('change', function() {
|
||||
$('.rpg-stat-toggle').off('change').on('change', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.customStats[index].enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Rename stat
|
||||
$('.rpg-stat-name').off('blur').on('blur', function() {
|
||||
$('.rpg-stat-name').off('blur').on('blur', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.customStats[index].name = $(this).val();
|
||||
});
|
||||
|
||||
// Change stat max value
|
||||
$('.rpg-stat-max').off('blur').on('blur', function() {
|
||||
$('.rpg-stat-max').off('blur').on('blur', function () {
|
||||
const index = $(this).data('index');
|
||||
const value = parseInt($(this).val()) || 100;
|
||||
extensionSettings.trackerConfig.userStats.customStats[index].maxValue = Math.max(1, value);
|
||||
});
|
||||
|
||||
// Stats display mode toggle
|
||||
$('input[name="stats-display-mode"]').off('change').on('change', function() {
|
||||
$('input[name="stats-display-mode"]').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.statsDisplayMode = $(this).val();
|
||||
renderUserStatsTab(); // Re-render to show/hide max value fields
|
||||
});
|
||||
|
||||
// Add attribute
|
||||
$('#rpg-add-attr').off('click').on('click', function() {
|
||||
$('#rpg-add-attr').off('click').on('click', function () {
|
||||
// Ensure rpgAttributes array exists with defaults if needed
|
||||
if (!extensionSettings.trackerConfig.userStats.rpgAttributes || extensionSettings.trackerConfig.userStats.rpgAttributes.length === 0) {
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes = [
|
||||
@@ -928,64 +928,64 @@ function setupUserStatsListeners() {
|
||||
});
|
||||
|
||||
// Remove attribute
|
||||
$('.rpg-attr-remove').off('click').on('click', function() {
|
||||
$('.rpg-attr-remove').off('click').on('click', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes.splice(index, 1);
|
||||
renderUserStatsTab();
|
||||
});
|
||||
|
||||
// Toggle attribute
|
||||
$('.rpg-attr-toggle').off('change').on('change', function() {
|
||||
$('.rpg-attr-toggle').off('change').on('change', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes[index].enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Rename attribute
|
||||
$('.rpg-attr-name').off('blur').on('blur', function() {
|
||||
$('.rpg-attr-name').off('blur').on('blur', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes[index].name = $(this).val();
|
||||
});
|
||||
|
||||
// Enable/disable RPG Attributes section toggle
|
||||
$('#rpg-show-rpg-attrs').off('change').on('change', function() {
|
||||
$('#rpg-show-rpg-attrs').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.showRPGAttributes = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Show/hide level toggle
|
||||
$('#rpg-show-level').off('change').on('change', function() {
|
||||
$('#rpg-show-level').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.showLevel = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Always send attributes toggle
|
||||
$('#rpg-always-send-attrs').off('change').on('change', function() {
|
||||
$('#rpg-always-send-attrs').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.alwaysSendAttributes = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Status section toggles
|
||||
$('#rpg-status-enabled').off('change').on('change', function() {
|
||||
$('#rpg-status-enabled').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.statusSection.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-mood-emoji').off('change').on('change', function() {
|
||||
$('#rpg-mood-emoji').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.statusSection.showMoodEmoji = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-status-fields').off('blur').on('blur', function() {
|
||||
$('#rpg-status-fields').off('blur').on('blur', function () {
|
||||
const fields = $(this).val().split(',').map(f => f.trim()).filter(f => f);
|
||||
extensionSettings.trackerConfig.userStats.statusSection.customFields = fields;
|
||||
});
|
||||
|
||||
// Skills section toggles
|
||||
$('#rpg-skills-enabled').off('change').on('change', function() {
|
||||
$('#rpg-skills-enabled').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.skillsSection.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-skills-label').off('blur').on('blur', function() {
|
||||
$('#rpg-skills-label').off('blur').on('blur', function () {
|
||||
extensionSettings.trackerConfig.userStats.skillsSection.label = $(this).val();
|
||||
saveSettings();
|
||||
});
|
||||
|
||||
$('#rpg-skills-fields').off('blur').on('blur', function() {
|
||||
$('#rpg-skills-fields').off('blur').on('blur', function () {
|
||||
const fields = $(this).val().split(',').map(f => f.trim()).filter(f => f);
|
||||
extensionSettings.trackerConfig.userStats.skillsSection.customFields = fields;
|
||||
saveSettings();
|
||||
@@ -1057,35 +1057,35 @@ function renderInfoBoxTab() {
|
||||
function setupInfoBoxListeners() {
|
||||
const widgets = extensionSettings.trackerConfig.infoBox.widgets;
|
||||
|
||||
$('#rpg-widget-date').off('change').on('change', function() {
|
||||
$('#rpg-widget-date').off('change').on('change', function () {
|
||||
widgets.date.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-date-format').off('change').on('change', function() {
|
||||
$('#rpg-date-format').off('change').on('change', function () {
|
||||
widgets.date.format = $(this).val();
|
||||
});
|
||||
|
||||
$('#rpg-widget-weather').off('change').on('change', function() {
|
||||
$('#rpg-widget-weather').off('change').on('change', function () {
|
||||
widgets.weather.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-widget-temperature').off('change').on('change', function() {
|
||||
$('#rpg-widget-temperature').off('change').on('change', function () {
|
||||
widgets.temperature.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('input[name="temp-unit"]').off('change').on('change', function() {
|
||||
$('input[name="temp-unit"]').off('change').on('change', function () {
|
||||
widgets.temperature.unit = $(this).val();
|
||||
});
|
||||
|
||||
$('#rpg-widget-time').off('change').on('change', function() {
|
||||
$('#rpg-widget-time').off('change').on('change', function () {
|
||||
widgets.time.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-widget-location').off('change').on('change', function() {
|
||||
$('#rpg-widget-location').off('change').on('change', function () {
|
||||
widgets.location.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-widget-events').off('change').on('change', function() {
|
||||
$('#rpg-widget-events').off('change').on('change', function () {
|
||||
widgets.recentEvents.enabled = $(this).is(':checked');
|
||||
});
|
||||
}
|
||||
@@ -1209,7 +1209,7 @@ function renderPresentCharactersTab() {
|
||||
*/
|
||||
function setupPresentCharactersListeners() {
|
||||
// Relationships enabled toggle
|
||||
$('#rpg-relationships-enabled').off('change').on('change', function() {
|
||||
$('#rpg-relationships-enabled').off('change').on('change', function () {
|
||||
if (!extensionSettings.trackerConfig.presentCharacters.relationships) {
|
||||
extensionSettings.trackerConfig.presentCharacters.relationships = { enabled: true, relationshipEmojis: {} };
|
||||
}
|
||||
@@ -1217,7 +1217,7 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Add new relationship
|
||||
$('#rpg-add-relationship').off('click').on('click', function() {
|
||||
$('#rpg-add-relationship').off('click').on('click', function () {
|
||||
// Ensure relationships object exists
|
||||
if (!extensionSettings.trackerConfig.presentCharacters.relationships) {
|
||||
extensionSettings.trackerConfig.presentCharacters.relationships = { enabled: true, relationshipEmojis: {} };
|
||||
@@ -1254,7 +1254,7 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Remove relationship
|
||||
$('.rpg-remove-relationship').off('click').on('click', function() {
|
||||
$('.rpg-remove-relationship').off('click').on('click', function () {
|
||||
const relationship = $(this).data('relationship');
|
||||
|
||||
// Remove from new structure
|
||||
@@ -1275,7 +1275,7 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Update relationship name
|
||||
$('.rpg-relationship-name').off('blur').on('blur', function() {
|
||||
$('.rpg-relationship-name').off('blur').on('blur', function () {
|
||||
const newName = $(this).val();
|
||||
const $item = $(this).closest('.rpg-relationship-item');
|
||||
const emoji = $item.find('.rpg-relationship-emoji').val();
|
||||
@@ -1309,7 +1309,7 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Update relationship emoji
|
||||
$('.rpg-relationship-emoji').off('blur').on('blur', function() {
|
||||
$('.rpg-relationship-emoji').off('blur').on('blur', function () {
|
||||
const name = $(this).closest('.rpg-relationship-item').find('.rpg-relationship-name').val();
|
||||
|
||||
// Ensure structures exist
|
||||
@@ -1326,21 +1326,21 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Thoughts configuration
|
||||
$('#rpg-thoughts-enabled').off('change').on('change', function() {
|
||||
$('#rpg-thoughts-enabled').off('change').on('change', function () {
|
||||
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
||||
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
||||
}
|
||||
extensionSettings.trackerConfig.presentCharacters.thoughts.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
$('#rpg-thoughts-name').off('blur').on('blur', function() {
|
||||
$('#rpg-thoughts-name').off('blur').on('blur', function () {
|
||||
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
||||
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
||||
}
|
||||
extensionSettings.trackerConfig.presentCharacters.thoughts.name = $(this).val();
|
||||
});
|
||||
|
||||
$('#rpg-thoughts-description').off('blur').on('blur', function() {
|
||||
$('#rpg-thoughts-description').off('blur').on('blur', function () {
|
||||
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
||||
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
||||
}
|
||||
@@ -1348,7 +1348,7 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Add field
|
||||
$('#rpg-add-field').off('click').on('click', function() {
|
||||
$('#rpg-add-field').off('click').on('click', function () {
|
||||
extensionSettings.trackerConfig.presentCharacters.customFields.push({
|
||||
id: 'custom_' + Date.now(),
|
||||
name: 'New Field',
|
||||
@@ -1359,14 +1359,14 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Remove field
|
||||
$('.rpg-field-remove').off('click').on('click', function() {
|
||||
$('.rpg-field-remove').off('click').on('click', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.customFields.splice(index, 1);
|
||||
renderPresentCharactersTab();
|
||||
});
|
||||
|
||||
// Move field up
|
||||
$('.rpg-field-move-up').off('click').on('click', function() {
|
||||
$('.rpg-field-move-up').off('click').on('click', function () {
|
||||
const index = $(this).data('index');
|
||||
if (index > 0) {
|
||||
const fields = extensionSettings.trackerConfig.presentCharacters.customFields;
|
||||
@@ -1376,7 +1376,7 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Move field down
|
||||
$('.rpg-field-move-down').off('click').on('click', function() {
|
||||
$('.rpg-field-move-down').off('click').on('click', function () {
|
||||
const index = $(this).data('index');
|
||||
const fields = extensionSettings.trackerConfig.presentCharacters.customFields;
|
||||
if (index < fields.length - 1) {
|
||||
@@ -1386,25 +1386,25 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Toggle field
|
||||
$('.rpg-field-toggle').off('change').on('change', function() {
|
||||
$('.rpg-field-toggle').off('change').on('change', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Rename field
|
||||
$('.rpg-field-label').off('blur').on('blur', function() {
|
||||
$('.rpg-field-label').off('blur').on('blur', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].name = $(this).val();
|
||||
});
|
||||
|
||||
// Update description
|
||||
$('.rpg-field-placeholder').off('blur').on('blur', function() {
|
||||
$('.rpg-field-placeholder').off('blur').on('blur', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].description = $(this).val();
|
||||
});
|
||||
|
||||
// Character stats toggle
|
||||
$('#rpg-char-stats-enabled').off('change').on('change', function() {
|
||||
$('#rpg-char-stats-enabled').off('change').on('change', function () {
|
||||
if (!extensionSettings.trackerConfig.presentCharacters.characterStats) {
|
||||
extensionSettings.trackerConfig.presentCharacters.characterStats = { enabled: false, customStats: [] };
|
||||
}
|
||||
@@ -1412,7 +1412,7 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Add character stat
|
||||
$('#rpg-add-char-stat').off('click').on('click', function() {
|
||||
$('#rpg-add-char-stat').off('click').on('click', function () {
|
||||
if (!extensionSettings.trackerConfig.presentCharacters.characterStats) {
|
||||
extensionSettings.trackerConfig.presentCharacters.characterStats = { enabled: false, customStats: [] };
|
||||
}
|
||||
@@ -1428,20 +1428,20 @@ function setupPresentCharactersListeners() {
|
||||
});
|
||||
|
||||
// Remove character stat
|
||||
$('.rpg-char-stat-remove').off('click').on('click', function() {
|
||||
$('.rpg-char-stat-remove').off('click').on('click', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats.splice(index, 1);
|
||||
renderPresentCharactersTab();
|
||||
});
|
||||
|
||||
// Toggle character stat
|
||||
$('.rpg-char-stat-toggle').off('change').on('change', function() {
|
||||
$('.rpg-char-stat-toggle').off('change').on('change', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats[index].enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Rename character stat
|
||||
$('.rpg-char-stat-label').off('blur').on('blur', function() {
|
||||
$('.rpg-char-stat-label').off('blur').on('blur', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats[index].name = $(this).val();
|
||||
});
|
||||
@@ -1637,70 +1637,70 @@ function setupHistoryPersistenceListeners() {
|
||||
}
|
||||
|
||||
// Main toggle
|
||||
$('#rpg-history-persistence-enabled').off('change').on('change', function() {
|
||||
$('#rpg-history-persistence-enabled').off('change').on('change', function () {
|
||||
extensionSettings.historyPersistence.enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Send All Enabled on Refresh toggle
|
||||
$('#rpg-history-send-all-enabled').off('change').on('change', function() {
|
||||
$('#rpg-history-send-all-enabled').off('change').on('change', function () {
|
||||
extensionSettings.historyPersistence.sendAllEnabledOnRefresh = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Message count
|
||||
$('#rpg-history-message-count').off('change').on('change', function() {
|
||||
$('#rpg-history-message-count').off('change').on('change', function () {
|
||||
extensionSettings.historyPersistence.messageCount = parseInt($(this).val()) || 0;
|
||||
});
|
||||
|
||||
// Injection position
|
||||
$('#rpg-history-injection-position').off('change').on('change', function() {
|
||||
$('#rpg-history-injection-position').off('change').on('change', function () {
|
||||
extensionSettings.historyPersistence.injectionPosition = $(this).val();
|
||||
});
|
||||
|
||||
// Context preamble
|
||||
$('#rpg-history-context-preamble').off('blur').on('blur', function() {
|
||||
$('#rpg-history-context-preamble').off('blur').on('blur', function () {
|
||||
extensionSettings.historyPersistence.contextPreamble = $(this).val();
|
||||
});
|
||||
|
||||
// User Stats toggles
|
||||
$('.rpg-history-stat-toggle').off('change').on('change', function() {
|
||||
$('.rpg-history-stat-toggle').off('change').on('change', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.customStats[index].persistInHistory = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Status section
|
||||
$('#rpg-history-status').off('change').on('change', function() {
|
||||
$('#rpg-history-status').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.statusSection.persistInHistory = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Skills section
|
||||
$('#rpg-history-skills').off('change').on('change', function() {
|
||||
$('#rpg-history-skills').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.skillsSection.persistInHistory = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Inventory
|
||||
$('#rpg-history-inventory').off('change').on('change', function() {
|
||||
$('#rpg-history-inventory').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.inventoryPersistInHistory = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Quests
|
||||
$('#rpg-history-quests').off('change').on('change', function() {
|
||||
$('#rpg-history-quests').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.userStats.questsPersistInHistory = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Info Box widget toggles
|
||||
$('.rpg-history-widget-toggle').off('change').on('change', function() {
|
||||
$('.rpg-history-widget-toggle').off('change').on('change', function () {
|
||||
const widgetId = $(this).data('widget');
|
||||
extensionSettings.trackerConfig.infoBox.widgets[widgetId].persistInHistory = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Present Characters field toggles
|
||||
$('.rpg-history-charfield-toggle').off('change').on('change', function() {
|
||||
$('.rpg-history-charfield-toggle').off('change').on('change', function () {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].persistInHistory = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Thoughts
|
||||
$('#rpg-history-thoughts').off('change').on('change', function() {
|
||||
$('#rpg-history-thoughts').off('change').on('change', function () {
|
||||
extensionSettings.trackerConfig.presentCharacters.thoughts.persistInHistory = $(this).is(':checked');
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user