Ver Fonte

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
Inverle há 8 meses atrás
pai
commit
6744a2fdce
1 ficheiros alterados com 82 adições e 76 exclusões
  1. 82 76
      p/scripts/main.js

+ 82 - 76
p/scripts/main.js

@@ -212,85 +212,88 @@ function removeArticle(div) {
 const pending_entries = {};
 const pending_entries = {};
 let mark_read_queue = [];
 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 (!queue || queue.length === 0) {
 		if (callback) {
 		if (callback) {
 			callback();
 			callback();
 		}
 		}
 		return;
 		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;
 let send_mark_read_queue_timeout = 0;
@@ -2096,15 +2099,18 @@ function init_normal() {
 	init_actualize();
 	init_actualize();
 	faviconNbUnread();
 	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() {
 function init_main_beforeDOM() {