From 3c0db75c7976b07425724e1faa7d5c8a270d303f Mon Sep 17 00:00:00 2001 From: Merci Jacob <68013195+mercihabam@users.noreply.github.com> Date: Mon, 17 Feb 2025 14:22:53 +0200 Subject: [PATCH] fix(frontend/backend): address some of the many blocking issues (#1443) * fix(frontend): prevent Cypht-related mobile nav CSS attributes from overriding third-party styles * fix(backend): showing server sieve capabilities * fix(frontend): git revision link not opening the remote url * fix(frontend): fadeOutAndRemove should not only be extended to cash but also to jQuery * fix(frontend): refresh ui state when adding a server * fix(backend): adding accounts via files imports * fix(backend): downloading server accounts sample files in third-party softwares * fix elements spacing of the search page * fix(backend): offline error message when hihandling a message action or deleting a folder * fix(frontend): hide the refresh icon on the search page as it's replaced by the update button * fix(frontend): delete a saved search term * fix(backend): undefined array key warnings when listing folders' messages * fix(frontend): ensure that a search operation updates the cached pages results * fix(frontend): ensure that a filter operation updates the cached pages results * fix(frontend): when opening an unread message, the counter does not get updated * fix(frontend): Snooze - Pick a date does not show a date picke * fix(frontend): remove the deleted message from the store when a delete action has been performed --- .../data/server_accounts_sample.csv | 0 .../data/server_accounts_sample.yaml | 0 index.php | 1 + modules/core/js_modules/Hm_MessagesStore.js | 15 +++- modules/core/js_modules/[cash]/extend.js | 8 -- 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/message_list_functions.php | 4 +- modules/core/navigation/navigation.js | 8 +- modules/core/navigation/utils.js | 13 ++-- modules/core/site.css | 24 +++++- modules/core/site.js | 41 +++++++--- modules/developer/modules.php | 2 +- modules/github/js_modules/route_handlers.js | 4 +- modules/imap/functions.php | 4 +- modules/imap/handler_modules.php | 39 ++++++++-- modules/imap/js_modules/route_handlers.js | 8 +- modules/imap/site.js | 77 +++++++++++-------- modules/imap_folders/modules.php | 3 +- modules/nux/modules.php | 6 +- modules/nux/site.js | 7 +- modules/saved_searches/site.css | 1 - modules/saved_searches/site.js | 2 +- modules/sievefilters/modules.php | 2 +- modules/smtp/hm-smtp.php | 2 +- .../modules/core/message_list_functions.php | 6 +- tests/phpunit/modules/core/output_modules.php | 28 +++---- 29 files changed, 205 insertions(+), 120 deletions(-) rename {modules/nux/assets => assets}/data/server_accounts_sample.csv (100%) rename {modules/nux/assets => assets}/data/server_accounts_sample.yaml (100%) diff --git a/modules/nux/assets/data/server_accounts_sample.csv b/assets/data/server_accounts_sample.csv similarity index 100% rename from modules/nux/assets/data/server_accounts_sample.csv rename to assets/data/server_accounts_sample.csv diff --git a/modules/nux/assets/data/server_accounts_sample.yaml b/assets/data/server_accounts_sample.yaml similarity index 100% rename from modules/nux/assets/data/server_accounts_sample.yaml rename to assets/data/server_accounts_sample.yaml diff --git a/index.php b/index.php index 4e10632cb3..2675751b00 100644 --- a/index.php +++ b/index.php @@ -22,6 +22,7 @@ define('SITE_ID', ''); define('JS_HASH', ''); define('CSS_HASH', ''); +define('ASSETS_PATH', APP_PATH.'assets/'); /* show all warnings in debug mode */ if (DEBUG_MODE) { diff --git a/modules/core/js_modules/Hm_MessagesStore.js b/modules/core/js_modules/Hm_MessagesStore.js index ff4b5422f1..508fbf74d1 100644 --- a/modules/core/js_modules/Hm_MessagesStore.js +++ b/modules/core/js_modules/Hm_MessagesStore.js @@ -15,9 +15,9 @@ class Hm_MessagesStore { * @property {RowObject} 1 - An object containing the row message and the IMAP key */ - constructor(path, page = 1, rows = {}, abortController = new AbortController()) { + constructor(path, page = 1, filter = '', rows = {}, abortController = new AbortController()) { this.path = path; - this.list = path + '_' + page; + this.list = path + '_' + (filter ? filter + '_': '') + page; this.rows = rows; this.count = 0; this.flagAsReadOnOpen = true; @@ -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/[cash]/extend.js b/modules/core/js_modules/[cash]/extend.js index a1b29a427b..8f3ba950eb 100644 --- a/modules/core/js_modules/[cash]/extend.js +++ b/modules/core/js_modules/[cash]/extend.js @@ -40,14 +40,6 @@ $.fn.fadeOut = function(timeout = 600) { return this.css("opacity", 0) .css("transition", `opacity ${timeout}ms`) }; -$.fn.fadeOutAndRemove = function(timeout = 600) { - this.fadeOut(timeout) - var tm = setTimeout(() => { - this.remove(); - clearTimeout(tm) - }, timeout); - return this; -}; $.fn.modal = function(action) { const modalElement = this[0]; diff --git a/modules/core/js_modules/actions/pagination.js b/modules/core/js_modules/actions/pagination.js index 4bc70951b7..ffd7798387 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); + 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); + 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); + 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_Notices.show("Failed to fetch content", "danger"); diff --git a/modules/core/js_modules/actions/sortCombinedLists.js b/modules/core/js_modules/actions/sortCombinedLists.js index 97b55add64..7e7f2b1a51 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')); + 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_Notices.show('Failed to load messages', 'danger'); } diff --git a/modules/core/js_modules/route_handlers.js b/modules/core/js_modules/route_handlers.js index 83e5472def..607f3b8f9a 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); + 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 120b204ba1..447c352493 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()); + 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/message_list_functions.php b/modules/core/message_list_functions.php index 7950c36860..e3395294a8 100644 --- a/modules/core/message_list_functions.php +++ b/modules/core/message_list_functions.php @@ -446,7 +446,7 @@ function message_since_dropdown($since, $name, $output_mod, $original_default_va '-1 year' => 'Last year', '-5 years' => 'Last 5 years' ); - $res = ''; $reset = ''; foreach ($times as $val => $label) { $res .= ' 'To', 'CC' => 'Cc', ); - $res = ''; foreach ($flds as $val => $name) { $res .= '