diff --git a/api/WindowListener/implementation.js b/api/WindowListener/implementation.js index c1bcb57..7baa45c 100644 --- a/api/WindowListener/implementation.js +++ b/api/WindowListener/implementation.js @@ -2,47 +2,43 @@ * This file is provided by the addon-developer-support repository at * https://github.com/thundernest/addon-developer-support * - * Version: 1.42 - * - Add notifyLegacy() function to send data to privileged code. Together with the - * onNotifyBackground event a ping-pong-style communication is possible which can - * later be re-created with runtime.onMessage/sendMessage. Example: + * Version: 1.44 + * - Add notifyExperiment() function to send data to privileged scripts inside + * an Experiment. The privileged script must include notifyTools.js from the + * addon-developer-support repository. * - * //in background - * messenger.WindowListener.notifyLegacy({data: "voilá"}); + * // In a WebExtension background script: + * // Note: Restrictions of the structured clone algorythm apply to the send data. + * messenger.WindowListener.notifyExperiment({data: "voilá"}); * - * // in privileged code - * let onNotifyLegacyObserver = { - * observe: function (aSubject, aTopic, aData) { - * if (aData != ) - * return; - * console.log(aSubject.wrappedJSObject); - * } - * } - * window.addEventListener("load", function (event) { - * Services.obs.addObserver(onNotifyLegacyObserver, "WindowListenerNotifyLegacyObserver", false); - * window.addEventListener("unload", function (event) { - * Services.obs.removeObserver(onNotifyLegacyObserver, "WindowListenerNotifyLegacyObserver"); - * }, false); - * }, false); - * - * Version: 1.41 - * - Add onNotifyBackground event, which can be registered in the background page, to receive - * commands from privileged code. Example: + * // In a privileged script inside an Experiment: + * let Listerner1 = notifyTools.registerListener((rv) => console.log("listener #1", rv)); + * let Listerner2 = notifyTools.registerListener((rv) => console.log("listener #2", rv)); + * let Listerner3 = notifyTools.registerListener((rv) => console.log("listener #3", rv)); + * notifyTools.removeListener(Listerner2); * - * // in background - * messenger.WindowListener.onNotifyBackground.addListener((info) => { + * - Add onNotifyBackground event, which can be registered in the background page, + * to receive data from privileged scripts inside an Experiment. The privileged + * script must include notifyTools.js from the addon-developer-support repository. + * + * // In a WebExtension background script: + * messenger.WindowListener.onNotifyBackground.addListener(async (info) => { * switch (info.command) { * case "doSomething": - * soSomething(); + * let rv = await doSomething(info.data); + * return { + * result: rv, + * data: [1,2,3] + * }; * break; * } * }); * - * // in privileged code - * Services.obs.notifyObservers( - * {command: "doSomething"}, - * "WindowListenerNotifyBackgroundObserver", - * ); + * // In a privileged script inside an Experiment: + * let rv = await notifyTools.notifyBackground({command: "doSomething", data: [1,2,3]}); + * // rv will be whatever has been returned by the background script. + * // Note: Restrictions of the structured clone algorythm apply to + * // the send and recieved data. * * Version: 1.39 * - fix for 68 @@ -455,19 +451,29 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { }; this.onNotifyBackgroundObserver = { - observe: function (aSubject, aTopic, aData) { + observe: async function (aSubject, aTopic, aData) { if (self.observerTracker && aData == self.extension.id) { - self.observerTracker(aSubject.wrappedJSObject); + let payload = aSubject.wrappedJSObject; + // This is called from the WL observer.js and therefore it should have a resolve + // payload, but better check. + if (payload.resolve) { + let rv = await self.observerTracker(payload.data); + payload.resolve(rv); + } else { + self.observerTracker(payload.data); + } } } } return { WindowListener: { - notifyLegacy(info) { + notifyExperiment(data) { Services.obs.notifyObservers( - info, - "WindowListenerNotifyLegacyObserver", + // Stuff data in an array so simple strings can be used as payload + // without the observerService complaining. + [data], + "WindowListenerNotifyExperimentObserver", self.extension.id ); }, diff --git a/api/WindowListener/schema.json b/api/WindowListener/schema.json index 4a9ef23..82edd69 100644 --- a/api/WindowListener/schema.json +++ b/api/WindowListener/schema.json @@ -5,26 +5,26 @@ { "name": "onNotifyBackground", "type": "function", - "description": "Fired when a new notification for 'WindowListenerNotifyBackgroundObserver' has been received with aData matching the ID of this extension. Only one listener is supported.", + "description": "Fired when a new notification from notifyTools.js in an Experiment has been received.", "parameters": [ { - "name": "info", + "name": "data", "type": "any", - "description": "Info object passed into notifyObserver as aSubject and forwarded to the listener. Restrictions of the structured clone algorythm apply." + "description": "Restrictions of the structured clone algorythm apply." } ] } ], "functions": [ { - "name": "notifyLegacy", + "name": "notifyExperiment", "type": "function", - "description": "Notifies the 'WindowListenerNotifyLegacyObserver' and passes and uses the provided info object as aSubject for notifyObserver and the add-on ID as aData.", + "description": "Notifies notifyTools.js in an Experiment and sends data.", "parameters": [ { - "name": "info", + "name": "data", "type": "any", - "description": "Info object forwarded to the observer. The value will be in aSubject.wrappedJSObject. Restrictions of the structured clone algorythm apply." + "description": "Restrictions of the structured clone algorythm apply." } ] }, diff --git a/background.js b/background.js index 15fec48..a8a981e 100644 --- a/background.js +++ b/background.js @@ -16,7 +16,6 @@ messenger.runtime.onMessage.addListener((info, sender) => { } }); - /* * Register a onNotify listener to catch messages send from privileged scope. */ @@ -24,21 +23,16 @@ messenger.WindowListener.onNotifyBackground.addListener((info) => { switch (info.command) { case "openFirstRunTab": openFirstRunTab(); - // I used LatexIt to implement and test these functions. Left it in as - // a working example for ping-pong communication. - messenger.WindowListener.notifyLegacy(info); break; } }); - function openFirstRunTab() { messenger.tabs.create({ url: "content/firstrun.html" }); } - (async () => { messenger.WindowListener.registerDefaultPrefs( "defaults/preferences/defaults.js"); @@ -69,4 +63,3 @@ function openFirstRunTab() { } })(); - diff --git a/content/notifyTools.js b/content/notifyTools.js new file mode 100644 index 0000000..834f044 --- /dev/null +++ b/content/notifyTools.js @@ -0,0 +1,55 @@ +const ADDON_ID = "tblatex@xulforum.org"; + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +var notifyTools = { + registeredCallbacks: {}, + registeredCallbacksNextId: 1, + + onNotifyExperimentObserver: { + observe: async function (aSubject, aTopic, aData) { + if (ADDON_ID == "") { + throw new Error("notifyTools: ADDON_ID is empty!"); + } + if (aData != ADDON_ID) { + return; + } + // The data has been stuffed in an array so simple strings can be used as + // payload without the observerService complaining. + let [data] = aSubject.wrappedJSObject; + for (let registeredCallback of Object.values(notifyTools.registeredCallbacks)) { + registeredCallback(data); + } + } + }, + + registerListener: function (listener) { + let id = this.registeredCallbacksNextId++; + this.registeredCallbacks[id] = listener; + return id; + }, + + removeListener: function (id) { + delete this.registeredCallbacks[id]; + }, + + notifyBackground: function (data) { + if (ADDON_ID == "") { + throw new Error("notifyTools: ADDON_ID is empty!"); + } + return new Promise(resolve => { + Services.obs.notifyObservers( + {data, resolve}, + "WindowListenerNotifyBackgroundObserver", + ADDON_ID + ); + }); + } +} + +window.addEventListener("load", function (event) { + Services.obs.addObserver(notifyTools.onNotifyExperimentObserver, "WindowListenerNotifyExperimentObserver", false); + window.addEventListener("unload", function (event) { + Services.obs.removeObserver(notifyTools.onNotifyExperimentObserver, "WindowListenerNotifyExperimentObserver"); + }, false); +}, false); diff --git a/content/options.js b/content/options.js index fc2d794..b409ee7 100644 --- a/content/options.js +++ b/content/options.js @@ -1,22 +1,3 @@ -var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - -// I used LatexIt to implement and test these functions. Left it in as -// a working example for ping-pong communication. -let onNotifyLegacyObserver = { - observe: function (aSubject, aTopic, aData) { - if (aData != "tblatex@xulforum.org") { - return; - } - console.log(aSubject.wrappedJSObject); - } -} -window.addEventListener("load", function (event) { - Services.obs.addObserver(onNotifyLegacyObserver, "WindowListenerNotifyLegacyObserver", false); - window.addEventListener("unload", function (event) { - Services.obs.removeObserver(onNotifyLegacyObserver, "WindowListenerNotifyLegacyObserver"); - }, false); -}, false); - function pick_file(pref, title) { var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); @@ -30,12 +11,8 @@ function pick_file(pref, title) { }); } -function open_autodetect() { - // Notify WebExtension Background to open the first run tab. - Services.obs.notifyObservers( - {command: "openFirstRunTab"}, - "WindowListenerNotifyBackgroundObserver", - "tblatex@xulforum.org"); +async function open_autodetect() { + notifyTools.notifyBackground({command: "openFirstRunTab"}); } window.addEventListener("load", function (event) { diff --git a/content/options.xhtml b/content/options.xhtml index ab43acf..c0cefe1 100644 --- a/content/options.xhtml +++ b/content/options.xhtml @@ -8,6 +8,7 @@ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" > +