aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Inverle <inverle@proton.me> 2025-07-16 16:59:06 +0200
committerGravatar GitHub <noreply@github.com> 2025-07-16 16:59:06 +0200
commit6744a2fdceb7d362dcf61ef74c50f577b56406fb (patch)
tree26c962cfa0e36cc4d57533c8a1704e850424b1b4
parentedda6f0159e917e8ec35d2b5e677e5ce96408d96 (diff)
Fix mark as read request showing popup due to onbeforeunload (#7554)
* Prevent onbeforeunload from showing a popup before leaving * Send mark as read request when leaving and revert interval * Use visibilitychange event instead of onbeforeunload, and refactor send_mark_read_queue to use fetch * Move removed code to the new `catch` block * Refactor with async fetch
-rw-r--r--p/scripts/main.js158
1 files changed, 82 insertions, 76 deletions
diff --git a/p/scripts/main.js b/p/scripts/main.js
index 4566a1141..60912b349 100644
--- a/p/scripts/main.js
+++ b/p/scripts/main.js
@@ -212,85 +212,88 @@ function removeArticle(div) {
const pending_entries = {};
let mark_read_queue = [];
-function send_mark_read_queue(queue, asRead, callback) {
+async function send_mark_read_queue(queue, asRead, callback) {
if (!queue || queue.length === 0) {
if (callback) {
callback();
}
return;
}
- const req = new XMLHttpRequest();
- req.open('POST', '.?c=entry&a=read' + (asRead ? '' : '&is_read=0'), true);
- req.responseType = 'json';
- req.onerror = function (e) {
- for (let i = queue.length - 1; i >= 0; i--) {
- const div = document.getElementById('flux_' + queue[i]);
- div.querySelectorAll('a.read > .icon').forEach(icon => {
- icon.outerHTML = div.classList.contains('not_read') ? context.icons.unread : context.icons.read;
- });
- delete pending_entries['flux_' + queue[i]];
- }
- badAjax(this.status == 403);
- };
- req.onload = function (e) {
- if (this.status != 200) {
- return req.onerror(e);
- }
- const json = xmlHttpRequestJson(this);
- if (!json) {
- return req.onerror(e);
- }
- for (let i = queue.length - 1; i >= 0; i--) {
- const div = document.getElementById('flux_' + queue[i]);
- const myIcons = context.icons;
- let inc = 0;
- if (div.classList.contains('not_read')) {
- div.classList.remove('not_read');
- div.querySelectorAll('a.read').forEach(function (a) {
- a.href = a.href.replace('&is_read=0', '') + '&is_read=1';
- });
- div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.read; });
- inc--;
- if (context.auto_remove_article) {
- removeArticle(div);
- }
- } else {
- div.classList.add('not_read');
- div.classList.add('keep_unread'); // Split for IE11
- div.querySelectorAll('a.read').forEach(function (a) {
- a.href = a.href.replace('&is_read=1', '');
+ let json;
+ try {
+ const resp = await fetch('.?c=entry&a=read' + (asRead ? '' : '&is_read=0'), {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json; charset=UTF-8'
+ },
+ body: JSON.stringify({
+ ajax: true,
+ _csrf: context.csrf,
+ id: queue,
+ }),
+ keepalive: true
+ });
+ if (!resp.ok) {
+ for (let i = queue.length - 1; i >= 0; i--) {
+ const div = document.getElementById('flux_' + queue[i]);
+ div.querySelectorAll('a.read > .icon').forEach(icon => {
+ icon.outerHTML = div.classList.contains('not_read') ? context.icons.unread : context.icons.read;
});
- div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.unread; });
- inc++;
+ delete pending_entries['flux_' + queue[i]];
}
- const feed_link = div.querySelector('.website > a, a.website');
- if (feed_link) {
- const feed_url = feed_link.href;
- const feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
- incUnreadsFeed(div, feed_id, inc);
- }
- delete pending_entries['flux_' + queue[i]];
- }
- faviconNbUnread();
- if (json.tags) {
- const tagIds = Object.keys(json.tags);
- for (let i = tagIds.length - 1; i >= 0; i--) {
- const tagId = tagIds[i];
- incUnreadsTag(tagId, (asRead ? -1 : 1) * json.tags[tagId].length);
+ badAjax(resp.status == 403);
+ return;
+ }
+ json = await resp.json();
+ } catch (e) {
+ console.error(e.message);
+ badAjax();
+ return;
+ }
+ for (let i = queue.length - 1; i >= 0; i--) {
+ const div = document.getElementById('flux_' + queue[i]);
+ const myIcons = context.icons;
+ let inc = 0;
+ if (div.classList.contains('not_read')) {
+ div.classList.remove('not_read');
+ div.querySelectorAll('a.read').forEach(function (a) {
+ a.href = a.href.replace('&is_read=0', '') + '&is_read=1';
+ });
+ div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.read; });
+ inc--;
+ if (context.auto_remove_article) {
+ removeArticle(div);
}
+ } else {
+ div.classList.add('not_read');
+ div.classList.add('keep_unread'); // Split for IE11
+ div.querySelectorAll('a.read').forEach(function (a) {
+ a.href = a.href.replace('&is_read=1', '');
+ });
+ div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.unread; });
+ inc++;
}
- toggle_bigMarkAsRead_button();
- onScroll();
- if (callback) {
- callback();
+ const feed_link = div.querySelector('.website > a, a.website');
+ if (feed_link) {
+ const feed_url = feed_link.href;
+ const feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
+ incUnreadsFeed(div, feed_id, inc);
}
- };
- req.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
- req.send(JSON.stringify({
- ajax: true,
- _csrf: context.csrf,
- id: queue,
- }));
+ delete pending_entries['flux_' + queue[i]];
+ }
+ faviconNbUnread();
+ if (json.tags) {
+ const tagIds = Object.keys(json.tags);
+ for (let i = tagIds.length - 1; i >= 0; i--) {
+ const tagId = tagIds[i];
+ incUnreadsTag(tagId, (asRead ? -1 : 1) * json.tags[tagId].length);
+ }
+ }
+ toggle_bigMarkAsRead_button();
+ onScroll();
+ if (callback) {
+ callback();
+ }
}
let send_mark_read_queue_timeout = 0;
@@ -2096,15 +2099,18 @@ function init_normal() {
init_actualize();
faviconNbUnread();
- window.onbeforeunload = function (e) {
- const sidebar = document.getElementById('sidebar');
- if (sidebar) { // Save sidebar scroll position
- sessionStorage.setItem('FreshRSS_sidebar_scrollTop', sidebar.scrollTop);
- }
- if (mark_read_queue && mark_read_queue.length > 0) {
- return false;
+ document.addEventListener("visibilitychange", () => {
+ if (document.visibilityState === "hidden") {
+ const sidebar = document.getElementById('sidebar');
+ if (sidebar) { // Save sidebar scroll position
+ sessionStorage.setItem('FreshRSS_sidebar_scrollTop', sidebar.scrollTop);
+ }
+ if (mark_read_queue && mark_read_queue.length > 0) {
+ clearTimeout(send_mark_read_queue_timeout);
+ send_mark_queue_tick(null);
+ }
}
- };
+ });
}
function init_main_beforeDOM() {