Fix duplicate tracker entries by prioritizing text format over emoji format
- Added parsedFields tracking to prevent parsing the same field twice
- Split combined if conditions into separate checks for text vs emoji format
- Text format (Temperature:, Time:, etc.) is now parsed first and preferred
- Emoji format (��️:, 🕒:, etc.) only parsed if text format not found
- Prevents duplicate entries when AI generates both formats in output
- Fixes duplicate Temperature, Time, Location lines in tracker data
This commit is contained in:
@@ -63,47 +63,109 @@ export function renderInfoBox() {
|
|||||||
characters: []
|
characters: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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) {
|
for (const line of lines) {
|
||||||
// console.log('[RPG Companion] Processing line:', line);
|
// console.log('[RPG Companion] Processing line:', line);
|
||||||
|
|
||||||
// Support both new text format (Date:) and legacy emoji format (🗓️:)
|
// Support both new text format (Date:) and legacy emoji format (🗓️:)
|
||||||
if (line.startsWith('Date:') || line.includes('🗓️:')) {
|
// Prioritize text format over emoji format
|
||||||
// console.log('[RPG Companion] → Matched DATE');
|
if (line.startsWith('Date:')) {
|
||||||
const dateStr = line.replace('Date:', '').replace('🗓️:', '').trim();
|
if (!parsedFields.date) {
|
||||||
// Parse format: "Weekday, Month Day, Year" or "Weekday, Month, Year"
|
// console.log('[RPG Companion] → Matched DATE (text format)');
|
||||||
|
const dateStr = line.replace('Date:', '').trim();
|
||||||
const dateParts = dateStr.split(',').map(p => p.trim());
|
const dateParts = dateStr.split(',').map(p => p.trim());
|
||||||
data.weekday = dateParts[0] || '';
|
data.weekday = dateParts[0] || '';
|
||||||
data.month = dateParts[1] || '';
|
data.month = dateParts[1] || '';
|
||||||
data.year = dateParts[2] || '';
|
data.year = dateParts[2] || '';
|
||||||
data.date = dateStr;
|
data.date = dateStr;
|
||||||
} else if (line.startsWith('Temperature:') || line.includes('🌡️:')) {
|
parsedFields.date = true;
|
||||||
// console.log('[RPG Companion] → Matched TEMPERATURE');
|
}
|
||||||
const tempStr = line.replace('Temperature:', '').replace('🌡️:', '').trim();
|
} 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;
|
data.temperature = tempStr;
|
||||||
// Extract numeric value
|
|
||||||
const tempMatch = tempStr.match(/(-?\d+)/);
|
const tempMatch = tempStr.match(/(-?\d+)/);
|
||||||
if (tempMatch) {
|
if (tempMatch) {
|
||||||
data.tempValue = parseInt(tempMatch[1]);
|
data.tempValue = parseInt(tempMatch[1]);
|
||||||
}
|
}
|
||||||
} else if (line.startsWith('Time:') || line.includes('🕒:')) {
|
parsedFields.temperature = true;
|
||||||
// console.log('[RPG Companion] → Matched TIME');
|
}
|
||||||
const timeStr = line.replace('Time:', '').replace('🕒:', '').trim();
|
} 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;
|
data.time = timeStr;
|
||||||
// Parse "HH:MM → HH:MM" format
|
|
||||||
const timeParts = timeStr.split('→').map(t => t.trim());
|
const timeParts = timeStr.split('→').map(t => t.trim());
|
||||||
data.timeStart = timeParts[0] || '';
|
data.timeStart = timeParts[0] || '';
|
||||||
data.timeEnd = timeParts[1] || '';
|
data.timeEnd = timeParts[1] || '';
|
||||||
} else if (line.startsWith('Location:') || line.includes('🗺️:')) {
|
parsedFields.time = true;
|
||||||
// console.log('[RPG Companion] → Matched LOCATION');
|
}
|
||||||
data.location = line.replace('Location:', '').replace('🗺️:', '').trim();
|
} 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:')) {
|
} else if (line.startsWith('Weather:')) {
|
||||||
|
if (!parsedFields.weather) {
|
||||||
// New text format: Weather: [Emoji], [Forecast]
|
// New text format: Weather: [Emoji], [Forecast]
|
||||||
const weatherStr = line.replace('Weather:', '').trim();
|
const weatherStr = line.replace('Weather:', '').trim();
|
||||||
const weatherParts = weatherStr.split(',').map(p => p.trim());
|
const weatherParts = weatherStr.split(',').map(p => p.trim());
|
||||||
data.weatherEmoji = weatherParts[0] || '';
|
data.weatherEmoji = weatherParts[0] || '';
|
||||||
data.weatherForecast = weatherParts[1] || '';
|
data.weatherForecast = weatherParts[1] || '';
|
||||||
|
parsedFields.weather = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check if it's a weather line
|
// 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
|
// Since \p{Emoji} doesn't work reliably, use a simpler approach
|
||||||
const hasColon = line.includes(':');
|
const hasColon = line.includes(':');
|
||||||
const notInfoBox = !line.includes('Info Box');
|
const notInfoBox = !line.includes('Info Box');
|
||||||
@@ -130,6 +192,7 @@ export function renderInfoBox() {
|
|||||||
if (potentialEmoji.length <= 5) {
|
if (potentialEmoji.length <= 5) {
|
||||||
data.weatherEmoji = potentialEmoji;
|
data.weatherEmoji = potentialEmoji;
|
||||||
data.weatherForecast = forecast;
|
data.weatherForecast = forecast;
|
||||||
|
parsedFields.weather = true;
|
||||||
// console.log('[RPG Companion] ✓ Weather parsed:', data.weatherEmoji, data.weatherForecast);
|
// console.log('[RPG Companion] ✓ Weather parsed:', data.weatherEmoji, data.weatherForecast);
|
||||||
} else {
|
} else {
|
||||||
// console.log('[RPG Companion] ✗ First part too long for emoji:', potentialEmoji);
|
// console.log('[RPG Companion] ✗ First part too long for emoji:', potentialEmoji);
|
||||||
@@ -142,6 +205,7 @@ export function renderInfoBox() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// console.log('[RPG Companion] Parsed Info Box data:', {
|
// console.log('[RPG Companion] Parsed Info Box data:', {
|
||||||
// date: data.date,
|
// date: data.date,
|
||||||
@@ -157,14 +221,15 @@ export function renderInfoBox() {
|
|||||||
let html = '<div class="rpg-dashboard rpg-dashboard-row-1">';
|
let html = '<div class="rpg-dashboard rpg-dashboard-row-1">';
|
||||||
|
|
||||||
// Calendar widget - always show (editable even if empty)
|
// Calendar widget - always show (editable even if empty)
|
||||||
|
// Display abbreviated version but allow editing full value
|
||||||
const monthShort = data.month ? data.month.substring(0, 3).toUpperCase() : 'MON';
|
const monthShort = data.month ? data.month.substring(0, 3).toUpperCase() : 'MON';
|
||||||
const weekdayShort = data.weekday ? data.weekday.substring(0, 3).toUpperCase() : 'DAY';
|
const weekdayShort = data.weekday ? data.weekday.substring(0, 3).toUpperCase() : 'DAY';
|
||||||
const yearDisplay = data.year || 'YEAR';
|
const yearDisplay = data.year || 'YEAR';
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-dashboard-widget rpg-calendar-widget">
|
<div class="rpg-dashboard-widget rpg-calendar-widget">
|
||||||
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" title="Click to edit">${monthShort}</div>
|
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" data-full-value="${data.month || ''}" title="Click to edit">${monthShort}</div>
|
||||||
<div class="rpg-calendar-day rpg-editable" contenteditable="true" data-field="weekday" title="Click to edit">${weekdayShort}</div>
|
<div class="rpg-calendar-day rpg-editable" contenteditable="true" data-field="weekday" data-full-value="${data.weekday || ''}" title="Click to edit">${weekdayShort}</div>
|
||||||
<div class="rpg-calendar-year rpg-editable" contenteditable="true" data-field="year" title="Click to edit">${yearDisplay}</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>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -239,11 +304,32 @@ export function renderInfoBox() {
|
|||||||
|
|
||||||
// Add event handlers for editable Info Box fields
|
// Add event handlers for editable Info Box fields
|
||||||
$infoBoxContainer.find('.rpg-editable').on('blur', function() {
|
$infoBoxContainer.find('.rpg-editable').on('blur', function() {
|
||||||
const field = $(this).data('field');
|
const $this = $(this);
|
||||||
const value = $(this).text().trim();
|
const field = $this.data('field');
|
||||||
|
const value = $this.text().trim();
|
||||||
|
|
||||||
|
// For date fields, update the data-full-value immediately
|
||||||
|
if (field === 'month' || field === 'weekday' || field === 'year') {
|
||||||
|
$this.data('full-value', value);
|
||||||
|
// Update the display to show abbreviated version
|
||||||
|
if (field === 'month' || field === 'weekday') {
|
||||||
|
$this.text(value.substring(0, 3).toUpperCase());
|
||||||
|
} else {
|
||||||
|
$this.text(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateInfoBoxField(field, value);
|
updateInfoBoxField(field, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// For date fields, show full value on focus
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Remove updating class after animation
|
// Remove updating class after animation
|
||||||
if (extensionSettings.enableAnimations) {
|
if (extensionSettings.enableAnimations) {
|
||||||
setTimeout(() => $infoBoxContainer.removeClass('rpg-content-updating'), 500);
|
setTimeout(() => $infoBoxContainer.removeClass('rpg-content-updating'), 500);
|
||||||
@@ -512,5 +598,10 @@ export function updateInfoBoxField(field, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveChatData();
|
saveChatData();
|
||||||
|
|
||||||
|
// Only re-render if NOT editing date fields
|
||||||
|
// Date fields will update on next tracker generation to avoid losing user input
|
||||||
|
if (field !== 'month' && field !== 'weekday' && field !== 'year') {
|
||||||
renderInfoBox();
|
renderInfoBox();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user