Anakunda / Gazelle Forum: New Posts Indicator

// ==UserScript==
// @name         Gazelle Forum: New Posts Indicator
// @namespace    https://greasyfork.org/users/321857-anakunda#user-script-list
// @version      1.01.0
// @author       Anakunda
// @copyright    2020, Anakunda (https://greasyfork.org/users/321857-anakunda#user-script-list)
// @license      GPL-3.0-or-later
// @match        https://*/forums.php?action=viewthread&threadid=*
// @match        https://*/forums.php?page=4&action=viewthread&threadid=*
// @connect      *
// @grant        GM_getValue
// @grant        GM_setValue
// @require      https://openuserjs.org/src/libs/Anakunda/libLocks.min.js
// @require      https://openuserjs.org/src/libs/Anakunda/gazelleApiLib.js
// ==/UserScript==

'use strict';

const interval = 15;

let threadId = new URLSearchParams(document.location.search);
if (threadId.has('threadid')) threadId = parseInt(threadId.get('threadid')); else throw 'Thread Id missing';
let postBody = document.querySelector('textarea#quickpost');
if (postBody == null) throw 'Post body missing';
let replyControls = document.querySelector('form#quickpostform > div.preview_submit'), newPostsIndicator = null;
if (replyControls == null) throw 'Reply controls missing';
if (typeof GM_getValue == 'function') switch (document.domain) {
	case 'redacted.ch':
		var apiKey = GM_getValue('redacted_api_key');
		if (!apiKey) GM_setValue('redacted_api_key', '');
		break;
}

const getThreadSnapshot = (page = 999999) => queryAjaxAPI('forum', { type: 'viewthread', threadid: threadId, page: page });
let snapshot = getThreadSnapshot(), activeTimer;

function checkPosts() {
	snapshot.then(snapshot => getThreadSnapshot(snapshot.currentPage).then(function(response) {
		let now = new Date();
		console.debug(threadId, now.toLocaleTimeString(), response.pages, snapshot.pages,
			response.posts.length, snapshot.posts.length);
		if (response.pages <= snapshot.pages && response.posts.length <= snapshot.posts.length) return;
		activeTimer = clearInterval(activeTimer);
		if (newPostsIndicator == null) {
			newPostsIndicator = document.createElement('span');
			newPostsIndicator.style = 'margin-left: 3em; color: darkorange;';
			replyControls.append(newPostsIndicator);
		}
		newPostsIndicator.textContent = 'This thread received new post(s) [';
		let link = document.createElement('a');
		link.textContent = 'refresh';
		if (response.pages <= snapshot.pages || response.posts.length > snapshot.posts.length) {
			link.href = '#';
			link.onclick = function(evt) {
				document.location.reload();
				return false;
			};
		} else link.href = '/forums.php?action=viewthread&threadid=' + response.threadId +
			'&page=' + (response.currentPage + 1);
		newPostsIndicator.append(link);
		newPostsIndicator.append(']');
	}));
}

postBody.onfocus = function(evt) {
	if (activeTimer || newPostsIndicator != null) return;
	//console.debug('New thread posts monitor activated', evt);
	activeTimer = setInterval(checkPosts, interval * 1000);
	checkPosts();
};
postBody.onblur = function(evt) {
	if (!activeTimer) return;
	//console.debug('New thread posts monitor deactivated', evt);
	activeTimer = clearInterval(activeTimer);
	console.assert(activeTimer === undefined, 'activeTimer === undefined');
};