Skip to content

Commit 95c08a4

Browse files
committed
v3.0.1
(2020-10-26) ! options are not properly disabled ! incomplete clean up when addon gets disabled
1 parent 5cb86bd commit 95c08a4

4 files changed

Lines changed: 149 additions & 49 deletions

File tree

src/api/BootstrapLoader/implementation.js

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
* This file is provided by the addon-developer-support repository at
33
* https://github.com/thundernest/addon-developer-support
44
*
5+
* Version 1.4
6+
* - add registerOptionsPage
7+
*
8+
* Version: 1.3
9+
* - flush cache
10+
*
511
* Version: 1.2
612
* - add support for resource urls
713
*
@@ -14,13 +20,19 @@
1420

1521
// Get various parts of the WebExtension framework that we need.
1622
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
17-
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
23+
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");
1824
var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
19-
var log = console.log.bind(console);
25+
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
2026

2127
var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
2228
getAPI(context) {
29+
this.uniqueRandomID = "AddOnNS" + context.extension.instanceId;
30+
this.menu_addonsManager_id ="addonsManager";
31+
this.menu_addonsManager_prefs_id = "addonsManager_prefs_revived";
32+
this.menu_addonPrefs_id = "addonPrefs_revived";
33+
2334
this.pathToBootstrapScript = null;
35+
this.pathToOptionsPage = null;
2436
this.chromeHandle = null;
2537
this.chromeData = null;
2638
this.resourceData = null;
@@ -53,6 +65,12 @@ var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
5365
return {
5466
BootstrapLoader: {
5567

68+
registerOptionsPage(optionsUrl) {
69+
self.pathToOptionsPage = optionsUrl.startsWith("chrome://")
70+
? optionsUrl
71+
: context.extension.rootURI.resolve(optionsUrl);
72+
},
73+
5674
registerChromeUrl(data) {
5775
let chromeData = [];
5876
let resourceData = [];
@@ -110,12 +128,80 @@ var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
110128
} catch (e) {
111129
Components.utils.reportError(e)
112130
}
131+
132+
// Register window listener for main TB window
133+
if (self.pathToOptionsPage) {
134+
ExtensionSupport.registerWindowListener("injectListener_" + self.uniqueRandomID, {
135+
chromeURLs: [
136+
"chrome://messenger/content/messenger.xul",
137+
"chrome://messenger/content/messenger.xhtml",
138+
],
139+
async onLoadWindow(window) {
140+
try {
141+
// add the add-on options menu if needed
142+
if (!window.document.getElementById(self.menu_addonsManager_prefs_id)) {
143+
let addonprefs = window.MozXULElement.parseXULToFragment(`
144+
<menu id="${self.menu_addonsManager_prefs_id}" label="&addonPrefs.label;">
145+
<menupopup id="${self.menu_addonPrefs_id}">
146+
</menupopup>
147+
</menu>
148+
`, ["chrome://messenger/locale/messenger.dtd"]);
149+
150+
let element_addonsManager = window.document.getElementById(self.menu_addonsManager_id);
151+
element_addonsManager.parentNode.insertBefore(addonprefs, element_addonsManager.nextSibling);
152+
}
153+
154+
// add the options entry
155+
let element_addonPrefs = window.document.getElementById(self.menu_addonPrefs_id);
156+
let id = self.menu_addonPrefs_id + "_" + self.uniqueRandomID;
157+
158+
// Get the best size of the icon (16px or bigger)
159+
let iconSizes = Object.keys(self.extension.manifest.icons);
160+
iconSizes.sort((a,b)=>a-b);
161+
let bestSize = iconSizes.filter(e => parseInt(e) >= 16).shift();
162+
let icon = bestSize ? self.extension.manifest.icons[bestSize] : "";
163+
164+
let name = self.extension.manifest.name;
165+
let entry = window.MozXULElement.parseXULToFragment(
166+
`<menuitem class="menuitem-iconic" id="${id}" image="${icon}" label="${name}" />`);
167+
element_addonPrefs.appendChild(entry);
168+
let BL = {}
169+
BL.extension = self.extension;
170+
BL.messenger = Array.from(self.extension.views).find(
171+
view => view.viewType === "background").xulBrowser.contentWindow
172+
.wrappedJSObject.browser;
173+
window.document.getElementById(id).addEventListener("command", function() {window.openDialog(self.pathToOptionsPage, "AddonOptions", null, BL)});
174+
} catch (e) {
175+
Components.utils.reportError(e)
176+
}
177+
},
178+
179+
onUnloadWindow(window) {
180+
}
181+
});
182+
}
113183
}
114184
}
115185
};
116186
}
117187

