Prevent saveWorldInfo calls while rendering the list

b7323715b2693229f43bbecffea769484f89ed59

Cohee <18619528+Cohee1207@users.noreply.github.com>

1 files changed, +39 -20Ignore whitespace
public/scripts/world-info.js+39 -20
@@ -85,6 +85,7 @@ const saveSettingsDebounced = debounce(() => {
85}, debounce_timeout.relaxed);85}, debounce_timeout.relaxed);
86const sortFn = (a, b) => b.order - a.order;86const sortFn = (a, b) => b.order - a.order;
87let updateEditor = (navigation, flashOnNav = true) => { console.debug('Triggered WI navigation', navigation, flashOnNav); };87let updateEditor = (navigation, flashOnNav = true) => { console.debug('Triggered WI navigation', navigation, flashOnNav); };
88let isSaveWorldInfoDisabled = false;
8889
89// Do not optimize. updateEditor is a function that is updated by the displayWorldEntries with new data.90// Do not optimize. updateEditor is a function that is updated by the displayWorldEntries with new data.
90export const worldInfoFilter = new FilterHelper(() => updateEditor());91export const worldInfoFilter = new FilterHelper(() => updateEditor());
@@ -2010,12 +2011,9 @@ async function displayWorldEntries(name, data, navigation = navigation_option.no
20102011
2011 const worldEntriesList = $('#world_popup_entries_list');2012 const worldEntriesList = $('#world_popup_entries_list');
20122013
2013 // We save costly performance by removing all events before emptying. Because we know there are no relevant event handlers reacting on removing elements
2014 // This prevents jQuery from actually going through all registered events on the controls for each entry when removing it
2015 //worldEntriesList.find('*').off();
2016 worldEntriesList.css({ 'opacity': 0, 'transition': 'opacity 250ms ease-in-out' });2014 worldEntriesList.css({ 'opacity': 0, 'transition': 'opacity 250ms ease-in-out' });
2017 await delay(250);2015 await delay(250);
2018 clearEntryList(); // Use enhanced cleanup2016 clearEntryList();
2019 worldEntriesList.show();2017 worldEntriesList.show();
20202018
2021 if (!data || !('entries' in data)) {2019 if (!data || !('entries' in data)) {
@@ -2109,23 +2107,39 @@ async function displayWorldEntries(name, data, navigation = navigation_option.no
2109 formatNavigator: PAGINATION_TEMPLATE,2107 formatNavigator: PAGINATION_TEMPLATE,
2110 showNavigator: true,2108 showNavigator: true,
2111 callback: async function (/** @type {object[]} */ page) {2109 callback: async function (/** @type {object[]} */ page) {
2112 // We save costly performance by removing all events before emptying. Because we know there are no relevant event handlers reacting on removing elements2110 try {
2113 // This prevents jQuery from actually going through all registered events on the controls for each entry when removing it2111 // Prevent saveWorldInfo from firing timeouts while rendering the list
2114 //worldEntriesList.find('*').off();2112 isSaveWorldInfoDisabled = true;
2115 clearEntryList();2113 clearEntryList();
2116 //worldEntriesList.empty();2114
21172115 const keywordHeaders = await renderTemplateAsync('worldInfoKeywordHeaders');
2118 const keywordHeaders = await renderTemplateAsync('worldInfoKeywordHeaders');2116 const blocks = [];
2119 const blocksPromises = page.map(async (entry) => await getWorldEntry(name, data, entry)).filter(x => x);2117
2120 const blocks = await Promise.all(blocksPromises);2118 for (const entry of page) {
2121 const isCustomOrder = $('#world_info_sort_order').find(':selected').data('rule') === 'custom';2119 try {
2122 if (!isCustomOrder) {2120 const block = await getWorldEntry(name, data, entry);
2123 blocks.forEach(block => {2121 if (block) {
2124 block.find('.drag-handle').remove();2122 blocks.push(block);
2125 });2123 }
2124 } catch (error) {
2125 console.error(`Error while processing entry ${entry.uid}:`, error);
2126 }
2127 }
2128
2129 const isCustomOrder = $('#world_info_sort_order').find(':selected').data('rule') === 'custom';
2130 if (!isCustomOrder) {
2131 blocks.forEach(block => {
2132 block.find('.drag-handle').remove();
2133 });
2134 }
2135
2136 worldEntriesList.append(keywordHeaders);
2137 worldEntriesList.append(blocks);
2138 } catch (error) {
2139 console.error('Error while rendering WI entries:', error);
2140 } finally {
2141 isSaveWorldInfoDisabled = false;
2126 }2142 }
2127 worldEntriesList.append(keywordHeaders);
2128 worldEntriesList.append(blocks);
2129 },2143 },
2130 afterSizeSelectorChange: function (e) {2144 afterSizeSelectorChange: function (e) {
2131 accountStorage.setItem(storageKey, e.target.value);2145 accountStorage.setItem(storageKey, e.target.value);
@@ -3739,6 +3753,11 @@ async function _save(name, data) {
3739 * @return {Promise<void>} A promise that resolves when the world info is saved3753 * @return {Promise<void>} A promise that resolves when the world info is saved
3740 */3754 */
3741export async function saveWorldInfo(name, data, immediately = false) {3755export async function saveWorldInfo(name, data, immediately = false) {
3756 // Saving is temporarily disabled
3757 if (isSaveWorldInfoDisabled) {
3758 return;
3759 }
3760
3742 if (!name || !data) {3761 if (!name || !data) {
3743 return;3762 return;
3744 }3763 }