Skip to content

Commit 5cb86bd

Browse files
committed
v3.0.0
(2020-10-25) Adopted for Thunderbird 78
1 parent 8a44e6f commit 5cb86bd

7 files changed

Lines changed: 370 additions & 354 deletions

File tree

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* This file is provided by the addon-developer-support repository at
3+
* https://github.com/thundernest/addon-developer-support
4+
*
5+
* Version: 1.2
6+
* - add support for resource urls
7+
*
8+
* Author: John Bieling (john@thunderbird.net)
9+
*
10+
* This Source Code Form is subject to the terms of the Mozilla Public
11+
* License, v. 2.0. If a copy of the MPL was not distributed with this
12+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
13+
*/
14+
15+
// Get various parts of the WebExtension framework that we need.
16+
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
17+
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
18+
var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
19+
var log = console.log.bind(console);
20+
21+
var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
22+
getAPI(context) {
23+
this.pathToBootstrapScript = null;
24+
this.chromeHandle = null;
25+
this.chromeData = null;
26+
this.resourceData = null;
27+
this.bootstrappedObj = {};
28+
29+
// make the extension object and the messenger object available inside
30+
// the bootstrapped scope
31+
this.bootstrappedObj.extension = context.extension;
32+
this.bootstrappedObj.messenger = Array.from(context.extension.views)
33+
.find(view => view.viewType === "background")
34+
.xulBrowser.contentWindow.wrappedJSObject.browser;
35+
36+
37+
this.BOOTSTRAP_REASONS = {
38+
APP_STARTUP: 1,
39+
APP_SHUTDOWN: 2,
40+
ADDON_ENABLE: 3,
41+
ADDON_DISABLE: 4,
42+
ADDON_INSTALL: 5,
43+
ADDON_UNINSTALL: 6, // not supported
44+
ADDON_UPGRADE: 7,
45+
ADDON_DOWNGRADE: 8,
46+
};
47+
48+
const aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup);
49+
const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
50+
51+
let self = this;
52+
53+
return {
54+
BootstrapLoader: {
55+
56+
registerChromeUrl(data) {
57+
let chromeData = [];
58+
let resourceData = [];
59+
for (let entry of data) {
60+
if (entry[0] == "resource") resourceData.push(entry);
61+
else chromeData.push(entry)
62+
}
63+
64+
if (chromeData.length > 0) {
65+
const manifestURI = Services.io.newURI(
66+
"manifest.json",
67+
null,
68+
context.extension.rootURI
69+
);
70+
self.chromeHandle = aomStartup.registerChrome(manifestURI, chromeData);
71+
}
72+
73+
for (let res of resourceData) {
74+
// [ "resource", "shortname" , "path" ]
75+
let uri = Services.io.newURI(
76+
res[2],
77+
null,
78+
context.extension.rootURI
79+
);
80+
resProto.setSubstitutionWithFlags(
81+
res[1],
82+
uri,
83+
resProto.ALLOW_CONTENT_ACCESS
84+
);
85+
}
86+
87+
self.chromeData = chromeData;
88+
self.resourceData = resourceData;
89+
},
90+
91+
registerBootstrapScript: async function(aPath) {
92+
self.pathToBootstrapScript = aPath.startsWith("chrome://")
93+
? aPath
94+
: context.extension.rootURI.resolve(aPath);
95+
96+
// Get the addon object belonging to this extension.
97+
let addon = await AddonManager.getAddonByID(context.extension.id);
98+
//make the addon globally available in the bootstrapped scope
99+
self.bootstrappedObj.addon = addon;
100+
101+
// add BOOTSTRAP_REASONS to scope
102+
for (let reason of Object.keys(self.BOOTSTRAP_REASONS)) {
103+
self.bootstrappedObj[reason] = self.BOOTSTRAP_REASONS[reason];
104+
}
105+
106+
// Load registered bootstrap scripts and execute its startup() function.
107+
try {
108+
if (self.pathToBootstrapScript) Services.scriptloader.loadSubScript(self.pathToBootstrapScript, self.bootstrappedObj, "UTF-8");
109+
if (self.bootstrappedObj.startup) self.bootstrappedObj.startup.call(self.bootstrappedObj, self.extension.addonData, self.BOOTSTRAP_REASONS[self.extension.startupReason]);
110+
} catch (e) {
111+
Components.utils.reportError(e)
112+
}
113+
}
114+
}
115+
};
116+
}
117+
118+
onShutdown(isAppShutdown) {
119+
// Execute registered shutdown()
120+
try {
121+
if (this.bootstrappedObj.shutdown) {
122+
this.bootstrappedObj.shutdown(
123+
this.extension.addonData,
124+
isAppShutdown
125+
? this.BOOTSTRAP_REASONS.APP_SHUTDOWN
126+
: this.BOOTSTRAP_REASONS.ADDON_DISABLE);
127+
}
128+
} catch (e) {
129+
Components.utils.reportError(e)
130+
}
131+
132+
if (this.resourceData) {
133+
const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
134+
for (let res of this.resourceData) {
135+
// [ "resource", "shortname" , "path" ]
136+
resProto.setSubstitution(
137+
res[1],
138+
null,
139+
);
140+
}
141+
}
142+
143+
if (this.chromeHandle) {
144+
this.chromeHandle.destruct();
145+
this.chromeHandle = null;
146+
}
147+
148+
console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
149+
}
150+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[
2+
{
3+
"namespace": "BootstrapLoader",
4+
"functions": [
5+
{
6+
"name": "registerBootstrapScript",
7+
"type": "function",
8+
"description": "Register a bootstrap.js style script",
9+
"async": true,
10+
"parameters": [
11+
{
12+
"name": "aPath",
13+
"type": "string",
14+
"description": "Either the chrome:// path to the script or its relative location from the root of the extension,"
15+
}
16+
]
17+
}
18+
]
19+
}
20+
]

src/background.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
messenger.BootstrapLoader.registerBootstrapScript("bootstrap.js");

0 commit comments

Comments
 (0)