From 36686aa5d85353cec0136bb6ff9c42a82268576a Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 11:00:51 +0100 Subject: [PATCH 1/8] Call first run as a WebExtension page --- api/LatexIt/implementation.js | 66 +++++++++++++++++++ api/LatexIt/schema.json | 32 +++++++++ api/LegacyPrefs/README.md | 27 ++++++++ api/LegacyPrefs/implementation.js | 81 ++++++++++++++++++++--- api/LegacyPrefs/schema.json | 48 ++++++++++++++ background.js | 32 +++++++-- content/firstrun.html | 94 ++------------------------- content/firstrun.js | 78 +++++++++++++++++----- content/scripts/messenger_firstrun.js | 12 ---- manifest.json | 16 +++++ 10 files changed, 357 insertions(+), 129 deletions(-) create mode 100644 api/LatexIt/implementation.js create mode 100644 api/LatexIt/schema.json create mode 100644 api/LegacyPrefs/README.md delete mode 100644 content/scripts/messenger_firstrun.js diff --git a/api/LatexIt/implementation.js b/api/LatexIt/implementation.js new file mode 100644 index 0000000..98105b5 --- /dev/null +++ b/api/LatexIt/implementation.js @@ -0,0 +1,66 @@ +var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +function init_file (path) { + var f = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + try { + f.initWithPath(path); + } catch (e) { + dump("Wrong path! "+path+"\n"); + return { + exists: function () { return false; } + }; + } + return f +} + +var LatexIt = class extends ExtensionCommon.ExtensionAPI { + getAPI(context) { + + return { + LatexIt: { + + file_exists: async function(path) { + let file = init_file(path); + return file.exists(); + }, + + search_in_path: async function(isWindows) { + var env = Cc["@mozilla.org/process/environment;1"].createInstance(Ci.nsIEnvironment); + var sep = isWindows ? ";" : ":"; + var ext = isWindows ? ".exe" : ""; + var dirs = env.get("PATH").split(sep); + + let found = {}; + + for (var i = 0; i < dirs.length; ++i) { + var latex_bin = init_file(dirs[i]); + if (latex_bin.exists()) { + latex_bin.append("latex"+ext); + if (latex_bin.exists()) { + found.latex = latex_bin.path; + dump("Found latex in "+latex_bin.path+"\n"); + break; + } + } + } + + for (var i = 0; i < dirs.length; ++i) { + var dvipng_bin = init_file(dirs[i]); + if (dvipng_bin.exists()) { + dvipng_bin.append("dvipng"+ext); + if (dvipng_bin.exists()) { + found.dvipng = dvipng_bin.path; + dump("Found dvipng in "+dvipng_bin.path+"\n"); + break; + } + } + } + + return found; + } + + } + }; + } +}; diff --git a/api/LatexIt/schema.json b/api/LatexIt/schema.json new file mode 100644 index 0000000..d260087 --- /dev/null +++ b/api/LatexIt/schema.json @@ -0,0 +1,32 @@ +[ + { + "namespace": "LatexIt", + "functions": [ + { + "name": "file_exists", + "type": "function", + "async": true, + "description": "check if local file exists", + "parameters": [ + { + "name": "aPath", + "type": "string", + "description": "aPath" + } + ] + }, + { + "name": "search_in_path", + "type": "function", + "async": true, + "description": "search_in_path", + "parameters": [ + { + "name": "isWindows", + "type": "boolean" + } + ] + } + ] + } +] diff --git a/api/LegacyPrefs/README.md b/api/LegacyPrefs/README.md new file mode 100644 index 0000000..e6100a3 --- /dev/null +++ b/api/LegacyPrefs/README.md @@ -0,0 +1,27 @@ +## Objective + +Use this API to access Thunderbird's system preferences or to migrate your own preferences from the Thunderbird preference system to the local storage of your MailExtension. + +## Usage + +This API provides the following methods: + +### async getPref(aName, [aFallback]) + +Returns the value for the ``aName`` preference. If it is not defined or has no default value assigned, ``aFallback`` will be returned (which defaults to ``null``). + +### async getUserPref(aName) + +Returns the user defined value for the ``aName`` preference. This will ignore any defined default value and will only return an explicitly set value, which differs from the default. Otherwise it will return ``null``. + +### clearUserPref(aName) + +Clears the user defined value for preference ``aName``. Subsequent calls to ``getUserPref(aName)`` will return ``null``. + +### async setPref(aName, aValue) + +Set the ``aName`` preference to the given value. Will return false and log an error to the console, if the type of ``aValue`` does not match the type of the preference. + +--- + +A detailed example using the LegacyPref API to migrate add-on preferences to the local storage can be found in [/scripts/preferences/](https://github.com/thundernest/addon-developer-support/tree/master/scripts/preferences). diff --git a/api/LegacyPrefs/implementation.js b/api/LegacyPrefs/implementation.js index 3220445..4e52b52 100644 --- a/api/LegacyPrefs/implementation.js +++ b/api/LegacyPrefs/implementation.js @@ -1,3 +1,26 @@ +/* + * This file is provided by the addon-developer-support repository at + * https://github.com/thundernest/addon-developer-support + * + * Version: 1.5 + * replace set/getCharPref by set/getStringPref to fix encoding issue + * + * Version: 1.4 + * - setPref() function returns true if the value could be set, otherwise false + * + * Version: 1.3 + * - add setPref() function + * + * Version: 1.2 + * - add getPref() function + * + * Author: John Bieling (john@thunderbird.net) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); @@ -7,37 +30,77 @@ var LegacyPrefs = class extends ExtensionCommon.ExtensionAPI { return { LegacyPrefs: { - // get may only return something, if a value is set - getUserPref: async function(aName) { + getLegacyPref: async function(aName, aFallback = null, userPrefOnly = true) { let prefType = Services.prefs.getPrefType(aName); if (prefType == Services.prefs.PREF_INVALID) { - return null; + return aFallback; } - let value = null; - if (Services.prefs.prefHasUserValue(aName)) { + let value = aFallback; + if (!userPrefOnly || Services.prefs.prefHasUserValue(aName)) { switch (prefType) { case Services.prefs.PREF_STRING: - value = Services.prefs.getCharPref(aName, null); + value = Services.prefs.getStringPref(aName, aFallback); break; case Services.prefs.PREF_INT: - value = Services.prefs.getIntPref(aName, null); + value = Services.prefs.getIntPref(aName, aFallback); break; case Services.prefs.PREF_BOOL: - value = Services.prefs.getBoolPref(aName, null); + value = Services.prefs.getBoolPref(aName, aFallback); break; default: - console.error(`Legacy preference <${aName}> has an unknown type of <${prefType}>. Migration skipped.`); + console.error(`Legacy preference <${aName}> has an unknown type of <${prefType}>.`); } } return value; }, + + // only returns something, if a user pref value is set + getUserPref: async function(aName) { + return await this.getLegacyPref(aName); + }, + + // returns the default value, if no user defined value exists, + // and returns the fallback value, if the preference does not exist + getPref: async function(aName, aFallback = null) { + return await this.getLegacyPref(aName, aFallback, false); + }, clearUserPref: function(aName) { Services.prefs.clearUserPref(aName); + }, + + + // sets a pref + setPref: async function(aName, aValue) { + let prefType = Services.prefs.getPrefType(aName); + if (prefType == Services.prefs.PREF_INVALID) { + return false; + } + + switch (prefType) { + case Services.prefs.PREF_STRING: + Services.prefs.setStringPref(aName, aValue); + return true; + break; + + case Services.prefs.PREF_INT: + Services.prefs.setIntPref(aName, aValue); + return true; + break; + + case Services.prefs.PREF_BOOL: + Services.prefs.setBoolPref(aName, aValue); + return true; + break; + + default: + console.error(`Legacy preference <${aName}> has an unknown type of <${prefType}>.`); + } + return false; } } diff --git a/api/LegacyPrefs/schema.json b/api/LegacyPrefs/schema.json index 0e6bde2..2be3196 100644 --- a/api/LegacyPrefs/schema.json +++ b/api/LegacyPrefs/schema.json @@ -15,6 +15,54 @@ } ] }, + { + "name": "getPref", + "type": "function", + "async": true, + "description": "Gets a value from the legacy pref system.", + "parameters": [ + { + "name": "aName", + "type": "string", + "description": "Name of the preference." + }, + { + "name": "aFallback", + "type": "string", + "description": "Value to be returned, if the requested preference does not exist.", + "optional": true, + "default": null + } + ] + }, + { + "name": "setPref", + "type": "function", + "async": true, + "description": "Sets a value for an existing pref of the legacy pref system.", + "parameters": [ + { + "name": "aName", + "type": "string", + "description": "Name of the preference." + }, + { + "name": "aValue", + "choices": [ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "type": "boolean" + } + ], + "description": "Value to be set." + } + ] + }, { "name": "clearUserPref", "type": "function", diff --git a/background.js b/background.js index 5a4aee0..3f2ef58 100644 --- a/background.js +++ b/background.js @@ -1,5 +1,21 @@ -(async () => { +/* + * The WL API may only be called from the background script, so when we wish to call + * openOptionsDialog we need to tunnel the request though the messaging system. + */ +messenger.runtime.onMessage.addListener((data, sender) => { + switch (data.command) { + case "openOptionsDialog": + messenger.WindowListener.openOptionsDialog(data.windowId); + break; + case "closeFirstRunTab": + messenger.tabs.remove(sender.tab.id); + break; + } +}); + + +(async () => { messenger.WindowListener.registerDefaultPrefs( "defaults/preferences/defaults.js"); @@ -11,10 +27,6 @@ messenger.WindowListener.registerOptionsPage( "chrome://tblatex/content/options.xhtml"); - - messenger.WindowListener.registerWindow( - "chrome://messenger/content/messenger.xhtml", - "chrome://tblatex/content/scripts/messenger_firstrun.js"); messenger.WindowListener.registerWindow( "chrome://messenger/content/messengercompose/messengercompose.xhtml", @@ -25,4 +37,14 @@ "chrome://tblatex/content/scripts/customizeToolbar.js"); messenger.WindowListener.startListening(); + + // Check if the first run tab has to be shown. + let firstrun = await messenger.LegacyPrefs.getPref("tblatex.firstrun"); + if (firstrun != 4) { + messenger.tabs.create({ + url: "content/firstrun.html" + }); + } + })(); + diff --git a/content/firstrun.html b/content/firstrun.html index 058e258..50bab68 100644 --- a/content/firstrun.html +++ b/content/firstrun.html @@ -5,90 +5,9 @@ Configuring Thunderbird LaTeX extension - + - +

