From 94ed8835717df757fef6b0ae2d7cbb2d199ae4d8 Mon Sep 17 00:00:00 2001
From: Arkerthan <arkerthan@mailbox.org>
Date: Mon, 12 Sep 2022 18:39:29 +0200
Subject: [PATCH] Allow showing arbitrarily many reminder displays

---
 src/js/reminder.js                 | 91 +++++++++++++++++++++---------
 src/zz1-last/setupEventHandlers.js |  1 +
 2 files changed, 66 insertions(+), 26 deletions(-)

diff --git a/src/js/reminder.js b/src/js/reminder.js
index 719581a6c74..595923d3a6d 100644
--- a/src/js/reminder.js
+++ b/src/js/reminder.js
@@ -1,6 +1,9 @@
 App.Reminders = (function() {
-	const displayDiv = document.createElement("div");
-	const addDiv = document.createElement("div");
+	/**
+	 *  @type {Array<function():void>}
+	 */
+	let activeViewRefreshers = [];
+
 	return {
 		add: add,
 		list: list,
@@ -8,6 +11,7 @@ App.Reminders = (function() {
 		slaveDisplay: slaveDisplay,
 		slaveLink: slaveLink,
 		dialog: dialog,
+		clear: clearActive,
 	};
 
 	/**
@@ -15,10 +19,11 @@ App.Reminders = (function() {
 	 * @param {number} week
 	 * @param {string} [category]
 	 * @param {number} [slaveID]
+	 * @returns {boolean} Whether a reminder was actually added or we aborted.
 	 */
 	function add(message, week, category = "manual", slaveID = 0) {
 		if (message === "" || message === null) {
-			return;
+			return false;
 		}
 		const entry = {message: message, week: week, category: category};
 		if (slaveID) {
@@ -32,6 +37,7 @@ App.Reminders = (function() {
 		} else {
 			V.reminders.splice(index, 0, entry);
 		}
+		return true;
 	}
 
 	/**
@@ -52,28 +58,23 @@ App.Reminders = (function() {
 
 		const outerSpan = document.createElement("span");
 
-		function replace() {
-			App.UI.DOM.replace(outerSpan, list({maxFuture, filter, link}));
-			App.Utils.scheduleSidebarRefresh();
-		}
-
 		/**
 		 * @param {FC.ReminderEntry} entry
 		 */
 		function clearEntry(entry) {
 			V.reminders.splice(V.reminders.indexOf(entry), 1);
-			replace();
+			refreshActive();
 		}
 
 		// We only want to remove visible entries
 		function clearOverdue() {
 			V.reminders = V.reminders.filter(e => e.week >= V.week || e.week > V.week + maxFuture || !filter(e));
-			replace();
+			refreshActive();
 		}
 
 		function clearAll() {
 			V.reminders = V.reminders.filter(e => e.week > V.week + maxFuture || !filter(e));
-			replace();
+			refreshActive();
 		}
 
 		let overdue = 0;
@@ -126,25 +127,27 @@ App.Reminders = (function() {
 	}
 
 	/**
-	 * @param {function():void} refresh
 	 * @param {string} [category]
 	 * @param {number} [slaveID]
 	 * @returns {HTMLDivElement}
 	 */
-	function addField(refresh, category, slaveID) {
-		jQuery(addDiv).empty();
+	function addField(category, slaveID) {
+		const addDiv = document.createElement("div");
 
 		let entry = "";
 		let week = 0;
 
 		addDiv.append(
-			App.UI.DOM.makeTextBox("", v => { entry = v; }),
-			" in ", App.UI.DOM.makeTextBox(0, v => { week = v; }, true), " weeks.",
+			App.UI.DOM.makeTextBox("", v => {
+				entry = v;
+			}),
+			" in ", App.UI.DOM.makeTextBox(0, v => {
+				week = v;
+			}, true), " weeks.",
 			" ", App.UI.DOM.link("Add", () => {
-				add(entry, V.week + week, category, slaveID);
-				refresh();
-				App.Utils.scheduleSidebarRefresh();
-				jQuery(addDiv).append(addField(refresh, category, slaveID));
+				if (add(entry, V.week + week, category, slaveID)) {
+					refreshActive();
+				}
 			})
 		);
 
@@ -153,10 +156,22 @@ App.Reminders = (function() {
 
 	/**
 	 * @param {boolean} [link=false] show passage links
+	 * @param {HTMLElement} [displayDiv] Only to be used by the refresh functionality
 	 * @returns {HTMLElement}
 	 */
-	function fullDisplay(link) {
-		jQuery(displayDiv).empty();
+	function fullDisplay(link, displayDiv) {
+		if (displayDiv) {
+			// If displayDiv is given, it either is currently being shown or the tree it belonged to was removed from
+			// the page. In that case we don't need to refresh it ever again.
+			if (!displayDiv.isConnected) {
+				return null;
+			}
+			jQuery(displayDiv).empty();
+		} else {
+			displayDiv = document.createElement("div");
+		}
+		activeViewRefreshers.push(() => fullDisplay(link, displayDiv));
+
 		displayDiv.append(App.UI.DOM.makeElement("h2", "Reminders"));
 
 		const listEl = list({link});
@@ -165,17 +180,27 @@ App.Reminders = (function() {
 		}
 
 		displayDiv.append(App.UI.DOM.makeElement("h3", "Add new"));
-		displayDiv.append(App.UI.DOM.makeElement("p", addField(() => fullDisplay(link))));
+		displayDiv.append(App.UI.DOM.makeElement("p", addField()));
 
 		return displayDiv;
 	}
 
 	/**
 	 * @param {number} slaveID
+	 * @param {HTMLElement} [displayDiv] Only to be used by the refresh functionality
 	 * @returns {HTMLElement}
 	 */
-	function slaveDisplay(slaveID) {
-		jQuery(displayDiv).empty();
+	function slaveDisplay(slaveID, displayDiv) {
+		if (displayDiv) {
+			if (!displayDiv.isConnected) {
+				return null;
+			}
+			jQuery(displayDiv).empty();
+		} else {
+			displayDiv = document.createElement("div");
+		}
+		activeViewRefreshers.push(() => slaveDisplay(slaveID, displayDiv));
+
 		displayDiv.append(App.UI.DOM.makeElement("h2", `Reminders for ${SlaveFullName(getSlave(slaveID))}`));
 
 		const listEl = list({filter: e => e.slaveID === slaveID});
@@ -184,7 +209,7 @@ App.Reminders = (function() {
 		}
 
 		displayDiv.append(App.UI.DOM.makeElement("h3", "Add new"));
-		displayDiv.append(App.UI.DOM.makeElement("p", addField(() => slaveDisplay(slaveID), "slave", slaveID)));
+		displayDiv.append(App.UI.DOM.makeElement("p", addField("slave", slaveID)));
 
 		return displayDiv;
 	}
@@ -211,4 +236,18 @@ App.Reminders = (function() {
 		$(Dialog.body()).empty().append(slaveID ? slaveDisplay(slaveID) : fullDisplay(showLinks));
 		Dialog.open();
 	}
+
+	function refreshActive() {
+		console.log(activeViewRefreshers.length);
+		const ars = activeViewRefreshers;
+		activeViewRefreshers = [];
+		for (const refresher of ars) {
+			refresher();
+		}
+		App.Utils.scheduleSidebarRefresh();
+	}
+
+	function clearActive() {
+		activeViewRefreshers = [];
+	}
 })();
diff --git a/src/zz1-last/setupEventHandlers.js b/src/zz1-last/setupEventHandlers.js
index 44e3eb0ff12..896ed386a42 100644
--- a/src/zz1-last/setupEventHandlers.js
+++ b/src/zz1-last/setupEventHandlers.js
@@ -14,6 +14,7 @@ $(document).on(":passageinit", () => {
 		delete V.passageSwitchHandler;
 	}
 	App.UI.Tabs.clear();
+	App.Reminders.clear();
 	profileEvents.passageinit();
 });
 
-- 
GitLab