-
Notifications
You must be signed in to change notification settings - Fork 164
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1252 from jacob-js/enh-perf
Improve messages caching to ensure a message isn't fetched more than once when viewing its content
- Loading branch information
Showing
9 changed files
with
326 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/** | ||
* An abstraction object of the Message_List focused on state management without UI interaction. | ||
*/ | ||
class Hm_MessagesStore { | ||
|
||
/** | ||
* @typedef {Object} RowObject | ||
* @property {String} 0 - The HTML string of the row | ||
* @property {String} 1 - The IMAP key | ||
*/ | ||
|
||
/** | ||
* @typedef {Array} RowEntry | ||
* @property {String} 0 - The IMAP key | ||
* @property {RowObject} 1 - An object containing the row message and the IMAP key | ||
*/ | ||
|
||
constructor(path, page, rows = {}) { | ||
this.path = path; | ||
this.list = path + '_' + page; | ||
this.rows = rows; | ||
this.links = ""; | ||
this.count = 0; | ||
this.flagAsReadOnOpen = true; | ||
} | ||
|
||
/** | ||
* | ||
* @returns {Promise<Array<String>>} | ||
*/ | ||
async load(reload = false, hideLoadingState = false) { | ||
const storedMessages = this.#retrieveFromLocalStorage(); | ||
if (storedMessages && !reload) { | ||
this.rows = storedMessages.rows; | ||
this.links = storedMessages.links; | ||
this.count = storedMessages.count; | ||
this.flagAsReadOnOpen = storedMessages.flagAsReadOnOpen; | ||
return this; | ||
} | ||
|
||
const { formatted_message_list: updatedMessages, page_links: pageLinks, folder_status, do_not_flag_as_read_on_open } = await this.#fetch(hideLoadingState); | ||
|
||
this.count = Object.values(folder_status)[0].messages; | ||
this.links = pageLinks; | ||
this.rows = updatedMessages; | ||
this.flagAsReadOnOpen = !do_not_flag_as_read_on_open; | ||
|
||
this.#saveToLocalStorage(); | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* | ||
* @param {String} uid the id of the message to be marked as read | ||
* @returns {Boolean} true if the message was marked as read, false otherwise | ||
*/ | ||
markRowAsRead(uid) { | ||
const rows = Object.entries(this.rows); | ||
const row = this.#getRowByUid(uid)?.value; | ||
|
||
if (row) { | ||
const htmlRow = $(row[1]['0']); | ||
const wasUnseen = htmlRow.find('.unseen').length > 0 || htmlRow.hasClass('unseen'); | ||
|
||
htmlRow.removeClass('unseen'); | ||
htmlRow.find('.unseen').removeClass('unseen'); | ||
const objectRows = Object.fromEntries(rows); | ||
objectRows[row[0]]['0'] = htmlRow[0].outerHTML; | ||
|
||
this.rows = objectRows; | ||
this.#saveToLocalStorage(); | ||
|
||
return wasUnseen; | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* | ||
* @param {*} uid | ||
* @returns {RowObject|false} the next row entry if found, false otherwise | ||
*/ | ||
getNextRowForMessage(uid) { | ||
const rows = Object.entries(this.rows); | ||
const row = this.#getRowByUid(uid)?.index; | ||
|
||
if (row !== false) { | ||
const nextRow = rows[row + 1]; | ||
if (nextRow) { | ||
return nextRow[1]; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* | ||
* @param {*} uid | ||
* @returns {RowObject|false} the previous row entry if found, false otherwise | ||
*/ | ||
getPreviousRowForMessage(uid) { | ||
const rows = Object.entries(this.rows); | ||
const row = this.#getRowByUid(uid)?.index; | ||
if (row) { | ||
const previousRow = rows[row - 1]; | ||
if (previousRow) { | ||
return previousRow[1]; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
#fetch(hideLoadingState = false) { | ||
const detail = Hm_Utils.parse_folder_path(this.path, 'imap'); | ||
return new Promise((resolve, reject) => { | ||
Hm_Ajax.request( | ||
[ | ||
{ name: "hm_ajax_hook", value: "ajax_imap_folder_display" }, | ||
{ name: "imap_server_id", value: detail.server_id }, | ||
{ name: "folder", value: detail.folder }, | ||
], | ||
(response) => { | ||
resolve(response); | ||
}, | ||
[], | ||
hideLoadingState, | ||
undefined, | ||
reject | ||
); | ||
}); | ||
} | ||
|
||
#saveToLocalStorage() { | ||
Hm_Utils.save_to_local_storage(this.list, JSON.stringify({ rows: this.rows, links: this.links, count: this.count })); | ||
Hm_Utils.save_to_local_storage('flagAsReadOnOpen', this.flagAsReadOnOpen); | ||
} | ||
|
||
#retrieveFromLocalStorage() { | ||
const stored = Hm_Utils.get_from_local_storage(this.list); | ||
const flagAsReadOnOpen = Hm_Utils.get_from_local_storage('flagAsReadOnOpen'); | ||
if (stored) { | ||
return {...JSON.parse(stored), flagAsReadOnOpen: flagAsReadOnOpen !== 'false'}; | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* @typedef {Object} RowOutput | ||
* @property {Number} index - The index of the row | ||
* @property {RowEntry} value - The row entry | ||
* | ||
* @param {String} uid | ||
* @returns {RowOutput|false} row - The row object if found, false otherwise | ||
*/ | ||
#getRowByUid(uid) { | ||
const rows = Object.entries(this.rows); | ||
const row = rows.find(([key, value]) => $(value['0']).attr('data-uid') == uid); | ||
|
||
if (row) { | ||
const index = rows.indexOf(row); | ||
return { index, value: row }; | ||
} | ||
return false; | ||
} | ||
} | ||
|
||
[ | ||
Hm_MessagesStore | ||
].forEach((item) => { | ||
window[item.name] = item; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.