From cd509bbc68a4833635ac33a0ba38ce4abb3b739f Mon Sep 17 00:00:00 2001 From: Merci Jacob Date: Thu, 13 Feb 2025 16:01:06 +0200 Subject: [PATCH] fix(frontend): ensure that a filter operation updates the cached pages results --- modules/core/js_modules/Hm_MessagesStore.js | 11 +++++ modules/core/js_modules/actions/pagination.js | 8 ++-- .../js_modules/actions/sortCombinedLists.js | 6 +-- modules/core/js_modules/route_handlers.js | 2 +- modules/core/js_modules/utils/sortable.js | 4 +- modules/core/navigation/navigation.js | 4 ++ modules/core/navigation/utils.js | 9 ++-- modules/core/site.js | 20 ++++++--- modules/github/js_modules/route_handlers.js | 4 +- modules/imap/js_modules/route_handlers.js | 2 +- modules/imap/site.js | 43 ++++++++++++------- 11 files changed, 75 insertions(+), 38 deletions(-) diff --git a/modules/core/js_modules/Hm_MessagesStore.js b/modules/core/js_modules/Hm_MessagesStore.js index 60997ae6d..508fbf74d 100644 --- a/modules/core/js_modules/Hm_MessagesStore.js +++ b/modules/core/js_modules/Hm_MessagesStore.js @@ -140,6 +140,17 @@ class Hm_MessagesStore { } } + + updateRow(uid, html) { + const rows = Object.entries(this.rows); + const row = this.getRowByUid(uid)?.value; + if (row) { + const objectRows = Object.fromEntries(rows); + objectRows[row[0]]['0'] = html; + this.rows = objectRows; + this.#saveToLocalStorage(); + } + } #fetch(hideLoadingState = false) { return new Promise((resolve, reject) => { diff --git a/modules/core/js_modules/actions/pagination.js b/modules/core/js_modules/actions/pagination.js index 5987912b3..562a09822 100644 --- a/modules/core/js_modules/actions/pagination.js +++ b/modules/core/js_modules/actions/pagination.js @@ -20,7 +20,7 @@ async function nextPage() { const nextPage = parseInt(currentPage) + 1; - const store = new Hm_MessagesStore(getListPathParam(), currentPage, getParam('keyword')); + const store = new Hm_MessagesStore(getListPathParam(), currentPage, `${getParam('keyword')}_${getParam('filter')}`); store.load(false, false, true); await changePage(nextPage, this, store.offsets); @@ -33,7 +33,7 @@ async function previousPage() { let offsets = ''; if (previousPage > 1) { - const store = new Hm_MessagesStore(getListPathParam(), previousPage - 1, getParam('keyword')); + const store = new Hm_MessagesStore(getListPathParam(), previousPage - 1, `${getParam('keyword')}_${getParam('filter')}`); store.load(false, false, true); offsets = store.offsets; } @@ -61,11 +61,11 @@ async function changePage(toPage, button, offsets) { history.pushState(history.state, "", url.toString()); window.location.next = url.search; - const messagesStore = new Hm_MessagesStore(getListPathParam(), toPage, getParam('keyword')); + const messagesStore = new Hm_MessagesStore(getListPathParam(), toPage, `${getParam('keyword')}_${getParam('filter')}`); try { await messagesStore.load(); Hm_Utils.tbody().attr('id', messagesStore.list); - display_imap_mailbox(messagesStore.rows, null, messagesStore.list); + display_imap_mailbox(messagesStore.rows, null, messagesStore.list, messagesStore); $(".pagination .current").text(toPage); } catch (error) { Hm_Utils.add_sys_message("Failed to fetch content", "danger"); diff --git a/modules/core/js_modules/actions/sortCombinedLists.js b/modules/core/js_modules/actions/sortCombinedLists.js index 52160a34f..09a0afdee 100644 --- a/modules/core/js_modules/actions/sortCombinedLists.js +++ b/modules/core/js_modules/actions/sortCombinedLists.js @@ -2,13 +2,13 @@ async function sortCombinedLists(sortValue) { const url = new URL(window.location.href); url.searchParams.set('sort', sortValue); - history.pushState(null, null, url.toString()); + history.pushState(history.state, null, url.toString()); location.next = url.search; - const messagesStore = new Hm_MessagesStore(getListPathParam(), getParam('page'), getParam('keyword')); + const messagesStore = new Hm_MessagesStore(getListPathParam(), getParam('page'), `${getParam('keyword')}_${getParam('filter')}`); try { await messagesStore.load(true); Hm_Utils.tbody().attr('id', messagesStore.list); - display_imap_mailbox(messagesStore.rows, null, messagesStore.list); + display_imap_mailbox(messagesStore.rows, messagesStore.list, messagesStore); } catch (error) { Hm_Utils.add_sys_message('Failed to load messages', 'danger'); } diff --git a/modules/core/js_modules/route_handlers.js b/modules/core/js_modules/route_handlers.js index f13e9afe3..7cad2fdb1 100644 --- a/modules/core/js_modules/route_handlers.js +++ b/modules/core/js_modules/route_handlers.js @@ -70,7 +70,7 @@ function applyInfoPageHandlers() { function applyMessaleListPageHandlers(routeParams) { sortHandlerForMessageListAndSearchPage(); Hm_Message_List.set_row_events(); - const messagesStore = new Hm_MessagesStore(routeParams.list_path, routeParams.list_page, routeParams.keyword); + const messagesStore = new Hm_MessagesStore(routeParams.list_path, routeParams.list_page, `${routeParams.keyword}_${routeParams.filter}`); Hm_Utils.tbody().attr('id', messagesStore.list); $('.core_msg_control').on("click", function(e) { diff --git a/modules/core/js_modules/utils/sortable.js b/modules/core/js_modules/utils/sortable.js index e64f68923..447c35249 100644 --- a/modules/core/js_modules/utils/sortable.js +++ b/modules/core/js_modules/utils/sortable.js @@ -76,13 +76,13 @@ function handleMessagesDragAndDrop() { {'name': 'imap_move_page', 'value': page}, {'name': 'imap_move_action', 'value': 'move'}], async (res) =>{ - const store = new Hm_MessagesStore(getListPathParam(), Hm_Utils.get_url_page_number(), getParam('keyword')); + const store = new Hm_MessagesStore(getListPathParam(), Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); await store.load(false, true, true); const moveResponses = Object.values(res['move_responses']); moveResponses.forEach((response) => { store.removeRow(response.oldUid); }); - display_imap_mailbox(store.rows, store.list); + display_imap_mailbox(store.rows, store.list, store); } ); diff --git a/modules/core/navigation/navigation.js b/modules/core/navigation/navigation.js index 18d103a8a..c4dff4f58 100644 --- a/modules/core/navigation/navigation.js +++ b/modules/core/navigation/navigation.js @@ -11,6 +11,9 @@ window.addEventListener('popstate', function(event) { $('#cypht-main').replaceWith(event.state.main); loadCustomScripts(event.state.head); } + + window.location.next = window.location.search; + const unMountCallback = renderPage(window.location.href); if (unMountCallback) { @@ -114,6 +117,7 @@ function renderPage(href) { if (page) { const route = ROUTES.find(route => route.page === page); const routeParams = Object.fromEntries(searchParams.entries()); + if (route) { const unMountCallback = route.handler(routeParams, url.hash?.substring(1)); return unMountCallback; diff --git a/modules/core/navigation/utils.js b/modules/core/navigation/utils.js index 463781160..828f0d838 100644 --- a/modules/core/navigation/utils.js +++ b/modules/core/navigation/utils.js @@ -8,18 +8,19 @@ function hideRoutingToast() { window.routingToast = null; } +// Undefined is used as the default value instead of null to comply with the route handlers, which also use undefined as the default value. function getListPathParam() { - return new URLSearchParams(window.location.next || window.location.search).get('list_path') + return new URLSearchParams(window.location.next || window.location.search).get('list_path') ?? undefined; } function getMessageUidParam() { - return new URLSearchParams(window.location.next || window.location.search).get('uid') + return new URLSearchParams(window.location.next || window.location.search).get('uid') ?? undefined; } function getPageNameParam() { - return new URLSearchParams(window.location.next || window.location.search).get('page') + return new URLSearchParams(window.location.next || window.location.search).get('page') ?? undefined; } function getParam(param) { - return new URLSearchParams(window.location.next || window.location.search).get(param) + return new URLSearchParams(window.location.next || window.location.search).get(param) ?? undefined; } diff --git a/modules/core/site.js b/modules/core/site.js index fbe321f0f..900d56c81 100644 --- a/modules/core/site.js +++ b/modules/core/site.js @@ -248,11 +248,11 @@ var Hm_Ajax_Request = function() { return { if (name === getListPathParam()) { Hm_Folders.unread_counts[name] = res.folder_status[name]['unseen']; Hm_Folders.update_unread_counts(); - const messages = new Hm_MessagesStore(name, Hm_Utils.get_url_page_number(), getParam('keyword')); + const messages = new Hm_MessagesStore(name, Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); messages.load().then(() => { if (messages.count != res.folder_status[name].messages) { messages.load(true).then(() => { - display_imap_mailbox(messages.rows, messages.list); + display_imap_mailbox(messages.rows, messages.list, messages); }) } }); @@ -515,11 +515,21 @@ function Message_List() { fixLtrInRtl(); }; - this.update = function(msgs, id) { + this.update = function(msgs, id, store) { Hm_Utils.tbody(id).html(''); for (const index in msgs) { const row = msgs[index][0]; - Hm_Utils.tbody(id).append(row); + Hm_Utils.tbody(id).append(row).find('a').each(function() { + const link = $(this); + const filterParams = ["keyword", "filter"]; + const url = new URL(link.attr('href'), location.href); + filterParams.forEach(param => { + url.searchParams.set(param, getParam(param)); + }); + link.attr('href', url.toString()); + const row = link.closest('tr'); + store.updateRow(row.data('uid'), row.prop('outerHTML')); + }); } }; @@ -858,7 +868,7 @@ function Message_List() { let nextUrl; const target = $('.msg_headers tr').last(); - const messages = new Hm_MessagesStore(lisPath, Hm_Utils.get_url_page_number(), getParam('keyword')); + const messages = new Hm_MessagesStore(lisPath, Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); messages.load(false, true); const next = messages.getNextRowForMessage(msgUid); const prev = messages.getPreviousRowForMessage(msgUid); diff --git a/modules/github/js_modules/route_handlers.js b/modules/github/js_modules/route_handlers.js index f08293566..90e8c8ea7 100644 --- a/modules/github/js_modules/route_handlers.js +++ b/modules/github/js_modules/route_handlers.js @@ -31,7 +31,7 @@ function applyGithubMessageListPageHandler(routeParams) { if (routeParams.list_path === 'github_all') { const dataSources = hm_data_sources().map((source) => source.id); dataSources.forEach((id) => { - const messages = new Hm_MessagesStore('github_' + id, Hm_Utils.get_url_page_number(), getParam('keyword')); + const messages = new Hm_MessagesStore('github_' + id, Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); messages.load().then(store => { for (const row of Object.values(store.rows)) { Hm_Utils.tbody().append(row['0']); @@ -58,7 +58,7 @@ function applyGithubMessageListPageHandler(routeParams) { function refreshAll(dataSources, background = false, abortController) { dataSources.forEach((id) => { - const messages = new Hm_MessagesStore('github_' + id, Hm_Utils.get_url_page_number(), getParam('keyword'), {}, abortController); + const messages = new Hm_MessagesStore('github_' + id, Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`, {}, abortController); messages.load(true, background).then(store => { const rows = Object.values(store.rows); for (const index in rows) { diff --git a/modules/imap/js_modules/route_handlers.js b/modules/imap/js_modules/route_handlers.js index e3e7e7193..1c868a343 100644 --- a/modules/imap/js_modules/route_handlers.js +++ b/modules/imap/js_modules/route_handlers.js @@ -18,7 +18,7 @@ function applyImapMessageContentPageHandlers(routeParams) { imap_setup_message_view_page(routeParams.uid, null, routeParams.list_path, routeParams.list_parent, imap_setup_tags); imap_setup_snooze(); - const messages = new Hm_MessagesStore(routeParams.list_path, routeParams.list_page, routeParams.keyword); + const messages = new Hm_MessagesStore(routeParams.list_path, routeParams.list_page, `${routeParams.keyword}_${routeParams.filter}`); messages.load(false); const next = messages.getNextRowForMessage(routeParams.uid); const prev = messages.getPreviousRowForMessage(routeParams.uid); diff --git a/modules/imap/site.js b/modules/imap/site.js index 492d72ea3..579490c90 100644 --- a/modules/imap/site.js +++ b/modules/imap/site.js @@ -382,13 +382,24 @@ var remove_from_cached_imap_pages = function(msg_cache_key) { } async function select_imap_folder(path, page = 1,reload, processInTheBackground = false, abortController = null) { - const messages = new Hm_MessagesStore(path, page, getParam('keyword'), null, abortController); + const messages = new Hm_MessagesStore(path, page, `${getParam('keyword')}_${getParam('filter')}`, null, abortController); await messages.load(reload, processInTheBackground).then(() => { if (processInTheBackground) { const rows = Object.values(messages.rows); for (const index in rows) { - const row = rows[index]?.[0]; - const rowUid = $(row).data('uid'); + const row = $(rows[index]?.[0]); + const rowUid = row.data('uid'); + row.find('a').each(function() { + const link = $(this); + const filterParams = ["keyword", "filter"]; + const url = new URL(link.attr('href'), location.href); + filterParams.forEach(param => { + url.searchParams.set(param, getParam(param)); + }); + link.attr('href', url.toString()); + const row = link.closest('tr'); + messages.updateRow(rowUid, row.prop('outerHTML')); + }); const tableRow = Hm_Utils.tbody(messages.list).find(`tr[data-uid="${rowUid}"]`); if (!tableRow.length) { if (Hm_Utils.rows(messages.list).length >= index) { @@ -406,7 +417,7 @@ async function select_imap_folder(path, page = 1,reload, processInTheBackground } }); } else { - display_imap_mailbox(messages.rows, messages.list); + display_imap_mailbox(messages.rows, messages.list, messages); } if (messages.pages) { showPagination(messages.pages); @@ -440,12 +451,12 @@ var setup_imap_folder_page = async function(listPath, listPage = 1) { e.preventDefault(); $('#imap_filter_form').trigger('submit'); }); - $('.imap_keyword').on('search', function(e) { + $('.imap_keyword').on('change', function(e) { e.preventDefault(); $('#imap_filter_form').trigger('submit'); }); - const hadLocalData = new Hm_MessagesStore(listPath, listPage, getParam('keyword')).hasLocalData(); + const hadLocalData = new Hm_MessagesStore(listPath, listPage, `${getParam('keyword')}_${getParam('filter')}`).hasLocalData(); await select_imap_folder(listPath, listPage); handleMessagesDragAndDrop(); @@ -469,13 +480,13 @@ $(document).on('submit', '#imap_filter_form', async function(event) { event.preventDefault(); const url = new URL(location.href); url.search = $(this).serialize(); - history.replaceState(null, '', url); + history.pushState(history.state, "", url.toString()); location.next = url.search; try { - const messages = new Hm_MessagesStore(getListPathParam(), Hm_Utils.get_url_page_number(), getParam('keyword')); + const messages = new Hm_MessagesStore(getListPathParam(), Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); await messages.load(!messages.hasLocalData()); Hm_Utils.tbody().attr('id', messages.list); - display_imap_mailbox(messages.rows, messages.list); + display_imap_mailbox(messages.rows, messages.list, messages); if (messages.pages) { showPagination(messages.pages); } @@ -484,10 +495,10 @@ $(document).on('submit', '#imap_filter_form', async function(event) { } }); -var display_imap_mailbox = function(rows, id) { +var display_imap_mailbox = function(rows, id, store) { Hm_Message_List.toggle_msg_controls(); if (rows) { - Hm_Message_List.update(rows, id); + Hm_Message_List.update(rows, id, store); Hm_Message_List.check_empty_list(); $('input[type=checkbox]').on("click", function(e) { Hm_Message_List.toggle_msg_controls(); @@ -521,7 +532,7 @@ async function markPrefetchedMessagesAsRead(uid) { const detail = Hm_Utils.parse_folder_path(listPath, 'imap'); const msgId = `${detail.type}_${detail.server_id}_${uid}_${detail.folder}`; - const messages = new Hm_MessagesStore(listPath, Hm_Utils.get_url_page_number(), getParam('keyword')); + const messages = new Hm_MessagesStore(listPath, Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); await messages.load(false, true); if (!messages.flagAsReadOnOpen) { return; @@ -976,7 +987,7 @@ var imap_perform_move_copy = function(dest_id, context, action = null) { {'name': 'imap_move_action', 'value': action}], async function(res) { var index; - const store = new Hm_MessagesStore(getListPathParam(), Hm_Utils.get_url_page_number(), getParam('keyword')); + const store = new Hm_MessagesStore(getListPathParam(), Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); await store.load(false, true, true); const moveResponses = Object.values(res['move_responses']); moveResponses.forEach((response) => { @@ -990,7 +1001,7 @@ var imap_perform_move_copy = function(dest_id, context, action = null) { } } if (getListPathParam().substr(0, 4) === 'imap') { - display_imap_mailbox(store.rows, store.list); + display_imap_mailbox(store.rows, store.list, store); } else { Hm_Message_List.load_sources(); @@ -1171,14 +1182,14 @@ var imap_setup_snooze = function() { const snoozedMessages = Object.values(res['snoozed_messages']); if (snoozedMessages.length) { const path = getParam("list_parent") || getListPathParam(); - const store = new Hm_MessagesStore(path, Hm_Utils.get_url_page_number(), getParam('keyword')); + const store = new Hm_MessagesStore(path, Hm_Utils.get_url_page_number(), `${getParam('keyword')}_${getParam('filter')}`); await store.load(false, true, true); snoozedMessages.forEach((msg) => { store.removeRow(msg); }); if (getPageNameParam() == 'message_list') { - display_imap_mailbox(store.rows, store.list); + display_imap_mailbox(store.rows, store.list, store); } Hm_Folders.reload_folders(true);