diff options
Diffstat (limited to 'browser/extensions/flyweb/bootstrap.js')
-rw-r--r-- | browser/extensions/flyweb/bootstrap.js | 297 |
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); + } +}; |