diff --git a/dist/birb.js b/dist/birb.js index 9e84ff2..f857d70 100644 --- a/dist/birb.js +++ b/dist/birb.js @@ -839,6 +839,123 @@ } } + /** + * @typedef {import('./application.js').BirbSaveData} BirbSaveData + */ + + /** + * @abstract + */ + class Context { + + /** + * @abstract + * @returns {boolean} Whether this context is applicable + */ + isContextActive() { + throw new Error("Method not implemented"); + } + + /** + * @abstract + * @returns {BirbSaveData|{}} + */ + getSaveData() { + throw new Error("Method not implemented"); + } + + /** + * @abstract + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + throw new Error("Method not implemented"); + } + + /** + * @abstract + */ + resetSaveData() { + throw new Error("Method not implemented"); + } + } + + class LocalContext extends Context { + + isContextActive() { + return window.location.hostname === "127.0.0.1" + || window.location.hostname === "localhost" + || window.location.hostname.startsWith("192.168."); + } + + getSaveData() { + log("Loading save data from localStorage"); + return JSON.parse(localStorage.getItem("birbSaveData") ?? "{}"); + } + + /** + * @override + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + log("Saving data to localStorage"); + localStorage.setItem("birbSaveData", JSON.stringify(saveData)); + } + + resetSaveData() { + log("Resetting save data in localStorage"); + localStorage.removeItem("birbSaveData"); + } + } + + class UserScriptContext extends Context { + + isContextActive() { + // @ts-expect-error + return typeof GM_getValue === "function"; + } + + getSaveData() { + log("Loading save data from UserScript storage"); + /** @type {BirbSaveData|{}} */ + let saveData = {}; + // @ts-expect-error + saveData = GM_getValue("birbSaveData", {}) ?? {}; + return saveData; + } + + /** + * @override + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + log("Saving data to UserScript storage"); + // @ts-expect-error + GM_setValue("birbSaveData", saveData); + } + + resetSaveData() { + log("Resetting save data in UserScript storage"); + // @ts-expect-error + GM_deleteValue("birbSaveData"); + } + } + + const CONTEXTS = [ + new LocalContext(), + new UserScriptContext(), + ]; + + function getContext() { + for (const context of CONTEXTS) { + if (context.isContextActive()) { + return context; + } + } + error("No applicable context found, defaulting to LocalContext"); + return CONTEXTS[0]; + } + /** * @typedef {Object} SavedStickyNote * @property {string} id @@ -1678,7 +1795,7 @@ insertModal(`${birdBirb()} Mode`, message); }), new Separator(), - new MenuItem("2025.10.29.20", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.10.29.20"); }, false), + new MenuItem("2025.11.2.0", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.2.0"); }, false), ]; const styleElement = document.createElement("style"); @@ -1718,34 +1835,9 @@ /** @type {StickyNote[]} */ let stickyNotes = []; - /** - * @returns {boolean} Whether the script is running in a userscript extension context - */ - function isUserScript() { - // @ts-expect-error - return typeof GM_getValue === "function"; - } - - function isTestEnvironment() { - return window.location.hostname === "127.0.0.1" - || window.location.hostname === "localhost" - || window.location.hostname.startsWith("192.168."); - } - function load() { /** @type {Record} */ - let saveData = {}; - - if (isUserScript()) { - log("Loading save data from UserScript storage"); - // @ts-expect-error - saveData = GM_getValue("birbSaveData", {}) ?? {}; - } else if (isTestEnvironment()) { - log("Test environment detected, loading save data from localStorage"); - saveData = JSON.parse(localStorage.getItem("birbSaveData") ?? "{}"); - } else { - log("Not a UserScript"); - } + let saveData = getContext().getSaveData(); debug("Loaded data: " + JSON.stringify(saveData)); @@ -1788,29 +1880,11 @@ })); } - if (isUserScript()) { - log("Saving data to UserScript storage"); - // @ts-expect-error - GM_setValue("birbSaveData", saveData); - } else if (isTestEnvironment()) { - log("Test environment detected, saving data to localStorage"); - localStorage.setItem("birbSaveData", JSON.stringify(saveData)); - } else { - log("Not a UserScript"); - } + getContext().putSaveData(saveData); } function resetSaveData() { - if (isUserScript()) { - log("Resetting save data in UserScript storage"); - // @ts-expect-error - GM_deleteValue("birbSaveData"); - } else if (isTestEnvironment()) { - log("Test environment detected, resetting save data in localStorage"); - localStorage.removeItem("birbSaveData"); - } else { - log("Not a UserScript"); - } + getContext().resetSaveData(); load(); } diff --git a/dist/birb.user.js b/dist/birb.user.js index 17398d6..b2a311e 100644 --- a/dist/birb.user.js +++ b/dist/birb.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name Pocket Bird // @namespace https://idreesinc.com -// @version 2025.10.29.20 +// @version 2025.11.2.0 // @description birb // @author Idrees // @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/birb.user.js @@ -853,6 +853,123 @@ } } + /** + * @typedef {import('./application.js').BirbSaveData} BirbSaveData + */ + + /** + * @abstract + */ + class Context { + + /** + * @abstract + * @returns {boolean} Whether this context is applicable + */ + isContextActive() { + throw new Error("Method not implemented"); + } + + /** + * @abstract + * @returns {BirbSaveData|{}} + */ + getSaveData() { + throw new Error("Method not implemented"); + } + + /** + * @abstract + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + throw new Error("Method not implemented"); + } + + /** + * @abstract + */ + resetSaveData() { + throw new Error("Method not implemented"); + } + } + + class LocalContext extends Context { + + isContextActive() { + return window.location.hostname === "127.0.0.1" + || window.location.hostname === "localhost" + || window.location.hostname.startsWith("192.168."); + } + + getSaveData() { + log("Loading save data from localStorage"); + return JSON.parse(localStorage.getItem("birbSaveData") ?? "{}"); + } + + /** + * @override + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + log("Saving data to localStorage"); + localStorage.setItem("birbSaveData", JSON.stringify(saveData)); + } + + resetSaveData() { + log("Resetting save data in localStorage"); + localStorage.removeItem("birbSaveData"); + } + } + + class UserScriptContext extends Context { + + isContextActive() { + // @ts-expect-error + return typeof GM_getValue === "function"; + } + + getSaveData() { + log("Loading save data from UserScript storage"); + /** @type {BirbSaveData|{}} */ + let saveData = {}; + // @ts-expect-error + saveData = GM_getValue("birbSaveData", {}) ?? {}; + return saveData; + } + + /** + * @override + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + log("Saving data to UserScript storage"); + // @ts-expect-error + GM_setValue("birbSaveData", saveData); + } + + resetSaveData() { + log("Resetting save data in UserScript storage"); + // @ts-expect-error + GM_deleteValue("birbSaveData"); + } + } + + const CONTEXTS = [ + new LocalContext(), + new UserScriptContext(), + ]; + + function getContext() { + for (const context of CONTEXTS) { + if (context.isContextActive()) { + return context; + } + } + error("No applicable context found, defaulting to LocalContext"); + return CONTEXTS[0]; + } + /** * @typedef {Object} SavedStickyNote * @property {string} id @@ -1692,7 +1809,7 @@ insertModal(`${birdBirb()} Mode`, message); }), new Separator(), - new MenuItem("2025.10.29.20", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.10.29.20"); }, false), + new MenuItem("2025.11.2.0", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.2.0"); }, false), ]; const styleElement = document.createElement("style"); @@ -1732,34 +1849,9 @@ /** @type {StickyNote[]} */ let stickyNotes = []; - /** - * @returns {boolean} Whether the script is running in a userscript extension context - */ - function isUserScript() { - // @ts-expect-error - return typeof GM_getValue === "function"; - } - - function isTestEnvironment() { - return window.location.hostname === "127.0.0.1" - || window.location.hostname === "localhost" - || window.location.hostname.startsWith("192.168."); - } - function load() { /** @type {Record} */ - let saveData = {}; - - if (isUserScript()) { - log("Loading save data from UserScript storage"); - // @ts-expect-error - saveData = GM_getValue("birbSaveData", {}) ?? {}; - } else if (isTestEnvironment()) { - log("Test environment detected, loading save data from localStorage"); - saveData = JSON.parse(localStorage.getItem("birbSaveData") ?? "{}"); - } else { - log("Not a UserScript"); - } + let saveData = getContext().getSaveData(); debug("Loaded data: " + JSON.stringify(saveData)); @@ -1802,29 +1894,11 @@ })); } - if (isUserScript()) { - log("Saving data to UserScript storage"); - // @ts-expect-error - GM_setValue("birbSaveData", saveData); - } else if (isTestEnvironment()) { - log("Test environment detected, saving data to localStorage"); - localStorage.setItem("birbSaveData", JSON.stringify(saveData)); - } else { - log("Not a UserScript"); - } + getContext().putSaveData(saveData); } function resetSaveData() { - if (isUserScript()) { - log("Resetting save data in UserScript storage"); - // @ts-expect-error - GM_deleteValue("birbSaveData"); - } else if (isTestEnvironment()) { - log("Test environment detected, resetting save data in localStorage"); - localStorage.removeItem("birbSaveData"); - } else { - log("Not a UserScript"); - } + getContext().resetSaveData(); load(); } diff --git a/manifest.json b/manifest.json index 2a54dec..8883dc8 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "Pocket Bird", "description": "It's a bird, in your browser. What more could you want?", - "version": "2025.10.29.20", + "version": "2025.11.2.0", "homepage_url": "https://idreesinc.com", "icons": { "48": "images/icons/transparent/48x48x1.png", diff --git a/src/application.js b/src/application.js index 0ba36cd..1469338 100644 --- a/src/application.js +++ b/src/application.js @@ -2,6 +2,7 @@ import Frame from './frame.js'; import Layer from './layer.js'; import Anim from './anim.js'; import { Birb, Animations } from './birb.js'; +import { getContext } from './context.js'; import { Directions, @@ -270,34 +271,9 @@ Promise.all([ /** @type {StickyNote[]} */ let stickyNotes = []; - /** - * @returns {boolean} Whether the script is running in a userscript extension context - */ - function isUserScript() { - // @ts-expect-error - return typeof GM_getValue === "function"; - } - - function isTestEnvironment() { - return window.location.hostname === "127.0.0.1" - || window.location.hostname === "localhost" - || window.location.hostname.startsWith("192.168."); - } - function load() { /** @type {Record} */ - let saveData = {}; - - if (isUserScript()) { - log("Loading save data from UserScript storage"); - // @ts-expect-error - saveData = GM_getValue("birbSaveData", {}) ?? {}; - } else if (isTestEnvironment()) { - log("Test environment detected, loading save data from localStorage"); - saveData = JSON.parse(localStorage.getItem("birbSaveData") ?? "{}"); - } else { - log("Not a UserScript"); - } + let saveData = getContext().getSaveData(); debug("Loaded data: " + JSON.stringify(saveData)); @@ -340,29 +316,11 @@ Promise.all([ })); } - if (isUserScript()) { - log("Saving data to UserScript storage"); - // @ts-expect-error - GM_setValue("birbSaveData", saveData); - } else if (isTestEnvironment()) { - log("Test environment detected, saving data to localStorage"); - localStorage.setItem("birbSaveData", JSON.stringify(saveData)); - } else { - log("Not a UserScript"); - } + getContext().putSaveData(saveData); } function resetSaveData() { - if (isUserScript()) { - log("Resetting save data in UserScript storage"); - // @ts-expect-error - GM_deleteValue("birbSaveData"); - } else if (isTestEnvironment()) { - log("Test environment detected, resetting save data in localStorage"); - localStorage.removeItem("birbSaveData"); - } else { - log("Not a UserScript"); - } + getContext().resetSaveData(); load(); } diff --git a/src/context.js b/src/context.js new file mode 100644 index 0000000..8ac3299 --- /dev/null +++ b/src/context.js @@ -0,0 +1,119 @@ + +import { debug, log, error } from "./shared.js"; + +/** + * @typedef {import('./application.js').BirbSaveData} BirbSaveData + */ + +/** + * @abstract + */ +export class Context { + + /** + * @abstract + * @returns {boolean} Whether this context is applicable + */ + isContextActive() { + throw new Error("Method not implemented"); + } + + /** + * @abstract + * @returns {BirbSaveData|{}} + */ + getSaveData() { + throw new Error("Method not implemented"); + } + + /** + * @abstract + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + throw new Error("Method not implemented"); + } + + /** + * @abstract + */ + resetSaveData() { + throw new Error("Method not implemented"); + } +} + +export class LocalContext extends Context { + + isContextActive() { + return window.location.hostname === "127.0.0.1" + || window.location.hostname === "localhost" + || window.location.hostname.startsWith("192.168."); + } + + getSaveData() { + log("Loading save data from localStorage"); + return JSON.parse(localStorage.getItem("birbSaveData") ?? "{}"); + } + + /** + * @override + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + log("Saving data to localStorage"); + localStorage.setItem("birbSaveData", JSON.stringify(saveData)); + } + + resetSaveData() { + log("Resetting save data in localStorage"); + localStorage.removeItem("birbSaveData"); + } +} + +export class UserScriptContext extends Context { + + isContextActive() { + // @ts-expect-error + return typeof GM_getValue === "function"; + } + + getSaveData() { + log("Loading save data from UserScript storage"); + /** @type {BirbSaveData|{}} */ + let saveData = {}; + // @ts-expect-error + saveData = GM_getValue("birbSaveData", {}) ?? {}; + return saveData; + } + + /** + * @override + * @param {BirbSaveData} saveData + */ + putSaveData(saveData) { + log("Saving data to UserScript storage"); + // @ts-expect-error + GM_setValue("birbSaveData", saveData); + } + + resetSaveData() { + log("Resetting save data in UserScript storage"); + // @ts-expect-error + GM_deleteValue("birbSaveData"); + } +} + +const CONTEXTS = [ + new LocalContext(), + new UserScriptContext(), +]; + +export function getContext() { + for (const context of CONTEXTS) { + if (context.isContextActive()) { + return context; + } + } + error("No applicable context found, defaulting to LocalContext"); + return CONTEXTS[0]; +} \ No newline at end of file