-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
247 additions
and
167 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,16 @@ | |
* This file is provided by the addon-developer-support repository at | ||
* https://github.com/thundernest/addon-developer-support | ||
* | ||
* Version 1.4 | ||
* - updated implementation to not assign this anymore | ||
* | ||
* Version 1.3 | ||
* - moved registering the observer into startup | ||
* | ||
* Version 1.1 | ||
* - added startup event, to make sure API is ready as soon as the add-on is starting | ||
* NOTE: This requires to add the startup event to the manifest, see: | ||
* https://github.com/thundernest/addon-developer-support/tree/master/auxiliary-apis/NotifyTools#usage | ||
* | ||
* Author: John Bieling ([email protected]) | ||
* | ||
|
@@ -11,28 +20,62 @@ | |
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
|
||
// Get various parts of the WebExtension framework that we need. | ||
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); | ||
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm"); | ||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); | ||
"use strict"; | ||
|
||
(function (exports) { | ||
|
||
// Get various parts of the WebExtension framework that we need. | ||
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); | ||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); | ||
|
||
var observerTracker = new Set(); | ||
|
||
class NotifyTools extends ExtensionCommon.ExtensionAPI { | ||
getAPI(context) { | ||
return { | ||
NotifyTools: { | ||
|
||
notifyExperiment(data) { | ||
return new Promise(resolve => { | ||
Services.obs.notifyObservers( | ||
{ data, resolve }, | ||
"NotifyExperimentObserver", | ||
context.extension.id | ||
); | ||
}); | ||
}, | ||
|
||
onNotifyBackground: new ExtensionCommon.EventManager({ | ||
context, | ||
name: "NotifyTools.onNotifyBackground", | ||
register: (fire) => { | ||
observerTracker.add(fire.sync); | ||
return () => { | ||
observerTracker.delete(fire.sync); | ||
}; | ||
}, | ||
}).api(), | ||
|
||
var NotifyTools = class extends ExtensionCommon.ExtensionAPI { | ||
getAPI(context) { | ||
var self = this; | ||
} | ||
}; | ||
} | ||
|
||
this.onNotifyBackgroundObserver = { | ||
observe: async function (aSubject, aTopic, aData) { | ||
// Force API to run at startup, otherwise event listeners might not be added at the requested time. Also needs | ||
// "events": ["startup"] in the experiment manifest | ||
onStartup() { | ||
this.onNotifyBackgroundObserver = async (aSubject, aTopic, aData) => { | ||
if ( | ||
Object.keys(self.observerTracker).length > 0 && | ||
aData == self.extension.id | ||
observerTracker.size > 0 && | ||
aData == this.extension.id | ||
) { | ||
let payload = aSubject.wrappedJSObject; | ||
// This is called from the BL observer.js and therefore it should have a resolve | ||
// payload, but better check. | ||
|
||
// Make sure payload has a resolve function, which we use to resolve the | ||
// observer notification. | ||
if (payload.resolve) { | ||
let observerTrackerPromises = []; | ||
// Push listener into promise array, so they can run in parallel | ||
for (let listener of Object.values(self.observerTracker)) { | ||
for (let listener of observerTracker.values()) { | ||
observerTrackerPromises.push(listener(payload.data)); | ||
} | ||
// We still have to await all of them but wait time is just the time needed | ||
|
@@ -54,70 +97,39 @@ var NotifyTools = class extends ExtensionCommon.ExtensionAPI { | |
payload.resolve(results[0]); | ||
} | ||
} else { | ||
// Just call the listener. | ||
for (let listener of Object.values(self.observerTracker)) { | ||
// Older version of NotifyTools, which is not sending a resolve function, deprecated. | ||
console.log("Please update the notifyTools API and the notifyTools script to at least v1.5"); | ||
for (let listener of observerTracker.values()) { | ||
listener(payload.data); | ||
} | ||
} | ||
} | ||
}, | ||
}; | ||
|
||
this.observerTracker = {}; | ||
this.observerTrackerNext = 1; | ||
// Add observer for notifyTools.js | ||
Services.obs.addObserver( | ||
this.onNotifyBackgroundObserver, | ||
"NotifyBackgroundObserver", | ||
false | ||
); | ||
|
||
return { | ||
NotifyTools: { | ||
|
||
notifyExperiment(data) { | ||
return new Promise(resolve => { | ||
Services.obs.notifyObservers( | ||
{ data, resolve }, | ||
"NotifyExperimentObserver", | ||
self.extension.id | ||
); | ||
}); | ||
}, | ||
|
||
onNotifyBackground: new ExtensionCommon.EventManager({ | ||
context, | ||
name: "NotifyTools.onNotifyBackground", | ||
register: (fire) => { | ||
let trackerId = self.observerTrackerNext++; | ||
self.observerTracker[trackerId] = fire.sync; | ||
return () => { | ||
delete self.observerTracker[trackerId]; | ||
}; | ||
}, | ||
}).api(), | ||
}; | ||
|
||
} | ||
}; | ||
} | ||
// Add observer for notifyTools.js | ||
Services.obs.addObserver( | ||
this.onNotifyBackgroundObserver, | ||
"NotifyBackgroundObserver", | ||
false | ||
); | ||
} | ||
|
||
// Force API to run at startup, otherwise event listeners might not be added at the requested time. Also needs | ||
// "events": ["startup"] in the experiment manifest | ||
onShutdown(isAppShutdown) { | ||
if (isAppShutdown) { | ||
return; // the application gets unloaded anyway | ||
} | ||
|
||
onStartup() { } | ||
// Remove observer for notifyTools.js | ||
Services.obs.removeObserver( | ||
this.onNotifyBackgroundObserver, | ||
"NotifyBackgroundObserver" | ||
); | ||
|
||
onShutdown(isAppShutdown) { | ||
if (isAppShutdown) { | ||
return; // the application gets unloaded anyway | ||
// Flush all caches | ||
Services.obs.notifyObservers(null, "startupcache-invalidate"); | ||
} | ||
}; | ||
|
||
// Remove observer for notifyTools.js | ||
Services.obs.removeObserver( | ||
this.onNotifyBackgroundObserver, | ||
"NotifyBackgroundObserver" | ||
); | ||
exports.NotifyTools = NotifyTools; | ||
|
||
// Flush all caches | ||
Services.obs.notifyObservers(null, "startupcache-invalidate"); | ||
} | ||
}; | ||
})(this) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
* This file is provided by the addon-developer-support repository at | ||
* https://github.com/thundernest/addon-developer-support | ||
* | ||
* Version: 1.56 | ||
* Version: 1.57 | ||
* | ||
* Author: John Bieling ([email protected]) | ||
* | ||
|
@@ -200,7 +200,7 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { | |
// returns the outer browser, not the nested browser of the add-on manager | ||
// events must be attached to the outer browser | ||
getAddonManagerFromTab(tab) { | ||
if (tab.browser) { | ||
if (tab.browser && tab.mode.name == "contentTab") { | ||
let win = tab.browser.contentWindow; | ||
if (win && win.location.href == "about:addons") { | ||
return win; | ||
|
@@ -211,9 +211,28 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { | |
getAddonManagerFromWindow(window) { | ||
let tabMail = this.getTabMail(window); | ||
for (let tab of tabMail.tabInfo) { | ||
let win = this.getAddonManagerFromTab(tab); | ||
if (win) { | ||
return win; | ||
let managerWindow = this.getAddonManagerFromTab(tab); | ||
if (managerWindow) { | ||
return managerWindow; | ||
} | ||
} | ||
} | ||
|
||
async getAddonManagerFromWindowWaitForLoad(window) { | ||
let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane"); | ||
|
||
let tabMail = this.getTabMail(window); | ||
for (let tab of tabMail.tabInfo) { | ||
if (tab.browser && tab.mode.name == "contentTab") { | ||
// Instead of registering a load observer, wait until its loaded. Not nice, | ||
// but gets aroud a lot of edge cases. | ||
while(!tab.pageLoaded) { | ||
await new Promise(r => setTimeout(r, 150)); | ||
} | ||
let managerWindow = this.getAddonManagerFromTab(tab); | ||
if (managerWindow) { | ||
return managerWindow; | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -329,41 +348,20 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { | |
|
||
// TabMonitor to detect opening of tabs, to setup the options button in the add-on manager. | ||
this.tabMonitor = { | ||
onTabTitleChanged(aTab) { }, | ||
onTabClosing(aTab) { }, | ||
onTabPersist(aTab) { }, | ||
onTabRestored(aTab) { }, | ||
onTabSwitched(aNewTab, aOldTab) { | ||
//self.setupAddonManager(self.getAddonManagerFromTab(aNewTab)); | ||
}, | ||
async onTabOpened(aTab) { | ||
if (aTab.browser) { | ||
if (!aTab.pageLoaded) { | ||
// await a location change if browser is not loaded yet | ||
await new Promise((resolve) => { | ||
let reporterListener = { | ||
QueryInterface: ChromeUtils.generateQI([ | ||
"nsIWebProgressListener", | ||
"nsISupportsWeakReference", | ||
]), | ||
onStateChange() { }, | ||
onProgressChange() { }, | ||
onLocationChange( | ||
/* in nsIWebProgress*/ aWebProgress, | ||
/* in nsIRequest*/ aRequest, | ||
/* in nsIURI*/ aLocation | ||
) { | ||
aTab.browser.removeProgressListener(reporterListener); | ||
resolve(); | ||
}, | ||
onStatusChange() { }, | ||
onSecurityChange() { }, | ||
onContentBlockingEvent() { }, | ||
}; | ||
aTab.browser.addProgressListener(reporterListener); | ||
}); | ||
onTabTitleChanged(tab) { }, | ||
onTabClosing(tab) { }, | ||
onTabPersist(tab) { }, | ||
onTabRestored(tab) { }, | ||
onTabSwitched(aNewTab, aOldTab) { }, | ||
async onTabOpened(tab) { | ||
if (tab.browser && tab.mode.name == "contentTab") { | ||
let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane"); | ||
// Instead of registering a load observer, wait until its loaded. Not nice, | ||
// but gets aroud a lot of edge cases. | ||
while(!tab.pageLoaded) { | ||
await new Promise(r => setTimeout(r, 150)); | ||
} | ||
self.setupAddonManager(self.getAddonManagerFromTab(aTab)); | ||
self.setupAddonManager(self.getAddonManagerFromTab(tab)); | ||
} | ||
}, | ||
}; | ||
|
@@ -594,16 +592,14 @@ var WindowListener = class extends ExtensionCommon.ExtensionAPI { | |
self | ||
); | ||
} else { | ||
// Setup the options button/menu in the add-on manager, if it is already open. | ||
self.setupAddonManager( | ||
self.getAddonManagerFromWindow(window), | ||
true | ||
); | ||
// Add a tabmonitor, to be able to setup the options button/menu in the add-on manager. | ||
self | ||
.getTabMail(window) | ||
.registerTabMonitor(self.tabMonitor); | ||
window[self.uniqueRandomID].hasTabMonitor = true; | ||
// Setup the options button/menu in the add-on manager, if it is already open. | ||
let managerWindow = await self.getAddonManagerFromWindowWaitForLoad(window); | ||
self.setupAddonManager(managerWindow, true); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.