118188
onShutdown(isAppShutdown) {
189+
//remove our entry in the add-on options menu
190+
if (this.pathToOptionsPage) {
191+
for (let window of Services.wm.getEnumerator("mail:3pane")) {
192+
let id = this.menu_addonPrefs_id + "_" + this.uniqueRandomID;
193+
window.document.getElementById(id).remove();
194+
195+
//do we have to remove the entire add-on options menu?
196+
let element_addonPrefs = window.document.getElementById(this.menu_addonPrefs_id);
197+
if (element_addonPrefs.children.length == 0) {
198+
window.document.getElementById(this.menu_addonsManager_prefs_id).remove();
199+
}
200+
}
201+
// Stop listening for new windows.
202+
ExtensionSupport.unregisterWindowListener("injectListener_" + this.uniqueRandomID);
203+
}
204+
119205
// Execute registered shutdown()
120206
try {
121207
if (this.bootstrappedObj.shutdown) {
@@ -144,7 +230,8 @@ var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
144230
this.chromeHandle.destruct();
145231
this.chromeHandle = null;
146232
}
147-
233+
// Flush all caches
234+
Services.obs.notifyObservers(null, "startupcache-invalidate");
148235
console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
149236
}
150237
};

src/api/BootstrapLoader/schema.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,36 @@
22
{
33
"namespace": "BootstrapLoader",
44
"functions": [
5+
{
6+
"name": "registerOptionsPage",
7+
"type": "function",
8+
"parameters": [
9+
{
10+
"name": "aPath",
11+
"type": "string",
12+
"description": "Path to the options page, which should be made accessible in the (legacy) Add-On Options menu."
13+
}
14+
]
15+
},
16+
{
17+
"name": "registerChromeUrl",
18+
"type": "function",
19+
"description": "Register folders which should be available as chrome:// urls (as defined in the legacy chrome.manifest)",
20+
"async": true,
21+
"parameters": [
22+
{
23+
"name": "chromeData",
24+
"type": "array",
25+
"items": {
26+
"type": "array",
27+
"items" : {
28+
"type": "string"
29+
}
30+
},
31+
"description": "Array of ChromeData Arrays."
32+
}
33+
]
34+
},
535
{
636
"name": "registerBootstrapScript",
737
"type": "function",

src/bootstrap.js

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ var self = this,
1111
},
1212
log = console.log.bind(console);
1313

14-
1514
function include(path)
1615
{
1716
Services.scriptloader.loadSubScript(addon.getResourceURI(path).spec, self);
@@ -147,12 +146,12 @@ function main(window)
147146

148147
function disableAll(obj, r, s)
149148
{
149+
if (obj.hasAttribute && obj.hasAttribute("autoSLM"))
150+
return true;
151+
150152
if (!s && obj.hasAttribute && obj.hasAttribute("autoSLM"))
151153
s = true;
152154

153-
if (obj.tagName == "button" || (obj.hasAttribute && obj.hasAttribute("autoSLM")))
154-
return true;
155-
156155
if (s || typeof(r) == "undefined")
157156
{
158157
if ("disabled" in obj && !("___autoSLM_disabled" in obj))
@@ -318,7 +317,7 @@ function fixpref(window, r, s)
318317
{
319318
function addElement(el, parent, type)
320319
{
321-
el.setAttribute("autoSLM", "");
320+
el.setAttribute("autoSLM", '');
322321
type = type || "appendChild";
323322

324323
if (type == "insertBefore")
@@ -331,10 +330,25 @@ function fixpref(window, r, s)
331330
el.parentNode.removeChild(el);
332331
}), false);
333332
}
334-
function prefChange()
333+
334+
function prefChange(e, val)
335335
{
336-
disableAll(startBox.parentNode.parentNode, pref.getIntPref("sel") ? true : false);
336+
if (e && (e.target.id != "autoSLM" || e.attrName != "value"))
337+
return;
338+
339+
if (e && "newValue" in e)
340+
val = ~~e.newValue;
341+
else
342+
val = pref.getIntPref("sel");
343+
344+
disableAll(startBox.parentNode.parentNode, val ? true : false);
345+
try
346+
{
347+
doc.getElementById("autoSLM_checkbox").disabled = !val;
348+
}
349+
catch (e){}
337350
}
351+
338352
if (!r && !doc.getElementById("autoSLM_box"))
339353
{
340354
let h = startBox.parentNode.parentNode.clientHeight,
@@ -343,14 +357,13 @@ function fixpref(window, r, s)
343357
menupopup = doc.createXULElement("menupopup"),
344358
menulist = doc.createXULElement("menulist"),
345359
box = doc.createXULElement("hbox"),
346-
menuitem = doc.createXULElement("menuitem"),
347-
p = doc.createXULElement("preference");
360+
menuitem = doc.createXULElement("menuitem");
348361

349362
menulist.id = "autoSLM";
350363
menulist.setAttribute("label", "Select first unread message only");
351364
menulist.setAttribute("preference", PREF_BRANCH + "sel");
352-
menulist.addEventListener("command", prefChange, true);
353-
menulist.setAttribute("onsyncfrompreference", "prefChange(event)");
365+
menulist.addEventListener("DOMAttrModified", prefChange, false);
366+
menulist.value = pref.getIntPref("sel");
354367
box.setAttribute("flex", false);
355368
box.id = "autoSLM_box";
356369
menuitem.setAttribute("value", 0);
@@ -367,44 +380,15 @@ function fixpref(window, r, s)
367380
menulist.appendChild(menupopup);
368381
box.appendChild(menulist);
369382

370-
addElement(box, startBox.parentNode, "insertBefore");
371-
372383
checkbox.id = "autoSLM_checkbox";
373384
checkbox.setAttribute("label", "Auto focus on messages list");
374385
checkbox.setAttribute("preference", PREF_BRANCH + "focus");
375-
addElement(checkbox, box);
376-
377-
let ps = doc.getElementsByTagName("preferences");
378-
if (ps.length)
379-
{
380-
ps = ps[0];
381-
}
382-
else
383-
{
384-
ps = doc.createXULElement("prefrences");
385-
startBox.appendChild(ps);
386-
}
387-
addElement(p, ps);
388-
389-
p.id = PREF_BRANCH + "sel";
390-
p.setAttribute("type", "int");
391-
p.setAttribute("name", p.id);
392-
addElement(p, ps);
386+
box.appendChild(checkbox);
393387

394-
p = doc.createXULElement("preference");
395-
p.id = PREF_BRANCH + "focus";
396-
p.setAttribute("type", "bool");
397-
p.setAttribute("name", p.id);
398-
addElement(p, ps);
388+
addElement(box, startBox.parentNode, "insertBefore");
399389

400390
width = startBox.parentNode.parentNode.clientWidth - w;
401391
height = startBox.parentNode.parentNode.clientHeight - h;
402-
// window.resizeBy(width, height);
403-
try
404-
{
405-
doc.getElementById("MailPreferences").showPane(doc.getElementById("MailPreferences").currentPane);
406-
}
407-
catch(e){}
408392
try
409393
{
410394
let p = [
@@ -425,7 +409,6 @@ function fixpref(window, r, s)
425409
listen(window, window, "unload", unload(function()
426410
{
427411
disableAll(startBox.parentNode.parentNode);
428-
// window.resizeBy(-width, -height);
429412
}), false);
430413
}
431414
else if (!s && doc.getElementById("paneGeneral"))

src/manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
"applications": {
44
"gecko": {
55
"id": "autoselectlatestmessage@vano",
6-
"strict_min_version": "78.0"
6+
"strict_min_version": "70.0"
77
}
88
},
99
"name": "Auto Select Latest Message",
1010
"author": "V@no",
1111
"description": "Automatically select and display latest message on startup or when switching folder for the first time",
12-
"version": "3.0.0",
12+
"version": "3.0.1",
1313
"experiment_apis": {
1414
"BootstrapLoader": {
1515
"schema": "api/BootstrapLoader/schema.json",
@@ -18,7 +18,7 @@
1818
"paths": [["BootstrapLoader"]],
1919
"script": "api/BootstrapLoader/implementation.js"
2020
}
21-
}
21+
}
2222
},
2323
"background": {
2424
"scripts": [

0 commit comments

Comments
 (0)