/* -*- 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 privacyPolicyURL = "https://www.mozilla.org/en-US/privacy/firefox/"; let reportIssueURL = "https://mzl.la/fxr"; let licenseURL = "https://mixedreality.mozilla.org/FirefoxRealityPC/license.html"; // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser 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( "resource://gre/modules/PrivateBrowsingUtils.sys.mjs" ); const { AppConstants } = ChromeUtils.importESModule( "resource://gre/modules/AppConstants.sys.mjs" ); const { XPCOMUtils } = ChromeUtils.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs" ); // 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", "chrome://fxr/content/fxr-fullScreen.js" ); XPCOMUtils.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(aWebProgress, aRequest, aLocation, aFlags) { // 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, aStatus) { 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(e) { 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; } }