Skip to content

Commit 33d1576

Browse files
Docs: lots of comments styled using JSDoc syntax
Including some typification, useful for validators (since JavaScript is an untyped language).
1 parent dda47f2 commit 33d1576

File tree

2 files changed

+88
-35
lines changed

2 files changed

+88
-35
lines changed

gwynethllewelyn/postlocalstorage/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "A very simple phpBB3 extension to locally store the content of a post being written, to avoid losing everything after a crash or session expiration.",
55
"homepage": "https://github.com/GwynethLlewelyn/post-local-storage",
66
"version": "1.1.0",
7-
"time": "2024-04-15",
7+
"time": "2024-04-17",
88
"license": "GPL-2.0-only",
99
"keywords": [
1010
"phpbb",
Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,62 @@
1-
// Copyright (C) 2023,2024 Gwyneth Llewelyn
2-
//
3-
// This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2.
4-
//
5-
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6-
//
7-
// You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1+
/**
2+
* postlocalstorage_functions.js
3+
* Handles the content storage of a post/reply/direct message inside localStorage.
4+
*
5+
* @author Gwyneth Llewelyn
6+
* @copyright © 2023,2024 by Gwyneth Llewelyn. Some rights reserved.
7+
* @license GPL-2.0-only
8+
*/
89

10+
/**
11+
* @function anonymous
12+
*
13+
* @param {Object} message - This object (will be set to `this`).
14+
* @param {Document} doc - This object's DOM (will be set to `this.document`).
15+
*/
916
(function(message, doc) {
10-
var nIntervId; //
17+
/**
18+
* Handler for the SetInterval event, so we can remove it on submit.
19+
* @type {number}
20+
* @since 1.1.0
21+
*/
22+
var nIntervId;
1123

12-
// One year = 31536000000 milliseconds.
24+
/**
25+
* Freshness interval in milliseconds.
26+
* One year = 31536000000 milliseconds.
27+
* @const {number}
28+
*/
1329
const FRESHNESS_INTERVAL = 365 * 24 * 60 * 60 * 1000;
1430

1531
// If there is no localStorage support, give up
1632
if (!message.localStorage) {
1733
console.debug("no local storage support");
1834
return;
1935
}
20-
// phpBB3 uses a textarea with name 'message', both for Quick Replies _and_ normal replies
36+
/**
37+
* phpBB3 uses a textarea with name 'message', both for Quick Replies _and_ normal replies
38+
* @type {Element?}
39+
*/
2140
var textarea = doc.querySelector('textarea[name="message"]');
2241
// no point in being around if this is nil; also: avoids crashing below (gwyneth 20220303)
2342
if (!textarea) {
2443
console.warn("no phpBB3 content body textarea found");
2544
return;
2645
}
27-
// phpBB3 usually gives the subject/topic the name 'subject' — same for QR and normal replies.
46+
/**
47+
* phpBB3 usually gives the subject/topic the name 'subject' — same for QR and normal replies.
48+
* @type {Element?}
49+
*/
2850
var subject = doc.querySelector('input[name="subject"]');
2951
if (!subject) {
3052
console.debug("no phpBB3 subject line found");
3153
// I have not decided what to do in this case! Possibly just:
3254
// subject = "(no subject)";
3355
}
34-
// The key for the key/value pair in localStorage is the current URL.
56+
/**
57+
* The key for the key/value pair in localStorage is the current URL.
58+
* @type {string}
59+
*/
3560
var key = message.location.href;
3661
// Firefox seems to have an odd bug which affects clicking backspace in quick succession.
3762
// Kudos to @gvp9000 and for the fix below. (gwyneth 20240414)
@@ -40,16 +65,38 @@
4065
for (let i = 0; i < count_hash_num - 1; i++) {
4166
key = key.substring(0, key.lastIndexOf('#'));
4267
}
43-
// JSON object to be saved with the textarea content + subject content + timestamp.
68+
/**
69+
* JSON object to be saved with the textarea content + subject content + timestamp.
70+
* @type {JSON?}
71+
*/
4472
var item = null;
45-
// Event to be used for saving content on demand, when user switches pages.
46-
// Note: both the 'pagehide' or 'beforeunload' are deprecated and should not be used.
73+
74+
/**
75+
* Event name to be used for saving content on demand, when user switches pages.
76+
*
77+
* Note: both the 'pagehide' or 'beforeunload' events are deprecated and should not be used here.
78+
* @const {string}
79+
*/
4780
const unloadEvent = "visibilitychange";
4881

49-
// If there's a localStorage entry for the current URL, update the textarea with the saved value.
82+
/**
83+
* JSON object describing what we store on the localStorage for each article/message.
84+
* @typedef StoredContent
85+
* @type {object}
86+
* @property {string} subject - Content of the "subject" input box (also known as "title").
87+
* @property {string} content - The actual content of the textarea box (the article/message itself).
88+
* @property {number} timestamp - Time in milliseconds since the Unix epoch, to deal with stale content.
89+
*/
90+
91+
// If there's a `localStorage` entry for the current URL, update the textarea with the saved value.
5092
item = message.localStorage.getItem(key);
5193
if (item) {
94+
/**
95+
* JSON representation of one object in the localStorage.
96+
* @type {StoredContent?}
97+
*/
5298
var data = JSON.parse(item);
99+
/** @since 1.1.0 */
53100
// Before 1.1.0, 'our' objects did not carry timestamps, so we need to check for them: (gwyneth 20240415)
54101
if (data?.timestamp) {
55102
// check if data is stale.
@@ -68,23 +115,23 @@
68115
} else {
69116
// We don't know if the existing data is stale or not, since it comes from pre-1.1.0 times.
70117
// So, upgrade object to the new format, i.e. add a timestamp to existing content.
118+
/** @type {string} */
71119
let tempContent = data?.content ?? "";
120+
/** @type {string} */
72121
let tempSubject = data?.subject ?? "";
73122
message.localStorage.removeItem(key);
74123
item = JSON.stringify({ "content": tempContent, "subject": tempSubject, "timestamp": Date.now() });
75124
message.localStorage.setItem(key, item);
76125
}
77126
}
78-
//
79-
// // Workaround for non-existing Object.hasOwn()
80-
// function isIn(field, obj) {
81-
// if ("hasOwn" in Object) {
82-
// return Object.hasOwn(field, obj);
83-
// }
84-
// return (field in obj);
85-
// }
86127

87-
// This function will store the current value of the textarea in localStorage (or delete it if the textarea is blank) with a timestamp.
128+
/**
129+
* This function will store the current value of the textarea in localStorage (or delete it if the textarea is blank) with a timestamp.
130+
*
131+
* It gets triggered by the "type" events on the input and textarea elements,
132+
* @function updateStorage
133+
* @type EventListener
134+
*/
88135
function updateStorage() {
89136
// Note: if the visibilitychange event is being used, one should check to see if the visibilityState
90137
// is 'hidden' or 'visible'; but we're going to save to storage in both cases.
@@ -106,6 +153,7 @@
106153
// When the user presses a key just *once* inside the textarea, run the storage function when the page is unloaded.
107154
textarea.addEventListener(
108155
"keyup",
156+
/** @listens keyup */
109157
function() {
110158
message.addEventListener(unloadEvent, updateStorage);
111159
nIntervId = message.setInterval(updateStorage, 10000);
@@ -114,21 +162,26 @@
114162
// Same for the subject, I think:
115163
subject.addEventListener(
116164
"keyup",
165+
/** @listens keyup */
117166
function() {
118167
message.addEventListener(unloadEvent, updateStorage);
119168
nIntervId = message.setInterval(updateStorage, 10000);
120169
}, { once: true }
121170
);
122171

123172
// When the form is submitted, delete the localStorage key/value pair.
124-
textarea.form.addEventListener("submit", function() {
125-
// ... except on Preview. We still want to keep the storage around during preview!
126-
// Kudos to
127-
if (document.activeElement.value != 'Preview') {
128-
message.localStorage.removeItem(key);
129-
message.removeEventListener(unloadEvent, updateStorage);
130-
message.clearInterval(nIntervId);
131-
console.debug("Text submitted (not in preview!); removed from localStorage");
173+
textarea.form.addEventListener(
174+
"submit",
175+
/** @listens submit */
176+
function() {
177+
// ... except on Preview. We still want to keep the storage around during preview!
178+
// Kudos to
179+
if (document.activeElement.value != 'Preview') {
180+
message.localStorage.removeItem(key);
181+
message.removeEventListener(unloadEvent, updateStorage);
182+
message.clearInterval(nIntervId);
183+
console.debug("Text submitted (not in preview!); removed from localStorage");
184+
}
132185
}
133-
});
186+
);
134187
})(this, this.document);

0 commit comments

Comments
 (0)