gecko-dev/mobile/android/components/extensions/ext-pageAction.js
Rob Wu be3652cd57 Bug 1287010 - Make environment of Context explicit. r=billm
- Add `envType` to BaseContext.
 - Pass an explicit envType to all `registerSchemaAPI` invocations.
 - The factories passed to `registerSchemaAPI` will be split up later, so
   that content scripts (`content_child`) and addon pages can share
   common implementations.
 - The factories that implement the addon API will also be split up,
   to separate code running in the main process (`addon_parent`) from
   code running in a child process (`addon_child`).
 - Remove the use of a hardcoded list of `namespaces` from ProxyContext.
   Now `envType` is used to specify whether an API should be activated.

MozReview-Commit-ID: Jiff8HIwG92

--HG--
extra : rebase_source : 946a3c0009a4e3223c2d10044b3099a94c845394
2016-08-16 15:51:50 -07:00

160 lines
4.3 KiB
JavaScript

/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
"resource://devtools/shared/event-emitter.js");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
// Import the android PageActions module.
XPCOMUtils.defineLazyModuleGetter(this, "PageActions",
"resource://gre/modules/PageActions.jsm");
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
IconDetails,
SingletonEventManager,
} = ExtensionUtils;
// WeakMap[Extension -> PageAction]
var pageActionMap = new WeakMap();
function PageAction(options, extension) {
this.id = null;
this.extension = extension;
this.icons = IconDetails.normalize({path: options.default_icon}, extension);
this.popupUrl = options.default_popup;
this.options = {
title: options.default_title || extension.name,
id: extension.id,
clickCallback: () => {
if (this.popupUrl) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
win.BrowserApp.addTab(this.popupUrl, {
selected: true,
parentId: win.BrowserApp.selectedTab.id,
});
} else {
this.emit("click");
}
},
};
this.shouldShow = false;
EventEmitter.decorate(this);
}
PageAction.prototype = {
show(tabId, context) {
if (this.id) {
return Promise.resolve();
}
if (this.options.icon) {
this.id = PageActions.add(this.options);
return Promise.resolve();
}
this.shouldShow = true;
let {icon} = IconDetails.getPreferredIcon(this.icons, this.extension,
18 * context.contentWindow.devicePixelRatio);
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
return IconDetails.convertImageURLToDataURL(icon, context, browserWindow).then(dataURI => {
if (this.shouldShow) {
this.options.icon = dataURI;
this.id = PageActions.add(this.options);
}
}).catch(() => {
return Promise.reject({
message: "Failed to load PageAction icon",
});
});
},
hide(tabId) {
this.shouldShow = false;
if (this.id) {
PageActions.remove(this.id);
this.id = null;
}
},
setPopup(tab, url) {
// TODO: Only set the popup for the specified tab once we have Tabs API support.
this.popupUrl = url;
},
getPopup(tab) {
// TODO: Only return the popup for the specified tab once we have Tabs API support.
return this.popupUrl;
},
shutdown() {
this.hide();
},
};
/* eslint-disable mozilla/balanced-listeners */
extensions.on("manifest_page_action", (type, directive, extension, manifest) => {
let pageAction = new PageAction(manifest.page_action, extension);
pageActionMap.set(extension, pageAction);
});
extensions.on("shutdown", (type, extension) => {
if (pageActionMap.has(extension)) {
pageActionMap.get(extension).shutdown();
pageActionMap.delete(extension);
}
});
/* eslint-enable mozilla/balanced-listeners */
extensions.registerSchemaAPI("pageAction", "addon_parent", context => {
let {extension} = context;
return {
pageAction: {
onClicked: new SingletonEventManager(context, "pageAction.onClicked", fire => {
let listener = (event) => {
fire();
};
pageActionMap.get(extension).on("click", listener);
return () => {
pageActionMap.get(extension).off("click", listener);
};
}).api(),
show(tabId) {
return pageActionMap.get(extension)
.show(tabId, context)
.then(() => {});
},
hide(tabId) {
pageActionMap.get(extension).hide(tabId);
return Promise.resolve();
},
setPopup(details) {
// TODO: Use the Tabs API to get the tab from details.tabId.
let tab = null;
let url = details.popup && context.uri.resolve(details.popup);
pageActionMap.get(extension).setPopup(tab, url);
},
getPopup(details) {
// TODO: Use the Tabs API to get the tab from details.tabId.
let tab = null;
let popup = pageActionMap.get(extension).getPopup(tab);
return Promise.resolve(popup);
},
},
};
});