This patch was autogenerated by my decomponents.py
It covers almost every file with the extension js, jsm, html, py,
xhtml, or xul.
It removes blank lines after removed lines, when the removed lines are
preceded by either blank lines or the start of a new block. The "start
of a new block" is defined fairly hackily: either the line starts with
//, ends with */, ends with {, <![CDATA[, """ or '''. The first two
cover comments, the third one covers JS, the fourth covers JS embedded
in XUL, and the final two cover JS embedded in Python. This also
applies if the removed line was the first line of the file.
It covers the pattern matching cases like "var {classes: Cc,
interfaces: Ci, utils: Cu, results: Cr} = Components;". It'll remove
the entire thing if they are all either Ci, Cr, Cc or Cu, or it will
remove the appropriate ones and leave the residue behind. If there's
only one behind, then it will turn it into a normal, non-pattern
matching variable definition. (For instance, "const { classes: Cc,
Constructor: CC, interfaces: Ci, utils: Cu } = Components" becomes
"const CC = Components.Constructor".)
MozReview-Commit-ID: DeSHcClQ7cG
252 lines
8.6 KiB
JavaScript
252 lines
8.6 KiB
JavaScript
/* -*- 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/. */
|
|
|
|
/*
|
|
* This is the implementation of nsIPresentationDevicePrompt XPCOM.
|
|
* It will be registered into a XPCOM component by Presentation.jsm.
|
|
*
|
|
* This component will prompt a device selection UI for users to choose which
|
|
* devices they want to connect, when PresentationRequest is started.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
var EXPORTED_SYMBOLS = ["PresentationDevicePrompt"];
|
|
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
// An string bundle for localization.
|
|
XPCOMUtils.defineLazyGetter(this, "Strings", function() {
|
|
return Services.strings.createBundle("chrome://presentation/locale/presentation.properties");
|
|
});
|
|
// To generate a device selection prompt.
|
|
ChromeUtils.defineModuleGetter(this, "PermissionUI",
|
|
"resource:///modules/PermissionUI.jsm");
|
|
/*
|
|
* Utils
|
|
*/
|
|
function log(aMsg) {
|
|
// Prefix is useful to grep log.
|
|
// dump("@ PresentationDevicePrompt: " + aMsg + "\n");
|
|
}
|
|
|
|
function GetString(aName) {
|
|
return Strings.GetStringFromName(aName);
|
|
}
|
|
|
|
/*
|
|
* Device Selection UI
|
|
*/
|
|
const kNotificationId = "presentation-device-selection";
|
|
const kNotificationPopupIcon = "chrome://presentation-shared/skin/link.svg";
|
|
|
|
// There is no dependancy between kNotificationId and kNotificationAnchorId,
|
|
// so it's NOT necessary to name them by same prefix
|
|
// (e.g., presentation-device-selection-notification-icon).
|
|
const kNotificationAnchorId = "presentation-device-notification-icon";
|
|
const kNotificationAnchorIcon = "chrome://presentation-shared/skin/link.svg";
|
|
|
|
// This will insert our own popupnotification content with the device list
|
|
// into the displayed popupnotification element.
|
|
// PopupNotifications.jsm will automatically generate a popupnotification
|
|
// element whose id is <notification id> + "-notification" and show it,
|
|
// so kPopupNotificationId must be kNotificationId + "-notification".
|
|
// Read more detail in PopupNotifications._refreshPanel.
|
|
const kPopupNotificationId = kNotificationId + "-notification";
|
|
|
|
function PresentationPermissionPrompt(aRequest, aDevices) {
|
|
this.request = aRequest;
|
|
this._isResponded = false;
|
|
this._devices = aDevices;
|
|
}
|
|
|
|
PresentationPermissionPrompt.prototype = {
|
|
__proto__: PermissionUI.PermissionPromptForRequestPrototype,
|
|
// PUBLIC APIs
|
|
get browser() {
|
|
return this.request.chromeEventHandler;
|
|
},
|
|
get principal() {
|
|
return this.request.principal;
|
|
},
|
|
get popupOptions() {
|
|
return {
|
|
removeOnDismissal: true,
|
|
popupIconURL: kNotificationPopupIcon, // Icon shown on prompt content
|
|
eventCallback: (aTopic, aNewBrowser) => {
|
|
log("eventCallback: " + aTopic);
|
|
let handler = {
|
|
// dismissed: () => { // Won't be fired if removeOnDismissal is true.
|
|
// log("Dismissed by user. Cancel the request.");
|
|
// },
|
|
removed: () => {
|
|
log("Prompt is removed.");
|
|
if (!this._isResponded) {
|
|
log("Dismissed by user. Cancel the request.");
|
|
this.request.cancel(Cr.NS_ERROR_NOT_AVAILABLE);
|
|
}
|
|
},
|
|
showing: () => {
|
|
log("Prompt is showing.");
|
|
// We cannot insert the device list at "showing" phase because
|
|
// the popupnotification content whose id is kPopupNotificationId
|
|
// is not generated yet.
|
|
},
|
|
shown: () => {
|
|
log("Prompt is shown.");
|
|
// Insert device selection list into popupnotification element.
|
|
this._createPopupContent();
|
|
},
|
|
};
|
|
|
|
// Call the handler for Notification events.
|
|
handler[aTopic]();
|
|
},
|
|
};
|
|
},
|
|
get notificationID() {
|
|
return kNotificationId;
|
|
},
|
|
get anchorID() {
|
|
let chromeDoc = this.browser.ownerDocument;
|
|
let anchor = chromeDoc.getElementById(kNotificationAnchorId);
|
|
if (!anchor) {
|
|
let notificationPopupBox =
|
|
chromeDoc.getElementById("notification-popup-box");
|
|
// Icon shown on URL bar
|
|
let notificationIcon = chromeDoc.createElement("image");
|
|
notificationIcon.id = kNotificationAnchorId;
|
|
notificationIcon.setAttribute("src", kNotificationAnchorIcon);
|
|
notificationIcon.classList.add("notification-anchor-icon");
|
|
notificationIcon.setAttribute("role", "button");
|
|
notificationIcon.setAttribute("tooltiptext",
|
|
GetString("presentation.urlbar.tooltiptext"));
|
|
notificationIcon.style.setProperty("-moz-context-properties", "fill");
|
|
notificationIcon.style.fill = "currentcolor";
|
|
notificationIcon.style.opacity = "0.4";
|
|
notificationPopupBox.appendChild(notificationIcon);
|
|
}
|
|
|
|
return kNotificationAnchorId;
|
|
},
|
|
get message() {
|
|
return GetString("presentation.message", this._domainName);
|
|
},
|
|
get promptActions() {
|
|
return [{
|
|
label: GetString("presentation.deviceprompt.select.label"),
|
|
accessKey: GetString("presentation.deviceprompt.select.accessKey"),
|
|
callback: () => {
|
|
log("Select");
|
|
this._isResponded = true;
|
|
if (!this._listbox || !this._devices.length) {
|
|
log("No device can be selected!");
|
|
this.request.cancel(Cr.NS_ERROR_NOT_AVAILABLE);
|
|
return;
|
|
}
|
|
let device = this._devices[this._listbox.selectedIndex];
|
|
this.request.select(device);
|
|
log("device: " + device.name + "(" + device.id + ") is selected!");
|
|
},
|
|
}, {
|
|
label: GetString("presentation.deviceprompt.cancel.label"),
|
|
accessKey: GetString("presentation.deviceprompt.cancel.accessKey"),
|
|
callback: () => {
|
|
log("Cancel selection.");
|
|
this._isResponded = true;
|
|
this.request.cancel(Cr.NS_ERROR_NOT_AVAILABLE);
|
|
},
|
|
dismiss: true,
|
|
}];
|
|
},
|
|
// PRIVATE APIs
|
|
get _domainName() {
|
|
if (this.principal.URI instanceof Ci.nsIFileURL) {
|
|
return this.principal.URI.pathQueryRef.split("/")[1];
|
|
}
|
|
return this.principal.URI.hostPort;
|
|
},
|
|
_createPopupContent() {
|
|
log("_createPopupContent");
|
|
|
|
if (!this._devices.length) {
|
|
log("No available devices can be listed!");
|
|
return;
|
|
}
|
|
|
|
let chromeDoc = this.browser.ownerDocument;
|
|
|
|
let popupnotification = chromeDoc.getElementById(kPopupNotificationId);
|
|
if (!popupnotification) {
|
|
log("No available popupnotification element to be inserted!");
|
|
return;
|
|
}
|
|
|
|
let popupnotificationcontent =
|
|
chromeDoc.createElement("popupnotificationcontent");
|
|
|
|
this._listbox = chromeDoc.createElement("richlistbox");
|
|
this._listbox.setAttribute("flex", "1");
|
|
this._devices.forEach((device) => {
|
|
let listitem = chromeDoc.createElement("richlistitem");
|
|
let label = chromeDoc.createElement("label");
|
|
label.setAttribute("value", device.name);
|
|
listitem.appendChild(label);
|
|
this._listbox.appendChild(listitem);
|
|
});
|
|
|
|
popupnotificationcontent.appendChild(this._listbox);
|
|
popupnotification.appendChild(popupnotificationcontent);
|
|
},
|
|
};
|
|
|
|
|
|
/*
|
|
* nsIPresentationDevicePrompt
|
|
*/
|
|
// For XPCOM registration
|
|
const PRESENTATIONDEVICEPROMPT_CONTRACTID = "@mozilla.org/presentation-device/prompt;1";
|
|
const PRESENTATIONDEVICEPROMPT_CID = Components.ID("{388bd149-c919-4a43-b646-d7ec57877689}");
|
|
|
|
function PresentationDevicePrompt() {}
|
|
|
|
PresentationDevicePrompt.prototype = {
|
|
// properties required for XPCOM registration:
|
|
classID: PRESENTATIONDEVICEPROMPT_CID,
|
|
classDescription: "Presentation API Device Prompt",
|
|
contractID: PRESENTATIONDEVICEPROMPT_CONTRACTID,
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt]),
|
|
|
|
// This will be fired when window.PresentationRequest(URL).start() is called.
|
|
promptDeviceSelection(aRequest) {
|
|
log("promptDeviceSelection");
|
|
|
|
// Cancel request if no available device.
|
|
let devices = this._loadDevices();
|
|
if (!devices.length) {
|
|
log("No available device.");
|
|
aRequest.cancel(Cr.NS_ERROR_NOT_AVAILABLE);
|
|
return;
|
|
}
|
|
|
|
// Show the prompt to users.
|
|
let promptUI = new PresentationPermissionPrompt(aRequest, devices);
|
|
promptUI.prompt();
|
|
},
|
|
_loadDevices() {
|
|
let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"]
|
|
.getService(Ci.nsIPresentationDeviceManager);
|
|
let devices = deviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray);
|
|
let list = [];
|
|
for (let i = 0; i < devices.length; i++) {
|
|
let device = devices.queryElementAt(i, Ci.nsIPresentationDevice);
|
|
list.push(device);
|
|
}
|
|
|
|
return list;
|
|
},
|
|
};
|