Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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/. */
/* import-globals-from common.js */
/* import-globals-from permissions.js */
// Configuration vars
let homeURL = "https://webxr.today/";
// Bug 1586294 - Localize the privacy policy URL (Services.urlFormatter?)
let reportIssueURL = "https://mzl.la/fxr";
let licenseURL =
let browser = null;
// Keep track of the current Permissions request to only allow one outstanding
// request/prompt at a time.
let currentPermissionRequest = null;
// And, keep a queue of pending Permissions requests to resolve when the
// current request finishes
let pendingPermissionRequests = [];
// The following variable map to UI elements whose behavior changes depending
// on some state from the browser control
let urlInput = null;
let secureIcon = null;
let backButton = null;
let forwardButton = null;
let refreshButton = null;
let stopButton = null;
const { PrivateBrowsingUtils } = ChromeUtils.importESModule(
);
const { AppConstants } = ChromeUtils.importESModule(
);
const { XPCOMUtils } = ChromeUtils.importESModule(
);
// Note: FxR UI uses a fork of browser-fullScreenAndPointerLock.js which removes
// the dependencies on browser.js.
// Bug 1587946 - Rationalize the fork of browser-fullScreenAndPointerLock.js
XPCOMUtils.defineLazyScriptGetter(
this,
"FullScreen",
);
ChromeUtils.defineLazyGetter(this, "gSystemPrincipal", () =>
Services.scriptSecurityManager.getSystemPrincipal()
);
window.addEventListener(
"DOMContentLoaded",
() => {
urlInput = document.getElementById("eUrlInput");
secureIcon = document.getElementById("eUrlSecure");
backButton = document.getElementById("eBack");
forwardButton = document.getElementById("eForward");
refreshButton = document.getElementById("eRefresh");
stopButton = document.getElementById("eStop");
setupBrowser();
setupNavButtons();
setupUrlBar();
},
{ once: true }
);
// Create XUL browser object
function setupBrowser() {
// Note: createXULElement is undefined when this page is not loaded
// via chrome protocol
if (document.createXULElement) {
browser = document.createXULElement("browser");
browser.setAttribute("type", "content");
browser.setAttribute("remote", "true");
browser.classList.add("browser_instance");
document.getElementById("eBrowserContainer").appendChild(browser);
browser.loadUrlWithSystemPrincipal = function (url) {
this.loadURI(url, { triggeringPrincipal: gSystemPrincipal });
};
// Expose this function for Permissions to be used on this browser element
// in other parts of the frontend
browser.fxrPermissionPrompt = permissionPrompt;
urlInput.value = homeURL;
browser.loadUrlWithSystemPrincipal(homeURL);
browser.addProgressListener(
{
QueryInterface: ChromeUtils.generateQI([
"nsIWebProgressListener",
"nsISupportsWeakReference",
]),
onLocationChange() {
// When URL changes, update the URL in the URL bar and update
// whether the back/forward buttons are enabled.
urlInput.value = browser.currentURI.spec;
backButton.disabled = !browser.canGoBack;
forwardButton.disabled = !browser.canGoForward;
},
onStateChange(aWebProgress, aRequest, aStateFlags) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
// Network requests are complete. Disable (hide) the stop button
// and enable (show) the refresh button
refreshButton.disabled = false;
stopButton.disabled = true;
} else {
// Network requests are outstanding. Disable (hide) the refresh
// button and enable (show) the stop button
refreshButton.disabled = true;
stopButton.disabled = false;
}
},
onSecurityChange(aWebProgress, aRequest, aState) {
// Update the Secure Icon when the security status of the
// content changes
if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE) {
secureIcon.style.visibility = "visible";
} else {
secureIcon.style.visibility = "hidden";
}
},
},
Ci.nsIWebProgress.NOTIFY_LOCATION |
Ci.nsIWebProgress.NOTIFY_SECURITY |
Ci.nsIWebProgress.NOTIFY_STATE_REQUEST
);
FullScreen.init();
// Send this notification to start and allow background scripts for
// WebExtensions, since this FxR UI doesn't participate in typical
// startup activities
Services.obs.notifyObservers(window, "extensions-late-startup");
}
}
function setupNavButtons() {
let aryNavButtons = [
"eBack",
"eForward",
"eRefresh",
"eStop",
"eHome",
"ePrefs",
];
function navButtonHandler() {
if (!this.disabled) {
switch (this.id) {
case "eBack":
browser.goBack();
break;
case "eForward":
browser.goForward();
break;
case "eRefresh":
browser.reload();
break;
case "eStop":
browser.stop();
break;
case "eHome":
browser.loadUrlWithSystemPrincipal(homeURL);
break;
case "ePrefs":
openSettings();
break;
}
}
}
for (let btnName of aryNavButtons) {
let elem = document.getElementById(btnName);
elem.addEventListener("click", navButtonHandler);
}
}
function setupUrlBar() {
// Navigate to new value when the user presses "Enter"
urlInput.addEventListener("keypress", async function (e) {
if (e.key == "Enter") {
// Use the URL Fixup Service in case the user wants to search instead
// of directly navigating to a location.
await Services.search.init();
let valueToFixUp = urlInput.value;
let flags =
Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
flags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
}
let { preferredURI } = Services.uriFixup.getFixupURIInfo(
valueToFixUp,
flags
);
browser.loadUrlWithSystemPrincipal(preferredURI.spec);
browser.focus();
}
});
// Upon focus, highlight the whole URL
urlInput.addEventListener("focus", function () {
urlInput.select();
});
}
//
// Code to manage Settings UI
//
function openSettings() {
let browserSettingsUI = document.createXULElement("browser");
browserSettingsUI.setAttribute("type", "chrome");
browserSettingsUI.classList.add("browser_settings");
showModalContainer(browserSettingsUI);
browserSettingsUI.loadURI("chrome://fxr/content/prefs.html", {
triggeringPrincipal: gSystemPrincipal,
});
}
function closeSettings() {
clearModalContainer();
}
function showPrivacyPolicy() {
closeSettings();
browser.loadUrlWithSystemPrincipal(privacyPolicyURL);
}
function showLicenseInfo() {
closeSettings();
browser.loadUrlWithSystemPrincipal(licenseURL);
}
function showReportIssue() {
closeSettings();
browser.loadUrlWithSystemPrincipal(reportIssueURL);
}
//
// Code to manage Permissions UI
//
function permissionPrompt(aRequest) {
let newPrompt;
if (aRequest instanceof Ci.nsIContentPermissionRequest) {
newPrompt = new FxrContentPrompt(aRequest, this, finishPrompt);
} else {
newPrompt = new FxrWebRTCPrompt(aRequest, this, finishPrompt);
}
if (currentPermissionRequest) {
// There is already an outstanding request running. Cache this new request
// to be prompted later
pendingPermissionRequests.push(newPrompt);
} else {
currentPermissionRequest = newPrompt;
currentPermissionRequest.showPrompt();
}
}
function finishPrompt() {
if (pendingPermissionRequests.length) {
// Prompt the next request
currentPermissionRequest = pendingPermissionRequests.shift();
currentPermissionRequest.showPrompt();
} else {
currentPermissionRequest = null;
}
}