Fix extension loading, enhance theming, add horizontal scrolling, improve emoji parsing, rename to Main Quests
This commit is contained in:
@@ -12,6 +12,44 @@ import {
|
||||
} from '../../core/state.js';
|
||||
import { saveChatData } from '../../core/persistence.js';
|
||||
|
||||
/**
|
||||
* Helper to separate emoji from text in a string
|
||||
* Handles cases where there's no comma or space after emoji
|
||||
* @param {string} str - String potentially containing emoji followed by text
|
||||
* @returns {{emoji: string, text: string}} Separated emoji and text
|
||||
*/
|
||||
function separateEmojiFromText(str) {
|
||||
if (!str) return { emoji: '', text: '' };
|
||||
|
||||
str = str.trim();
|
||||
|
||||
// Regex to match emoji at the start (handles most emoji including compound ones)
|
||||
const emojiRegex = /^[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F000}-\u{1F02F}\u{1F0A0}-\u{1F0FF}\u{1F100}-\u{1F64F}\u{1F680}-\u{1F6FF}\u{1F910}-\u{1F96B}\u{1F980}-\u{1F9E0}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}]+/u;
|
||||
const emojiMatch = str.match(emojiRegex);
|
||||
|
||||
if (emojiMatch) {
|
||||
const emoji = emojiMatch[0];
|
||||
let text = str.substring(emoji.length).trim();
|
||||
|
||||
// Remove leading comma or space if present
|
||||
text = text.replace(/^[,\s]+/, '');
|
||||
|
||||
return { emoji, text };
|
||||
}
|
||||
|
||||
// No emoji found - check if there's a comma separator anyway
|
||||
const commaParts = str.split(',');
|
||||
if (commaParts.length >= 2) {
|
||||
return {
|
||||
emoji: commaParts[0].trim(),
|
||||
text: commaParts.slice(1).join(',').trim()
|
||||
};
|
||||
}
|
||||
|
||||
// No clear separation - return original as text
|
||||
return { emoji: '', text: str };
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the info box as a visual dashboard with calendar, weather, temperature, clock, and map widgets.
|
||||
* Includes event listeners for editable fields.
|
||||
@@ -155,11 +193,24 @@ export function renderInfoBox() {
|
||||
}
|
||||
} else if (line.startsWith('Weather:')) {
|
||||
if (!parsedFields.weather) {
|
||||
// New text format: Weather: [Emoji], [Forecast]
|
||||
// New text format: Weather: [Emoji], [Forecast] OR Weather: [Emoji][Forecast] (no separator - FIXED)
|
||||
const weatherStr = line.replace('Weather:', '').trim();
|
||||
const weatherParts = weatherStr.split(',').map(p => p.trim());
|
||||
data.weatherEmoji = weatherParts[0] || '';
|
||||
data.weatherForecast = weatherParts[1] || '';
|
||||
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
|
||||
const weatherParts = weatherStr.split(',').map(p => p.trim());
|
||||
data.weatherEmoji = weatherParts[0] || '';
|
||||
data.weatherForecast = weatherParts[1] || '';
|
||||
} else {
|
||||
// No clear separation - assume it's all forecast text
|
||||
data.weatherEmoji = '🌤️'; // Default emoji
|
||||
data.weatherForecast = weatherStr;
|
||||
}
|
||||
|
||||
parsedFields.weather = true;
|
||||
}
|
||||
} else {
|
||||
@@ -217,8 +268,11 @@ export function renderInfoBox() {
|
||||
// });
|
||||
|
||||
// Build visual dashboard HTML
|
||||
// Wrap all content in a scrollable container
|
||||
let html = '<div class="rpg-info-content">';
|
||||
|
||||
// Row 1: Date, Weather, Temperature, Time widgets
|
||||
let html = '<div class="rpg-dashboard rpg-dashboard-row-1">';
|
||||
html += '<div class="rpg-dashboard rpg-dashboard-row-1">';
|
||||
|
||||
// Calendar widget - always show (editable even if empty)
|
||||
// Display abbreviated version but allow editing full value
|
||||
@@ -301,6 +355,67 @@ export function renderInfoBox() {
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Row 3: Recent Events widget (notebook style) - dynamically show 1-3 events
|
||||
// Parse Recent Events from infoBox string
|
||||
let recentEvents = [];
|
||||
if (committedTrackerData.infoBox) {
|
||||
const recentEventsLine = committedTrackerData.infoBox.split('\n').find(line => line.startsWith('Recent Events:'));
|
||||
if (recentEventsLine) {
|
||||
const eventsString = recentEventsLine.replace('Recent Events:', '').trim();
|
||||
if (eventsString) {
|
||||
recentEvents = eventsString.split(',').map(e => e.trim()).filter(e => e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const validEvents = recentEvents.filter(e => e && e.trim() && e !== 'Event 1' && e !== 'Event 2' && e !== 'Event 3');
|
||||
|
||||
// If no valid events, show at least one placeholder
|
||||
if (validEvents.length === 0) {
|
||||
validEvents.push('Click to add event');
|
||||
}
|
||||
|
||||
html += `
|
||||
<div class="rpg-dashboard rpg-dashboard-row-3">
|
||||
<div class="rpg-dashboard-widget rpg-events-widget">
|
||||
<div class="rpg-notebook-header">
|
||||
<div class="rpg-notebook-ring"></div>
|
||||
<div class="rpg-notebook-ring"></div>
|
||||
<div class="rpg-notebook-ring"></div>
|
||||
</div>
|
||||
<div class="rpg-notebook-title">Recent Events</div>
|
||||
<div class="rpg-notebook-lines">
|
||||
`;
|
||||
|
||||
// Dynamically generate event lines (max 3)
|
||||
for (let i = 0; i < Math.min(validEvents.length, 3); i++) {
|
||||
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>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// If we have less than 3 events, add empty placeholders with + icon
|
||||
for (let i = validEvents.length; i < 3; i++) {
|
||||
html += `
|
||||
<div class="rpg-notebook-line rpg-event-add">
|
||||
<span class="rpg-bullet">+</span>
|
||||
<span class="rpg-event-text rpg-editable rpg-event-placeholder" contenteditable="true" data-field="event${i + 1}" title="Click to add event">Add event...</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
html += `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Close the scrollable content wrapper
|
||||
html += '</div>';
|
||||
|
||||
$infoBoxContainer.html(html);
|
||||
|
||||
// Add event handlers for editable Info Box fields
|
||||
@@ -320,7 +435,12 @@ export function renderInfoBox() {
|
||||
}
|
||||
}
|
||||
|
||||
updateInfoBoxField(field, value);
|
||||
// Handle recent events separately
|
||||
if (field === 'event1' || field === 'event2' || field === 'event3') {
|
||||
updateRecentEvent(field, value);
|
||||
} else {
|
||||
updateInfoBoxField(field, value);
|
||||
}
|
||||
});
|
||||
|
||||
// For date fields, show full value on focus
|
||||
@@ -610,3 +730,84 @@ export function updateInfoBoxField(field, value) {
|
||||
renderInfoBox();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a recent event in the committed tracker data
|
||||
* @param {string} field - event1, event2, or event3
|
||||
* @param {string} value - New event text
|
||||
*/
|
||||
function updateRecentEvent(field, value) {
|
||||
// Map field to index
|
||||
const eventIndex = {
|
||||
'event1': 0,
|
||||
'event2': 1,
|
||||
'event3': 2
|
||||
}[field];
|
||||
|
||||
if (eventIndex !== undefined) {
|
||||
// Parse current infoBox to get existing events
|
||||
const lines = (committedTrackerData.infoBox || '').split('\n');
|
||||
let recentEvents = [];
|
||||
|
||||
// Find existing Recent Events line
|
||||
const recentEventsLine = lines.find(line => line.startsWith('Recent Events:'));
|
||||
if (recentEventsLine) {
|
||||
const eventsString = recentEventsLine.replace('Recent Events:', '').trim();
|
||||
if (eventsString) {
|
||||
recentEvents = eventsString.split(',').map(e => e.trim()).filter(e => e);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure array has enough slots
|
||||
while (recentEvents.length <= eventIndex) {
|
||||
recentEvents.push('');
|
||||
}
|
||||
|
||||
// Update the specific event
|
||||
recentEvents[eventIndex] = value;
|
||||
|
||||
// Filter out empty events and rebuild the line
|
||||
const validEvents = recentEvents.filter(e => e && e.trim());
|
||||
const newRecentEventsLine = validEvents.length > 0
|
||||
? `Recent Events: ${validEvents.join(', ')}`
|
||||
: '';
|
||||
|
||||
// Update infoBox with new Recent Events line
|
||||
const updatedLines = lines.filter(line => !line.startsWith('Recent Events:'));
|
||||
if (newRecentEventsLine) {
|
||||
// Add Recent Events line at the end (before any empty lines)
|
||||
let insertIndex = updatedLines.length;
|
||||
for (let i = updatedLines.length - 1; i >= 0; i--) {
|
||||
if (updatedLines[i].trim() !== '') {
|
||||
insertIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
updatedLines.splice(insertIndex, 0, newRecentEventsLine);
|
||||
}
|
||||
|
||||
committedTrackerData.infoBox = updatedLines.join('\n');
|
||||
lastGeneratedData.infoBox = updatedLines.join('\n');
|
||||
|
||||
// Update the message's swipe data
|
||||
const chat = getContext().chat;
|
||||
if (chat && chat.length > 0) {
|
||||
for (let i = chat.length - 1; i >= 0; i--) {
|
||||
const message = chat[i];
|
||||
if (!message.is_user) {
|
||||
if (message.extra && message.extra.rpg_companion_swipes) {
|
||||
const swipeId = message.swipe_id || 0;
|
||||
if (message.extra.rpg_companion_swipes[swipeId]) {
|
||||
message.extra.rpg_companion_swipes[swipeId].infoBox = updatedLines.join('\n');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveChatData();
|
||||
renderInfoBox();
|
||||
console.log(`[RPG Companion] Updated recent event ${field}:`, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* Quests Rendering Module
|
||||
* Handles UI rendering for quests system (main and optional quests)
|
||||
*/
|
||||
|
||||
import { extensionSettings, $questsContainer } from '../../core/state.js';
|
||||
import { saveSettings } from '../../core/persistence.js';
|
||||
|
||||
/**
|
||||
* HTML escape helper
|
||||
* @param {string} text - Text to escape
|
||||
* @returns {string} Escaped HTML
|
||||
*/
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the quests sub-tab navigation (Main, Optional)
|
||||
* @param {string} activeTab - Currently active sub-tab ('main', 'optional')
|
||||
* @returns {string} HTML for sub-tab navigation
|
||||
*/
|
||||
export function renderQuestsSubTabs(activeTab = 'main') {
|
||||
return `
|
||||
<div class="rpg-quests-subtabs">
|
||||
<button class="rpg-quests-subtab ${activeTab === 'main' ? 'active' : ''}" data-tab="main">
|
||||
Main Quest
|
||||
</button>
|
||||
<button class="rpg-quests-subtab ${activeTab === 'optional' ? 'active' : ''}" data-tab="optional">
|
||||
Optional Quests
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the main quest view
|
||||
* @param {string} mainQuest - Current main quest title
|
||||
* @returns {string} HTML for main quest view
|
||||
*/
|
||||
export function renderMainQuestView(mainQuest) {
|
||||
const questDisplay = (mainQuest && mainQuest !== 'None') ? mainQuest : '';
|
||||
const hasQuest = questDisplay.length > 0;
|
||||
|
||||
return `
|
||||
<div class="rpg-quest-section">
|
||||
<div class="rpg-quest-header">
|
||||
<h3 class="rpg-quest-section-title">Main Quests</h3>
|
||||
${!hasQuest ? `<button class="rpg-add-quest-btn" data-action="add-quest" data-field="main" title="Add main quests">
|
||||
<i class="fa-solid fa-plus"></i> Add Quest
|
||||
</button>` : ''}
|
||||
</div>
|
||||
<div class="rpg-quest-content">
|
||||
${hasQuest ? `
|
||||
<div class="rpg-inline-form" id="rpg-edit-quest-form-main" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-edit-quest-main" value="${escapeHtml(questDisplay)}" />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-edit-quest" data-field="main">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-edit-quest" data-field="main">
|
||||
<i class="fa-solid fa-check"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-quest-item" data-field="main">
|
||||
<div class="rpg-quest-title">${escapeHtml(questDisplay)}</div>
|
||||
<div class="rpg-quest-actions">
|
||||
<button class="rpg-quest-edit" data-action="edit-quest" data-field="main" title="Edit quest">
|
||||
<i class="fa-solid fa-edit"></i>
|
||||
</button>
|
||||
<button class="rpg-quest-remove" data-action="remove-quest" data-field="main" title="Complete/Remove quest">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
` : `
|
||||
<div class="rpg-inline-form" id="rpg-add-quest-form-main" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-quest-main" placeholder="Enter main quests title..." />
|
||||
<div class="rpg-inline-actions">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-quest" data-field="main">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-quest" data-field="main">
|
||||
<i class="fa-solid fa-check"></i> Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-quest-empty">No active main quests</div>
|
||||
`}
|
||||
</div>
|
||||
<div class="rpg-quest-hint">
|
||||
<i class="fa-solid fa-lightbulb"></i>
|
||||
The main quests represent your primary objective in the story.
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the optional quests view
|
||||
* @param {string[]} optionalQuests - Array of optional quest titles
|
||||
* @returns {string} HTML for optional quests view
|
||||
*/
|
||||
export function renderOptionalQuestsView(optionalQuests) {
|
||||
const quests = optionalQuests.filter(q => q && q !== 'None');
|
||||
|
||||
let questsHtml = '';
|
||||
if (quests.length === 0) {
|
||||
questsHtml = '<div class="rpg-quest-empty">No active optional quests</div>';
|
||||
} else {
|
||||
questsHtml = quests.map((quest, index) => `
|
||||
<div class="rpg-quest-item" data-field="optional" data-index="${index}">
|
||||
<div class="rpg-quest-title rpg-editable" contenteditable="true" data-field="optional" data-index="${index}" title="Click to edit">${escapeHtml(quest)}</div>
|
||||
<div class="rpg-quest-actions">
|
||||
<button class="rpg-quest-remove" data-action="remove-quest" data-field="optional" data-index="${index}" title="Complete/Remove quest">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="rpg-quest-section">
|
||||
<div class="rpg-quest-header">
|
||||
<h3 class="rpg-quest-section-title">Optional Quests</h3>
|
||||
<button class="rpg-add-quest-btn" data-action="add-quest" data-field="optional" title="Add optional quest">
|
||||
<i class="fa-solid fa-plus"></i> Add Quest
|
||||
</button>
|
||||
</div>
|
||||
<div class="rpg-quest-content">
|
||||
<div class="rpg-inline-form" id="rpg-add-quest-form-optional" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-quest-optional" placeholder="Enter optional quest title..." />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-quest" data-field="optional">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-quest" data-field="optional">
|
||||
<i class="fa-solid fa-check"></i> Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-quest-list">
|
||||
${questsHtml}
|
||||
</div>
|
||||
<div class="rpg-quest-hint">
|
||||
<i class="fa-solid fa-info-circle"></i>
|
||||
Optional quests are side objectives that complement your main story.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main render function for quests
|
||||
*/
|
||||
export function renderQuests() {
|
||||
if (!extensionSettings.showInventory || !$questsContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current sub-tab from container or default to 'main'
|
||||
const activeSubTab = $questsContainer.data('active-subtab') || 'main';
|
||||
|
||||
// Get quests data
|
||||
const mainQuest = extensionSettings.quests.main || 'None';
|
||||
const optionalQuests = extensionSettings.quests.optional || [];
|
||||
|
||||
// Build HTML
|
||||
let html = '<div class="rpg-quests-wrapper">';
|
||||
html += renderQuestsSubTabs(activeSubTab);
|
||||
|
||||
// Render active sub-tab
|
||||
html += '<div class="rpg-quests-panels">';
|
||||
if (activeSubTab === 'main') {
|
||||
html += renderMainQuestView(mainQuest);
|
||||
} else {
|
||||
html += renderOptionalQuestsView(optionalQuests);
|
||||
}
|
||||
html += '</div></div>';
|
||||
|
||||
$questsContainer.html(html);
|
||||
|
||||
// Attach event handlers
|
||||
attachQuestEventHandlers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach event handlers for quest interactions
|
||||
*/
|
||||
function attachQuestEventHandlers() {
|
||||
// Sub-tab switching
|
||||
$questsContainer.find('.rpg-quests-subtab').on('click', function() {
|
||||
const tab = $(this).data('tab');
|
||||
$questsContainer.data('active-subtab', tab);
|
||||
renderQuests();
|
||||
});
|
||||
|
||||
// Add quest button
|
||||
$questsContainer.find('[data-action="add-quest"]').on('click', function() {
|
||||
const field = $(this).data('field');
|
||||
$(`#rpg-add-quest-form-${field}`).show();
|
||||
$(`#rpg-new-quest-${field}`).focus();
|
||||
});
|
||||
|
||||
// Cancel add quest
|
||||
$questsContainer.find('[data-action="cancel-add-quest"]').on('click', function() {
|
||||
const field = $(this).data('field');
|
||||
$(`#rpg-add-quest-form-${field}`).hide();
|
||||
$(`#rpg-new-quest-${field}`).val('');
|
||||
});
|
||||
|
||||
// Save add quest
|
||||
$questsContainer.find('[data-action="save-add-quest"]').on('click', function() {
|
||||
const field = $(this).data('field');
|
||||
const input = $(`#rpg-new-quest-${field}`);
|
||||
const questTitle = input.val().trim();
|
||||
|
||||
if (questTitle) {
|
||||
if (field === 'main') {
|
||||
extensionSettings.quests.main = questTitle;
|
||||
} else {
|
||||
if (!extensionSettings.quests.optional) {
|
||||
extensionSettings.quests.optional = [];
|
||||
}
|
||||
extensionSettings.quests.optional.push(questTitle);
|
||||
}
|
||||
saveSettings();
|
||||
renderQuests();
|
||||
}
|
||||
});
|
||||
|
||||
// Edit quest (main only)
|
||||
$questsContainer.find('[data-action="edit-quest"]').on('click', function() {
|
||||
const field = $(this).data('field');
|
||||
$(`#rpg-edit-quest-form-${field}`).show();
|
||||
$('.rpg-quest-item[data-field="main"]').hide();
|
||||
$(`#rpg-edit-quest-${field}`).focus();
|
||||
});
|
||||
|
||||
// Cancel edit quest
|
||||
$questsContainer.find('[data-action="cancel-edit-quest"]').on('click', function() {
|
||||
const field = $(this).data('field');
|
||||
$(`#rpg-edit-quest-form-${field}`).hide();
|
||||
$('.rpg-quest-item[data-field="main"]').show();
|
||||
});
|
||||
|
||||
// Save edit quest
|
||||
$questsContainer.find('[data-action="save-edit-quest"]').on('click', function() {
|
||||
const field = $(this).data('field');
|
||||
const input = $(`#rpg-edit-quest-${field}`);
|
||||
const questTitle = input.val().trim();
|
||||
|
||||
if (questTitle) {
|
||||
extensionSettings.quests.main = questTitle;
|
||||
saveSettings();
|
||||
renderQuests();
|
||||
}
|
||||
});
|
||||
|
||||
// Remove quest
|
||||
$questsContainer.find('[data-action="remove-quest"]').on('click', function() {
|
||||
const field = $(this).data('field');
|
||||
const index = $(this).data('index');
|
||||
|
||||
if (field === 'main') {
|
||||
extensionSettings.quests.main = 'None';
|
||||
} else {
|
||||
extensionSettings.quests.optional.splice(index, 1);
|
||||
}
|
||||
saveSettings();
|
||||
renderQuests();
|
||||
});
|
||||
|
||||
// Inline editing for optional quests
|
||||
$questsContainer.find('.rpg-quest-title.rpg-editable').on('blur', function() {
|
||||
const $this = $(this);
|
||||
const field = $this.data('field');
|
||||
const index = $this.data('index');
|
||||
const newTitle = $this.text().trim();
|
||||
|
||||
if (newTitle && field === 'optional' && index !== undefined) {
|
||||
extensionSettings.quests.optional[index] = newTitle;
|
||||
saveSettings();
|
||||
}
|
||||
});
|
||||
|
||||
// Enter key to save in forms
|
||||
$questsContainer.find('.rpg-inline-input').on('keypress', function(e) {
|
||||
if (e.which === 13) {
|
||||
const field = $(this).attr('id').includes('edit') ?
|
||||
$(this).attr('id').replace('rpg-edit-quest-', '') :
|
||||
$(this).attr('id').replace('rpg-new-quest-', '');
|
||||
|
||||
if ($(this).attr('id').includes('edit')) {
|
||||
$(`[data-action="save-edit-quest"][data-field="${field}"]`).click();
|
||||
} else {
|
||||
$(`[data-action="save-add-quest"][data-field="${field}"]`).click();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user