Thunderbird LaTeX extension

Congratulations! You have successfully installed the Thunderbird LaTeX extension. Please take a few seconds to check that the settings we have @@ -138,10 +57,11 @@

Autodetection results

Are these settings correct?

- - + + +

+

+

- Autodetect again - diff --git a/content/firstrun.js b/content/firstrun.js index 192ac30..ff135d8 100644 --- a/content/firstrun.js +++ b/content/firstrun.js @@ -1,17 +1,63 @@ -(function () { - var prefs = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefService) - .getBranch("tblatex."); - if (prefs.getIntPref("firstrun") == 3) - return; +async function on_load() { + let plattform = await messenger.runtime.getPlatformInfo(); + let isWindows = (plattform.os == "win"); + if (isWindows) { + document.getElementById("div_win32").style.display = "block"; + } + + let found = await messenger.LatexIt.search_in_path(isWindows); + if (found.latex) { + await messenger.LegacyPrefs.setPref("tblatex.latex_path", found.latex); + } + if (found.dvipng) { + await messenger.LegacyPrefs.setPref("tblatex.dvipng_path", found.dvipng); + } - var tabmail = document.getElementById("tabmail"); - if (tabmail && 'openTab' in tabmail) /* Took this from Personas code ("Browse gallery"...) */ - Components.classes['@mozilla.org/appshell/window-mediator;1']. - getService(Components.interfaces.nsIWindowMediator). - getMostRecentWindow("mail:3pane"). - document.getElementById("tabmail"). - openTab("contentTab", { contentPage: "chrome://tblatex/content/firstrun.html" }); - else - openDialog("chrome://tblatex/content/firstrun.html", "", "width=640,height=480"); -})(); + var latex_path = await messenger.LegacyPrefs.getPref("tblatex.latex_path"); + if (latex_path.length > 0 && messenger.LatexIt.file_exists(latex_path)) { + document.getElementById("latex_path").appendChild(document.createTextNode(latex_path)); + document.getElementById("latex_icon").src = "accept.png"; + } else { + document.getElementById("latex_path").innerHTML = "Not Found!"; + document.getElementById("button_yes").setAttribute("disabled", "disabled"); + } + var dvipng_path = await messenger.LegacyPrefs.getPref("tblatex.dvipng_path"); + if (dvipng_path.length > 0 && messenger.LatexIt.file_exists(dvipng_path)) { + document.getElementById("dvipng_path").appendChild(document.createTextNode(dvipng_path)); + document.getElementById("dvipng_icon").src = "accept.png"; + } else { + document.getElementById("dvipng_path").innerHTML = "Not Found!"; + document.getElementById("button_yes").setAttribute("disabled", "disabled"); + } + + if (window.arguments && window.arguments[0]) { + window.arguments[0](document); + } +} + +async function on_yes() { + await messenger.LegacyPrefs.setPref("tblatex.firstrun", 3); + messenger.runtime.sendMessage({ + command: "closeFirstRunTab" + }) +} + +async function on_no() { + let w = await messenger.windows.getCurrent(); + messenger.runtime.sendMessage({ + command: "openOptionsDialog", + windowId: w.id + }) + await on_yes(); +} + +window.addEventListener("load", () => { + // Fire and forget, do not await the call. + on_load(); + + document.getElementById("button_no").addEventListener("click", on_no); + document.getElementById("button_yes").addEventListener("click", on_yes); + document.getElementById("button_autodetect").addEventListener("click", (e) => { + document.location.reload(); + }); +}); diff --git a/content/scripts/messenger_firstrun.js b/content/scripts/messenger_firstrun.js deleted file mode 100644 index 6a04e35..0000000 --- a/content/scripts/messenger_firstrun.js +++ /dev/null @@ -1,12 +0,0 @@ -// Import any needed modules. -var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - -// Load an additional JavaScript file. -Services.scriptloader.loadSubScript("chrome://tblatex/content/firstrun.js", window, "UTF-8"); -Services.scriptloader.loadSubScript("chrome://tblatex/content/osx-path-hacks.js", window, "UTF-8"); - -function onLoad(activatedWhileWindowOpen) { -} - -function onUnload(deactivatedWhileWindowOpen) { -} \ No newline at end of file diff --git a/manifest.json b/manifest.json index d3d2cea..44f810e 100644 --- a/manifest.json +++ b/manifest.json @@ -27,6 +27,22 @@ "paths": [["WindowListener"]], "script": "api/WindowListener/implementation.js" } + }, + "LegacyPrefs": { + "schema": "api/LegacyPrefs/schema.json", + "parent": { + "scopes": ["addon_parent"], + "paths": [["LegacyPrefs"]], + "script": "api/LegacyPrefs/implementation.js" + } + }, + "LatexIt": { + "schema": "api/LatexIt/schema.json", + "parent": { + "scopes": ["addon_parent"], + "paths": [["LatexIt"]], + "script": "api/LatexIt/implementation.js" + } } } } From 31a9668f43631d1473f22760affc0c15f057a383 Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 11:13:46 +0100 Subject: [PATCH 2/8] 3 it is --- background.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/background.js b/background.js index 3f2ef58..4bc186b 100644 --- a/background.js +++ b/background.js @@ -40,7 +40,7 @@ messenger.runtime.onMessage.addListener((data, sender) => { // Check if the first run tab has to be shown. let firstrun = await messenger.LegacyPrefs.getPref("tblatex.firstrun"); - if (firstrun != 4) { + if (firstrun != 3) { messenger.tabs.create({ url: "content/firstrun.html" }); From e26da18db651dcc639898035486e5e0c234d0f7c Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 14:05:32 +0100 Subject: [PATCH 3/8] add onNotify --- api/WindowListener/implementation.js | 20 ++++++++++++++++++++ api/WindowListener/schema.json | 15 ++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/api/WindowListener/implementation.js b/api/WindowListener/implementation.js index f3d2ee5..3ee50fc 100644 --- a/api/WindowListener/implementation.js +++ b/api/WindowListener/implementation.js @@ -412,9 +412,29 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { }, }; + this.onNotifyObserver = { + observe: function (aSubject, aTopic, aData) { + if (self.observerTracker && aData == self.extension.id) { + self.observerTracker(aSubject.wrappedJSObject); + } + } + } return { WindowListener: { + onNotify: new ExtensionCommon.EventManager({ + context, + name: "WindowListener.onNotify", + register: fire => { + Services.obs.addObserver(self.onNotifyObserver, "WindowListenerMessageObserver", false); + self.observerTracker = fire.sync; + return () => { + Services.obs.removeObserver(self.onNotifyObserver, "WindowListenerMessageObserver", false); + self.observerTracker = null; + }; + }, + }).api(), + async waitForMasterPassword() { // Wait until master password has been entered (if needed) while (!Services.logins.isLoggedIn) { diff --git a/api/WindowListener/schema.json b/api/WindowListener/schema.json index 4ba5b01..a0bb6b2 100644 --- a/api/WindowListener/schema.json +++ b/api/WindowListener/schema.json @@ -1,6 +1,19 @@ [ { - "namespace": "WindowListener", + "namespace": "WindowListener", + "events": [ + { + "name": "onNotify", + "type": "function", + "description": "Fired when a new notification for 'WindowListenerMessageObserver' has been received with aData matching the ID of this extension.", + "parameters": [ + { + "name": "info", + "type": "any" + } + ] + } + ], "functions": [ { "name": "registerDefaultPrefs", From dcf803d13d4db48262fc0d611d49e23a5aa42314 Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 14:14:07 +0100 Subject: [PATCH 4/8] allow to open WebExtension first-run-tab from legacy options --- background.js | 31 +++++++++++++++++++++++++------ content/options.js | 9 +++++++-- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/background.js b/background.js index 4bc186b..aa2687d 100644 --- a/background.js +++ b/background.js @@ -2,18 +2,39 @@ * The WL API may only be called from the background script, so when we wish to call * openOptionsDialog we need to tunnel the request though the messaging system. */ -messenger.runtime.onMessage.addListener((data, sender) => { - switch (data.command) { +messenger.runtime.onMessage.addListener((info, sender) => { + switch (info.command) { case "openOptionsDialog": - messenger.WindowListener.openOptionsDialog(data.windowId); + messenger.WindowListener.openOptionsDialog(info.windowId); break; case "closeFirstRunTab": messenger.tabs.remove(sender.tab.id); break; + case "openFirstRunTab": + openFirstRunTab(); + break; + } +}); + + +/* + * Register a onNotify listener to catch messages send from privileged scope. +*/ +messenger.WindowListener.onNotify.addListener((info) => { + switch (info.command) { + case "openFirstRunTab": + openFirstRunTab(); + break; } }); +function openFirstRunTab() { + messenger.tabs.create({ + url: "content/firstrun.html" + }); +} + (async () => { messenger.WindowListener.registerDefaultPrefs( @@ -41,9 +62,7 @@ messenger.runtime.onMessage.addListener((data, sender) => { // Check if the first run tab has to be shown. let firstrun = await messenger.LegacyPrefs.getPref("tblatex.firstrun"); if (firstrun != 3) { - messenger.tabs.create({ - url: "content/firstrun.html" - }); + openFirstRunTab(); } })(); diff --git a/content/options.js b/content/options.js index 974c45e..58e1544 100644 --- a/content/options.js +++ b/content/options.js @@ -1,3 +1,5 @@ +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + function pick_file(pref, title) { var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); @@ -36,8 +38,11 @@ function add_links(aDoc) { } function open_autodetect() { - window.openDialog('chrome://tblatex/content/firstrun.html', '', - 'all,chrome,dialog=no,status,toolbar,width=640,height=480', add_links); + // Notify WebExtension Background to open the first run tab. + Services.obs.notifyObservers( + {command: "openFirstRunTab"}, + "WindowListenerMessageObserver", + "tblatex@xulforum.org"); } window.addEventListener("load", function (event) { From 9010a3a36966538d37e26dea425393814b11caa9 Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 14:22:36 +0100 Subject: [PATCH 5/8] better name of observer + documentation --- api/WindowListener/implementation.js | 23 +++++++++++++++++++++-- content/options.js | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/api/WindowListener/implementation.js b/api/WindowListener/implementation.js index 3ee50fc..9ec1171 100644 --- a/api/WindowListener/implementation.js +++ b/api/WindowListener/implementation.js @@ -2,6 +2,25 @@ * This file is provided by the addon-developer-support repository at * https://github.com/thundernest/addon-developer-support * + * Version: 1.40 + * - Add onNotify event, which can be registered in the background page, to send + * commands from privileged code: + * + * // in background + * messenger.WindowListener.onNotify.addListener((info) => { + * switch (info.command) { + * case "doSomething": + * soSomething(); + * break; + * } + * }); + * + * // in privileged code + * Services.obs.notifyObservers( + * {command: "doSomething"}, + * "WindowListenerBackgroundObserver", + * ); + * * Version: 1.39 * - fix for 68 * @@ -426,10 +445,10 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { context, name: "WindowListener.onNotify", register: fire => { - Services.obs.addObserver(self.onNotifyObserver, "WindowListenerMessageObserver", false); + Services.obs.addObserver(self.onNotifyObserver, "WindowListenerBackgroundObserver", false); self.observerTracker = fire.sync; return () => { - Services.obs.removeObserver(self.onNotifyObserver, "WindowListenerMessageObserver", false); + Services.obs.removeObserver(self.onNotifyObserver, "WindowListenerBackgroundObserver", false); self.observerTracker = null; }; }, diff --git a/content/options.js b/content/options.js index 58e1544..163a8b9 100644 --- a/content/options.js +++ b/content/options.js @@ -41,7 +41,7 @@ function open_autodetect() { // Notify WebExtension Background to open the first run tab. Services.obs.notifyObservers( {command: "openFirstRunTab"}, - "WindowListenerMessageObserver", + "WindowListenerBackgroundObserver", "tblatex@xulforum.org"); } From 6dd271896cadf33a1fd4126e0b27f472ca86b97d Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 14:38:24 +0100 Subject: [PATCH 6/8] merge osx-path-hack into firstrun.js --- api/LatexIt/implementation.js | 17 ++++++++++++++++- api/LatexIt/schema.json | 7 ++++++- content/firstrun.js | 14 +++++++++++++- content/osx-path-hacks.js | 22 ---------------------- 4 files changed, 35 insertions(+), 25 deletions(-) delete mode 100644 content/osx-path-hacks.js diff --git a/api/LatexIt/implementation.js b/api/LatexIt/implementation.js index 98105b5..84f3e59 100644 --- a/api/LatexIt/implementation.js +++ b/api/LatexIt/implementation.js @@ -25,12 +25,27 @@ var LatexIt = class extends ExtensionCommon.ExtensionAPI { return file.exists(); }, - search_in_path: async function(isWindows) { + search_in_path: async function(isWindows, extraEnvPathSuggestions) { var env = Cc["@mozilla.org/process/environment;1"].createInstance(Ci.nsIEnvironment); var sep = isWindows ? ";" : ":"; var ext = isWindows ? ".exe" : ""; var dirs = env.get("PATH").split(sep); + // add suggestions to path + let pathMod = false; + for (let i = 0; i < extraEnvPathSuggestions.length; ++i) { + if (dirs.indexOf(suggestions[i]) < 0) { + dirs.push(suggestions[i]); + pathMod = true; + } + } + // Do we really have to CHANGE the path? We added the suggestions + // for the search and store the full path found. + if (pathMod) { + env.set("PATH", dirs.join(sep)); + dump("New path: " + env.get("PATH") + "\n"); + } + let found = {}; for (var i = 0; i < dirs.length; ++i) { diff --git a/api/LatexIt/schema.json b/api/LatexIt/schema.json index d260087..31ec2c5 100644 --- a/api/LatexIt/schema.json +++ b/api/LatexIt/schema.json @@ -24,7 +24,12 @@ { "name": "isWindows", "type": "boolean" - } + }, + { + "name": "extraEnvPathSuggestions", + "type": "array", + "items": { "type": "string" } + } ] } ] diff --git a/content/firstrun.js b/content/firstrun.js index ff135d8..823fc07 100644 --- a/content/firstrun.js +++ b/content/firstrun.js @@ -1,11 +1,23 @@ async function on_load() { + let extraEnvPathSuggestions = []; let plattform = await messenger.runtime.getPlatformInfo(); let isWindows = (plattform.os == "win"); + let isOSX = (plattform.os == "mac"); + if (isWindows) { document.getElementById("div_win32").style.display = "block"; } - let found = await messenger.LatexIt.search_in_path(isWindows); + if (isOSX) { + extraEnvPathSuggestions = [ + "/usr/local/bin", + "/usr/texbin", + "/usr/X11/bin", + "/usr/local/texlive/2016/bin/x86_64-darwin/" + ]; + } + + let found = await messenger.LatexIt.search_in_path(isWindows, extraEnvPathSuggestions); if (found.latex) { await messenger.LegacyPrefs.setPref("tblatex.latex_path", found.latex); } diff --git a/content/osx-path-hacks.js b/content/osx-path-hacks.js deleted file mode 100644 index 7cdca04..0000000 --- a/content/osx-path-hacks.js +++ /dev/null @@ -1,22 +0,0 @@ -(function () { - var isOSX = ("nsILocalFileMac" in Components.interfaces); - var Cc = Components.classes; - var Ci = Components.interfaces; - - if (isOSX) { - var env = Cc["@mozilla.org/process/environment;1"].createInstance(Ci.nsIEnvironment); - var paths = env.get("PATH").split(":"); - var suggestions = [ - "/usr/local/bin", - "/usr/texbin", - "/usr/X11/bin", - "/usr/local/texlive/2016/bin/x86_64-darwin/" - ]; - for (var i = 0; i < suggestions.length; ++i) { - if (paths.indexOf(suggestions[i]) < 0) - paths.push(suggestions[i]); - } - env.set("PATH", paths.join(":")); - dump("New path: "+env.get("PATH")+"\n"); - } -})(); From 6c39a79776656352663da6147472f8cc19d669e8 Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 17:17:43 +0100 Subject: [PATCH 7/8] add notifyLegacy() --- api/WindowListener/implementation.js | 51 ++++++++++++++++++++++------ api/WindowListener/schema.json | 19 +++++++++-- background.js | 5 ++- content/options.js | 19 ++++++++++- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/api/WindowListener/implementation.js b/api/WindowListener/implementation.js index 9ec1171..c1bcb57 100644 --- a/api/WindowListener/implementation.js +++ b/api/WindowListener/implementation.js @@ -2,12 +2,35 @@ * This file is provided by the addon-developer-support repository at * https://github.com/thundernest/addon-developer-support * - * Version: 1.40 - * - Add onNotify event, which can be registered in the background page, to send - * commands from privileged code: + * 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: + * + * //in background + * messenger.WindowListener.notifyLegacy({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 background - * messenger.WindowListener.onNotify.addListener((info) => { + * messenger.WindowListener.onNotifyBackground.addListener((info) => { * switch (info.command) { * case "doSomething": * soSomething(); @@ -18,7 +41,7 @@ * // in privileged code * Services.obs.notifyObservers( * {command: "doSomething"}, - * "WindowListenerBackgroundObserver", + * "WindowListenerNotifyBackgroundObserver", * ); * * Version: 1.39 @@ -431,7 +454,7 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { }, }; - this.onNotifyObserver = { + this.onNotifyBackgroundObserver = { observe: function (aSubject, aTopic, aData) { if (self.observerTracker && aData == self.extension.id) { self.observerTracker(aSubject.wrappedJSObject); @@ -441,14 +464,22 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { return { WindowListener: { - onNotify: new ExtensionCommon.EventManager({ + notifyLegacy(info) { + Services.obs.notifyObservers( + info, + "WindowListenerNotifyLegacyObserver", + self.extension.id + ); + }, + + onNotifyBackground: new ExtensionCommon.EventManager({ context, - name: "WindowListener.onNotify", + name: "WindowListener.onNotifyBackground", register: fire => { - Services.obs.addObserver(self.onNotifyObserver, "WindowListenerBackgroundObserver", false); + Services.obs.addObserver(self.onNotifyBackgroundObserver, "WindowListenerNotifyBackgroundObserver", false); self.observerTracker = fire.sync; return () => { - Services.obs.removeObserver(self.onNotifyObserver, "WindowListenerBackgroundObserver", false); + Services.obs.removeObserver(self.onNotifyBackgroundObserver, "WindowListenerNotifyBackgroundObserver", false); self.observerTracker = null; }; }, diff --git a/api/WindowListener/schema.json b/api/WindowListener/schema.json index a0bb6b2..4a9ef23 100644 --- a/api/WindowListener/schema.json +++ b/api/WindowListener/schema.json @@ -3,18 +3,31 @@ "namespace": "WindowListener", "events": [ { - "name": "onNotify", + "name": "onNotifyBackground", "type": "function", - "description": "Fired when a new notification for 'WindowListenerMessageObserver' has been received with aData matching the ID of this extension.", + "description": "Fired when a new notification for 'WindowListenerNotifyBackgroundObserver' has been received with aData matching the ID of this extension. Only one listener is supported.", "parameters": [ { "name": "info", - "type": "any" + "type": "any", + "description": "Info object passed into notifyObserver as aSubject and forwarded to the listener. Restrictions of the structured clone algorythm apply." } ] } ], "functions": [ + { + "name": "notifyLegacy", + "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.", + "parameters": [ + { + "name": "info", + "type": "any", + "description": "Info object forwarded to the observer. The value will be in aSubject.wrappedJSObject. Restrictions of the structured clone algorythm apply." + } + ] + }, { "name": "registerDefaultPrefs", "type": "function", diff --git a/background.js b/background.js index aa2687d..15fec48 100644 --- a/background.js +++ b/background.js @@ -20,10 +20,13 @@ messenger.runtime.onMessage.addListener((info, sender) => { /* * Register a onNotify listener to catch messages send from privileged scope. */ -messenger.WindowListener.onNotify.addListener((info) => { +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; } }); diff --git a/content/options.js b/content/options.js index 163a8b9..9331771 100644 --- a/content/options.js +++ b/content/options.js @@ -1,5 +1,22 @@ 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); @@ -41,7 +58,7 @@ function open_autodetect() { // Notify WebExtension Background to open the first run tab. Services.obs.notifyObservers( {command: "openFirstRunTab"}, - "WindowListenerBackgroundObserver", + "WindowListenerNotifyBackgroundObserver", "tblatex@xulforum.org"); } From d94168c500acc93a4f1b78716cdf42294508a0b8 Mon Sep 17 00:00:00 2001 From: John Bieling Date: Wed, 17 Mar 2021 17:29:39 +0100 Subject: [PATCH 8/8] Removed unused code TB no longer allows in-app links but always redirects to the system browser. --- content/firstrun.js | 4 ---- content/options.js | 24 ------------------------ 2 files changed, 28 deletions(-) diff --git a/content/firstrun.js b/content/firstrun.js index 823fc07..99adaf4 100644 --- a/content/firstrun.js +++ b/content/firstrun.js @@ -41,10 +41,6 @@ async function on_load() { document.getElementById("dvipng_path").innerHTML = "Not Found!"; document.getElementById("button_yes").setAttribute("disabled", "disabled"); } - - if (window.arguments && window.arguments[0]) { - window.arguments[0](document); - } } async function on_yes() { diff --git a/content/options.js b/content/options.js index 9331771..fc2d794 100644 --- a/content/options.js +++ b/content/options.js @@ -30,30 +30,6 @@ function pick_file(pref, title) { }); } -function add_links(aDoc) { - if (!window.Application) //TB 2.x will open this properly in an external browser - return; - - var links = aDoc.getElementsByClassName("external"); - for (var i = 0; i < links.length; ++i) (function (i) { - dump("link "+i+"\n"); - var uri = links[i].getAttribute("href"); - links[i].addEventListener("click", - function link_listener (event) { - if (!(uri instanceof Components.interfaces.nsIURI)) - uri = Components.classes["@mozilla.org/network/io-service;1"] - .getService(Components.interfaces.nsIIOService) - .newURI(uri, null, null); - - Components.classes["@mozilla.org/uriloader/external-protocol-service;1"] - .getService(Components.interfaces.nsIExternalProtocolService) - .loadURI(uri); - - event.preventDefault(); - }, true); - })(i); -} - function open_autodetect() { // Notify WebExtension Background to open the first run tab. Services.obs.notifyObservers(