summaryrefslogtreecommitdiffstats
path: root/browser/extensions/flyweb/bootstrap.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/extensions/flyweb/bootstrap.js')
-rw-r--r--browser/extensions/flyweb/bootstrap.js297
1 files changed, 297 insertions, 0 deletions
diff --git a/browser/extensions/flyweb/bootstrap.js b/browser/extensions/flyweb/bootstrap.js
new file mode 100644
index 000000000..089226519
--- /dev/null
+++ b/browser/extensions/flyweb/bootstrap.js
@@ -0,0 +1,297 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* 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/. */
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+ "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Console",
+ "resource://gre/modules/Console.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+ "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Integration",
+ "resource://gre/modules/Integration.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PermissionUI",
+ "resource:///modules/PermissionUI.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "gFlyWebBundle", function() {
+ const tns = {
+ "flyweb-button.label": "FlyWeb",
+ "flyweb-button.tooltiptext": "Discover nearby FlyWeb services",
+ "flyweb-items-empty": "There are no FlyWeb services currently nearby"
+ };
+ return {
+ GetStringFromName(name) {
+ return tns[name];
+ }
+ };
+});
+
+const FLYWEB_ENABLED_PREF = "dom.flyweb.enabled";
+
+function install(aData, aReason) {}
+
+function uninstall(aData, aReason) {}
+
+function startup(aData, aReason) {
+ // Observe pref changes and enable/disable as necessary.
+ Services.prefs.addObserver(FLYWEB_ENABLED_PREF, prefObserver, false);
+
+ // Only initialize if pref is enabled.
+ let enabled = Services.prefs.getBoolPref(FLYWEB_ENABLED_PREF);
+ if (enabled) {
+ FlyWebView.init();
+ }
+}
+
+function shutdown(aData, aReason) {
+ Services.prefs.removeObserver(FLYWEB_ENABLED_PREF, prefObserver);
+
+ let enabled = Services.prefs.getBoolPref(FLYWEB_ENABLED_PREF);
+ if (enabled) {
+ FlyWebView.uninit();
+ }
+}
+
+// use enabled pref as a way for tests (e.g. test_contextmenu.html) to disable
+// the addon when running.
+function prefObserver(aSubject, aTopic, aData) {
+ let enabled = Services.prefs.getBoolPref(FLYWEB_ENABLED_PREF);
+ if (enabled) {
+ FlyWebView.init();
+ } else {
+ FlyWebView.uninit();
+ }
+}
+
+let gDiscoveryManagerInstance;
+
+class DiscoveryManager {
+ constructor(aWindow) {
+ this._discoveryManager = new aWindow.FlyWebDiscoveryManager();
+ }
+
+ destroy() {
+ if (this._id) {
+ this.stop();
+ }
+
+ this._discoveryManager = null;
+ }
+
+ start(callback) {
+ if (!this._id) {
+ this._id = this._discoveryManager.startDiscovery(this);
+ }
+
+ this._callback = callback;
+ }
+
+ stop() {
+ this._discoveryManager.stopDiscovery(this._id);
+
+ this._id = null;
+ }
+
+ pairWith(serviceId, callback) {
+ this._discoveryManager.pairWithService(serviceId, {
+ pairingSucceeded(service) {
+ callback(service);
+ },
+
+ pairingFailed(error) {
+ console.error("FlyWeb failed to pair with service " + serviceId, error);
+ }
+ });
+ }
+
+ onDiscoveredServicesChanged(services) {
+ if (!this._id || !this._callback) {
+ return;
+ }
+
+ this._callback(services);
+ }
+}
+
+const FlyWebPermissionPromptIntegration = (base) => ({
+ __proto__: base,
+ createPermissionPrompt(type, request) {
+ if (type != "flyweb-publish-server") {
+ return super.createPermissionPrompt(...arguments);
+ }
+
+ return {
+ __proto__: PermissionUI.PermissionPromptForRequestPrototype,
+ get request() {
+ return request;
+ },
+ get permissionKey() {
+ return "flyweb-publish-server";
+ },
+ get popupOptions() {
+ return {
+ learnMoreURL: "https://flyweb.github.io",
+ popupIconURL: "chrome://flyweb/skin/icon-64.png",
+ };
+ },
+ get notificationID() {
+ return "flyweb-publish-server";
+ },
+ get anchorID() {
+ const kAnchorID = "flyweb-publish-server-notification-icon";
+ let chromeDoc = this.browser.ownerDocument;
+ let anchor = chromeDoc.getElementById(kAnchorID);
+ if (!anchor) {
+ let notificationPopupBox =
+ chromeDoc.getElementById("notification-popup-box");
+ let notificationIcon = chromeDoc.createElement("image");
+ notificationIcon.id = kAnchorID;
+ notificationIcon.setAttribute("src",
+ "chrome://flyweb/skin/icon-64.png");
+ notificationIcon.classList.add("notification-anchor-icon");
+ notificationIcon.setAttribute("role", "button");
+ notificationIcon.setAttribute("aria-label",
+ "View the publish-server request");
+ notificationIcon.style.filter =
+ "url('chrome://browser/skin/filters.svg#fill')";
+ notificationIcon.style.fill = "currentcolor";
+ notificationIcon.style.opacity = "0.4";
+ notificationPopupBox.appendChild(notificationIcon);
+ }
+
+ return kAnchorID;
+ },
+ get message() {
+ return "Would you like to let this site start a server accessible " +
+ "to nearby devices and people?";
+ },
+ get promptActions() {
+ return [{
+ label: "Allow Server",
+ accessKey: "A",
+ action: Ci.nsIPermissionManager.ALLOW_ACTION,
+ expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
+ }, {
+ label: "Block Server",
+ accessKey: "B",
+ action: Ci.nsIPermissionManager.DENY_ACTION,
+ expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
+ }];
+ },
+ };
+ },
+});
+
+let FlyWebView = {
+ init() {
+ // Create widget and add it to the menu panel.
+ CustomizableUI.createWidget({
+ id: "flyweb-button",
+ type: "view",
+ viewId: "flyweb-panel",
+ label: gFlyWebBundle.GetStringFromName("flyweb-button.label"),
+ tooltiptext: gFlyWebBundle.GetStringFromName("flyweb-button.tooltiptext"),
+
+ onBeforeCreated(aDocument) {
+ let panel = aDocument.createElement("panelview");
+ panel.id = "flyweb-panel";
+ panel.setAttribute("class", "PanelUI-subView");
+ panel.setAttribute("flex", "1");
+
+ let label = aDocument.createElement("label");
+ label.setAttribute("class", "panel-subview-header");
+ label.setAttribute("value", gFlyWebBundle.GetStringFromName("flyweb-button.label"));
+
+ let empty = aDocument.createElement("description");
+ empty.id = "flyweb-items-empty";
+ empty.setAttribute("mousethrough", "always");
+ empty.textContent = gFlyWebBundle.GetStringFromName("flyweb-items-empty");
+
+ let items = aDocument.createElement("vbox");
+ items.id = "flyweb-items";
+ items.setAttribute("class", "panel-subview-body");
+
+ panel.appendChild(label);
+ panel.appendChild(empty);
+ panel.appendChild(items);
+
+ panel.addEventListener("command", this);
+
+ aDocument.getElementById("PanelUI-multiView").appendChild(panel);
+
+ this._sheetURI = Services.io.newURI("chrome://flyweb/skin/flyweb.css", null, null);
+ aDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIDOMWindowUtils).loadSheet(this._sheetURI, 1);
+ },
+
+ onDestroyed(aDocument) {
+ aDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIDOMWindowUtils).removeSheet(this._sheetURI, 1);
+ },
+
+ onViewShowing(aEvent) {
+ let doc = aEvent.target.ownerDocument;
+
+ let items = doc.getElementById("flyweb-items");
+ let empty = doc.getElementById("flyweb-items-empty");
+
+ if (!gDiscoveryManagerInstance) {
+ gDiscoveryManagerInstance = new DiscoveryManager(doc.defaultView);
+ }
+
+ gDiscoveryManagerInstance.start((services) => {
+ while (items.firstChild) {
+ items.firstChild.remove();
+ }
+
+ let fragment = doc.createDocumentFragment();
+
+ for (let service of services) {
+ let button = doc.createElement("toolbarbutton");
+ button.setAttribute("class", "subviewbutton cui-withicon");
+ button.setAttribute("label", service.displayName);
+ button.setAttribute("data-service-id", service.serviceId);
+ fragment.appendChild(button);
+ }
+
+ items.appendChild(fragment);
+
+ empty.hidden = services.length > 0;
+ });
+ },
+
+ onViewHiding(aEvent) {
+ gDiscoveryManagerInstance.stop();
+ },
+
+ handleEvent(aEvent) {
+ if (aEvent.type === "command") {
+ let serviceId = aEvent.target.getAttribute("data-service-id");
+ gDiscoveryManagerInstance.pairWith(serviceId, (service) => {
+ aEvent.view.openUILinkIn(service.uiUrl, "tab");
+ });
+ }
+ }
+ });
+
+ Integration.contentPermission
+ .register(FlyWebPermissionPromptIntegration);
+ },
+
+ uninit() {
+ CustomizableUI.destroyWidget("flyweb-button");
+
+ if (gDiscoveryManagerInstance) {
+ gDiscoveryManagerInstance.destroy();
+ gDiscoveryManagerInstance = null;
+ }
+
+ Integration.contentPermission
+ .unregister(FlyWebPermissionPromptIntegration);
+ }
+};