fune/browser/extensions/presentation/content/PresentationDevicePrompt.jsm
Masatoshi Kimura f143125cc2 Bug 1326520 - Rename nsIURI.path to pathQueryRef. r=valentin.gosu
MozReview-Commit-ID: DqJdTGopR9G

--HG--
extra : rebase_source : e8c9eb03468c075b79013b6e0bd8b367229c24cd
2017-07-29 20:50:21 +09:00

253 lines
8.7 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"];
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.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.
XPCOMUtils.defineLazyModuleGetter(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;
},
};