Persist actionable tag states on reload (#4368) * Persist actionable tag states on reload Closes #3666 * Remove unneeded simulated clicks
Signed| @@ -6,6 +6,7 @@ | |||
| 6 | align-items: center; | 6 | align-items: center; |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | #rm_group_chats_block .tag.filterByFolder, | ||
| 9 | #rm_group_chats_block .tag.filterByGroups { | 10 | #rm_group_chats_block .tag.filterByGroups { |
| 10 | display: none; | 11 | display: none; |
| 11 | } | 12 | } |
| @@ -276,40 +276,36 @@ export async function RA_CountCharTokens() { | |||
| 276 | * The character or group is selected (clicked) if it is found. | 276 | * The character or group is selected (clicked) if it is found. |
| 277 | */ | 277 | */ |
| 278 | async function RA_autoloadchat() { | 278 | async function RA_autoloadchat() { |
| 279 | if (document.querySelector('#rm_print_characters_block .character_select') !== null) { | 279 | // active character is the name, we should look it up in the character list and get the id |
| 280 | // active character is the name, we should look it up in the character list and get the id | 280 | if (active_character !== null && active_character !== undefined) { |
| 281 | if (active_character !== null && active_character !== undefined) { | 281 | const active_character_id = characters.findIndex(x => getTagKeyForEntity(x) === active_character); |
| 282 | const active_character_id = characters.findIndex(x => getTagKeyForEntity(x) === active_character); | 282 | if (active_character_id !== -1) { |
| 283 | if (active_character_id !== -1) { | 283 | await selectCharacterById(active_character_id); |
| 284 | await selectCharacterById(active_character_id); | 284 | |
| 285 | 285 | // Do a little tomfoolery to spoof the tag selector | |
| 286 | // Do a little tomfoolery to spoof the tag selector | 286 | const selectedCharElement = $(`#rm_print_characters_block .character_select[chid="${active_character_id}"]`); |
| 287 | const selectedCharElement = $(`#rm_print_characters_block .character_select[chid="${active_character_id}"]`); | 287 | applyTagsOnCharacterSelect.call(selectedCharElement); |
| 288 | applyTagsOnCharacterSelect.call(selectedCharElement); | 288 | } else { |
| 289 | } else { | 289 | setActiveCharacter(null); |
| 290 | setActiveCharacter(null); | 290 | saveSettingsDebounced(); |
| 291 | saveSettingsDebounced(); | 291 | console.warn(`Currently active character with ID ${active_character} not found. Resetting to no active character.`); |
| 292 | console.warn(`Currently active character with ID ${active_character} not found. Resetting to no active character.`); | ||
| 293 | } | ||
| 294 | } | 292 | } |
| 293 | } | ||
| 295 | 294 | ||
| 296 | if (active_group !== null && active_group !== undefined) { | 295 | if (active_group !== null && active_group !== undefined) { |
| 297 | if (active_character) { | 296 | if (active_character) { |
| 298 | console.warn('Active character and active group are both set. Only active character will be loaded. Resetting active group.'); | 297 | console.warn('Active character and active group are both set. Only active character will be loaded. Resetting active group.'); |
| 298 | setActiveGroup(null); | ||
| 299 | saveSettingsDebounced(); | ||
| 300 | } else { | ||
| 301 | const result = await openGroupById(String(active_group)); | ||
| 302 | if (!result) { | ||
| 299 | setActiveGroup(null); | 303 | setActiveGroup(null); |
| 300 | saveSettingsDebounced(); | 304 | saveSettingsDebounced(); |
| 301 | } else { | 305 | console.warn(`Currently active group with ID ${active_group} not found. Resetting to no active group.`); |
| 302 | const result = await openGroupById(String(active_group)); | ||
| 303 | if (!result) { | ||
| 304 | setActiveGroup(null); | ||
| 305 | saveSettingsDebounced(); | ||
| 306 | console.warn(`Currently active group with ID ${active_group} not found. Resetting to no active group.`); | ||
| 307 | } | ||
| 308 | } | 306 | } |
| 309 | } | 307 | } |
| 310 | 308 | } | |
| 311 | // if the character list hadn't been loaded yet, try again. | ||
| 312 | } else { setTimeout(RA_autoloadchat, 100); } | ||
| 313 | } | 309 | } |
| 314 | 310 | ||
| 315 | export async function favsToHotswap() { | 311 | export async function favsToHotswap() { |
| @@ -28,6 +28,7 @@ import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js'; | |||
| 28 | import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | 28 | import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 29 | import { renderTemplateAsync } from './templates.js'; | 29 | import { renderTemplateAsync } from './templates.js'; |
| 30 | import { t, translate } from './i18n.js'; | 30 | import { t, translate } from './i18n.js'; |
| 31 | import { accountStorage } from './util/AccountStorage.js'; | ||
| 31 | 32 | ||
| 32 | export { | 33 | export { |
| 33 | TAG_FOLDER_TYPES, | 34 | TAG_FOLDER_TYPES, |
| @@ -64,6 +65,12 @@ function getFilterHelper(listSelector) { | |||
| 64 | return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter; | 65 | return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter; |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 68 | const ACTIONABLE_FILTER_STORAGE_KEYS = Object.freeze({ | ||
| 69 | GROUP: 'TagFilterState_GROUP', | ||
| 70 | FAV: 'TagFilterState_FAV', | ||
| 71 | FOLDER: 'TagFilterState_FOLDER', | ||
| 72 | }); | ||
| 73 | |||
| 67 | /** @enum {number} */ | 74 | /** @enum {number} */ |
| 68 | export const tag_filter_type = { | 75 | export const tag_filter_type = { |
| 69 | character: 0, | 76 | character: 0, |
| @@ -331,12 +338,14 @@ function getTagBlock(tag, entities, hidden = 0, isUseless = false) { | |||
| 331 | 338 | ||
| 332 | /** | 339 | /** |
| 333 | * Applies the favorite filter to the character list. | 340 | * Applies the favorite filter to the character list. |
| 334 | * @param {FilterHelper} filterHelper Instance of FilterHelper class. | 341 | * @param {FilterHelper} _filterHelper Instance of FilterHelper class. Unused since it needs to be applied to both filters. |
| 335 | */ | 342 | */ |
| 336 | function filterByFav(filterHelper) { | 343 | function filterByFav(_filterHelper) { |
| 337 | const state = toggleTagThreeState($(this)); | 344 | const state = toggleTagThreeState($(this)); |
| 338 | ACTIONABLE_TAGS.FAV.filter_state = state; | 345 | ACTIONABLE_TAGS.FAV.filter_state = state; |
| 339 | filterHelper.setFilterData(FILTER_TYPES.FAV, state); | 346 | accountStorage.setItem(ACTIONABLE_FILTER_STORAGE_KEYS.FAV, state); |
| 347 | entitiesFilter.setFilterData(FILTER_TYPES.FAV, state); | ||
| 348 | groupCandidatesFilter.setFilterData(FILTER_TYPES.FAV, state); | ||
| 340 | } | 349 | } |
| 341 | 350 | ||
| 342 | /** | 351 | /** |
| @@ -346,6 +355,7 @@ function filterByFav(filterHelper) { | |||
| 346 | function filterByGroups(filterHelper) { | 355 | function filterByGroups(filterHelper) { |
| 347 | const state = toggleTagThreeState($(this)); | 356 | const state = toggleTagThreeState($(this)); |
| 348 | ACTIONABLE_TAGS.GROUP.filter_state = state; | 357 | ACTIONABLE_TAGS.GROUP.filter_state = state; |
| 358 | accountStorage.setItem(ACTIONABLE_FILTER_STORAGE_KEYS.GROUP, state); | ||
| 349 | filterHelper.setFilterData(FILTER_TYPES.GROUP, state); | 359 | filterHelper.setFilterData(FILTER_TYPES.GROUP, state); |
| 350 | } | 360 | } |
| 351 | 361 | ||
| @@ -363,6 +373,7 @@ function filterByFolder(filterHelper) { | |||
| 363 | 373 | ||
| 364 | const state = toggleTagThreeState($(this)); | 374 | const state = toggleTagThreeState($(this)); |
| 365 | ACTIONABLE_TAGS.FOLDER.filter_state = state; | 375 | ACTIONABLE_TAGS.FOLDER.filter_state = state; |
| 376 | accountStorage.setItem(ACTIONABLE_FILTER_STORAGE_KEYS.FOLDER, state); | ||
| 366 | filterHelper.setFilterData(FILTER_TYPES.FOLDER, state); | 377 | filterHelper.setFilterData(FILTER_TYPES.FOLDER, state); |
| 367 | } | 378 | } |
| 368 | 379 | ||
| @@ -2220,6 +2231,36 @@ function extractCharacterAvatar(avatarSrc) { | |||
| 2220 | } | 2231 | } |
| 2221 | } | 2232 | } |
| 2222 | 2233 | ||
| 2234 | function restoreSavedTagFilters() { | ||
| 2235 | try { | ||
| 2236 | const validStates = new Set(Object.keys(FILTER_STATES)); | ||
| 2237 | const readState = (/** @type {string} */ storageKey) => { | ||
| 2238 | const v = accountStorage.getItem(storageKey); | ||
| 2239 | return v && validStates.has(v) ? v : null; | ||
| 2240 | }; | ||
| 2241 | |||
| 2242 | const favState = readState(ACTIONABLE_FILTER_STORAGE_KEYS.FAV); | ||
| 2243 | const groupState = readState(ACTIONABLE_FILTER_STORAGE_KEYS.GROUP); | ||
| 2244 | const folderState = readState(ACTIONABLE_FILTER_STORAGE_KEYS.FOLDER); | ||
| 2245 | |||
| 2246 | if (favState) { | ||
| 2247 | ACTIONABLE_TAGS.FAV.filter_state = favState; | ||
| 2248 | entitiesFilter.setFilterData(FILTER_TYPES.FAV, favState, true); | ||
| 2249 | groupCandidatesFilter.setFilterData(FILTER_TYPES.FAV, favState, true); | ||
| 2250 | } | ||
| 2251 | if (groupState) { | ||
| 2252 | ACTIONABLE_TAGS.GROUP.filter_state = groupState; | ||
| 2253 | entitiesFilter.setFilterData(FILTER_TYPES.GROUP, groupState, true); | ||
| 2254 | } | ||
| 2255 | if (folderState) { | ||
| 2256 | ACTIONABLE_TAGS.FOLDER.filter_state = folderState; | ||
| 2257 | entitiesFilter.setFilterData(FILTER_TYPES.FOLDER, folderState, true); | ||
| 2258 | } | ||
| 2259 | } catch (e) { | ||
| 2260 | console.warn('Failed to restore actionable filter states from account storage', e); | ||
| 2261 | } | ||
| 2262 | } | ||
| 2263 | |||
| 2223 | export function initTags() { | 2264 | export function initTags() { |
| 2224 | createTagInput('#tagInput', '#tagList', { tagOptions: { removable: true } }); | 2265 | createTagInput('#tagInput', '#tagList', { tagOptions: { removable: true } }); |
| 2225 | createTagInput('#groupTagInput', '#groupTagList', { tagOptions: { removable: true } }); | 2266 | createTagInput('#groupTagInput', '#groupTagList', { tagOptions: { removable: true } }); |
| @@ -2281,4 +2322,5 @@ export function initTags() { | |||
| 2281 | } | 2322 | } |
| 2282 | 2323 | ||
| 2283 | registerTagsSlashCommands(); | 2324 | registerTagsSlashCommands(); |
| 2325 | restoreSavedTagFilters(); | ||
| 2284 | } | 2326 | } |