Bug 1685801: Part 6 - Move some front-end code from BrowserUtils to a separate module. r=mccr8

Differential Revision: https://phabricator.services.mozilla.com/D101486
This commit is contained in:
Kris Maglione 2021-01-28 05:25:03 +00:00
Родитель 16d8777f81
Коммит 69c936d646
23 изменённых файлов: 253 добавлений и 240 удалений

Просмотреть файл

@ -14,8 +14,8 @@ const { XPCOMUtils } = ChromeUtils.import(
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
"BrowserUIUtils",
"resource:///modules/BrowserUIUtils.jsm"
);
XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
@ -73,7 +73,7 @@ class EncryptedMediaParent extends JSWindowActorParent {
let link = document.createXULElement("label", { is: "text-link" });
link.setAttribute("href", baseURL + "drm-content");
link.textContent = text;
return BrowserUtils.getLocalizedFragment(document, mainMessage, link);
return BrowserUIUtils.getLocalizedFragment(document, mainMessage, link);
}
getMessageWithBrandName(aNotificationId) {

Просмотреть файл

@ -631,7 +631,7 @@ var gXPInstallObserver = {
);
let b = doc.createElementNS("http://www.w3.org/1999/xhtml", "b");
b.textContent = options.name;
let fragment = BrowserUtils.getLocalizedFragment(doc, text, b);
let fragment = BrowserUIUtils.getLocalizedFragment(doc, text, b);
message.appendChild(fragment);
} else {
message.textContent = gNavigatorBundle.getString(

Просмотреть файл

@ -2188,7 +2188,7 @@ var BookmarkingUI = {
) {
let isBookmarked = this._itemGuids.size > 0;
if (!isBookmarked) {
BrowserUtils.setToolbarButtonHeightProperty(this.star);
BrowserUIUtils.setToolbarButtonHeightProperty(this.star);
// there are no other animations on this element, so we can simply
// listen for animationend with the "once" option to clean up
let animatableBox = document.getElementById(

Просмотреть файл

@ -23,6 +23,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm",
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
BrowserTelemetryUtils: "resource://gre/modules/BrowserTelemetryUtils.jsm",
BrowserUIUtils: "resource:///modules/BrowserUIUtils.jsm",
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
CFRPageActions: "resource://activity-stream/lib/CFRPageActions.jsm",
@ -4938,7 +4939,7 @@ var XULBrowserWindow = {
);
if (UrlbarPrefs.get("trimURLs")) {
url = BrowserUtils.trimURL(url);
url = BrowserUIUtils.trimURL(url);
}
}
@ -5127,7 +5128,7 @@ var XULBrowserWindow = {
aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT;
if (
(location == "about:blank" &&
BrowserUtils.checkEmptyPageOrigin(gBrowser.selectedBrowser)) ||
BrowserUIUtils.checkEmptyPageOrigin(gBrowser.selectedBrowser)) ||
location == ""
) {
// Second condition is for new tabs, otherwise
@ -5590,7 +5591,7 @@ var CombinedStopReload = {
this._cancelTransition();
if (shouldAnimate) {
BrowserUtils.setToolbarButtonHeightProperty(this.stopReloadContainer);
BrowserUIUtils.setToolbarButtonHeightProperty(this.stopReloadContainer);
this.stopReloadContainer.setAttribute("animate", "true");
} else {
this.stopReloadContainer.removeAttribute("animate");
@ -5613,7 +5614,7 @@ var CombinedStopReload = {
this.stopReloadContainer.closest("#nav-bar-customization-target");
if (shouldAnimate) {
BrowserUtils.setToolbarButtonHeightProperty(this.stopReloadContainer);
BrowserUIUtils.setToolbarButtonHeightProperty(this.stopReloadContainer);
this.stopReloadContainer.setAttribute("animate", "true");
} else {
this.stopReloadContainer.removeAttribute("animate");

Просмотреть файл

@ -228,7 +228,7 @@
return false;
}
if (!BrowserUtils.checkEmptyPageOrigin(browser)) {
if (!BrowserUIUtils.checkEmptyPageOrigin(browser)) {
return false;
}

Просмотреть файл

@ -31,7 +31,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.jsm",
BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm",
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
BrowserUIUtils: "resource:///modules/BrowserUIUtils.jsm",
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
ContextualIdentityService:
"resource://gre/modules/ContextualIdentityService.jsm",
@ -3950,7 +3950,7 @@ BrowserGlue.prototype = {
// same way that the url bar would.
body = URIs[0].uri.replace(/([?#]).*$/, "$1");
let wasTruncated = body.length < URIs[0].uri.length;
body = BrowserUtils.trimURL(body);
body = BrowserUIUtils.trimURL(body);
if (wasTruncated) {
body = bundle.formatStringFromName(
"singleTabArrivingWithTruncatedURL.body",

Просмотреть файл

@ -52,8 +52,8 @@ ChromeUtils.defineModuleGetter(
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
"BrowserUIUtils",
"resource:///modules/BrowserUIUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
@ -791,7 +791,7 @@ CustomizeMode.prototype = {
}
if (!this.window.gReduceMotion) {
let overflowButton = this.$("nav-bar-overflow-button");
BrowserUtils.setToolbarButtonHeightProperty(overflowButton).then(() => {
BrowserUIUtils.setToolbarButtonHeightProperty(overflowButton).then(() => {
overflowButton.setAttribute("animate", "true");
overflowButton.addEventListener("animationend", function onAnimationEnd(
event

Просмотреть файл

@ -34,8 +34,8 @@ ChromeUtils.defineModuleGetter(
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
"BrowserUIUtils",
"resource:///modules/BrowserUIUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
@ -367,7 +367,7 @@ class ExtensionControlledPopup {
);
} else {
description.appendChild(
BrowserUtils.getLocalizedFragment(doc, message, addonDetails)
BrowserUIUtils.getLocalizedFragment(doc, message, addonDetails)
);
}

Просмотреть файл

@ -8,8 +8,8 @@
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
"BrowserUIUtils",
"resource:///modules/BrowserUIUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
@ -64,7 +64,7 @@ XPCOMUtils.defineLazyGetter(this, "tabHidePopup", () => {
getLocalizedDescription: (doc, message, addonDetails) => {
let image = doc.createXULElement("image");
image.setAttribute("class", "extension-controlled-icon alltabs-icon");
return BrowserUtils.getLocalizedFragment(
return BrowserUIUtils.getLocalizedFragment(
doc,
message,
addonDetails,

Просмотреть файл

@ -10,8 +10,8 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
"BrowserUIUtils",
"resource:///modules/BrowserUIUtils.jsm"
);
var Pocket = {
@ -46,7 +46,7 @@ var Pocket = {
let libraryButton = document.getElementById("library-button");
if (libraryButton) {
BrowserUtils.setToolbarButtonHeightProperty(libraryButton);
BrowserUIUtils.setToolbarButtonHeightProperty(libraryButton);
}
let urlToSave = Pocket._urlToSave;

Просмотреть файл

@ -11,8 +11,8 @@ const { XPCOMUtils } = ChromeUtils.import(
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
"BrowserUIUtils",
"resource:///modules/BrowserUIUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
@ -76,7 +76,7 @@ var PocketPageAction = {
return;
}
BrowserUtils.setToolbarButtonHeightProperty(urlbarNode);
BrowserUIUtils.setToolbarButtonHeightProperty(urlbarNode);
PocketPageAction.urlbarNode = urlbarNode;
PocketPageAction.urlbarNode.setAttribute("open", "true");

Просмотреть файл

@ -396,7 +396,7 @@ function test() {
);
is(
gURLBar.value,
BrowserUtils.trimURL("http://example.com/"),
BrowserUIUtils.trimURL("http://example.com/"),
"Address bar's value set after loading URI"
);
runNextTest();

Просмотреть файл

@ -13,6 +13,7 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
AppConstants: "resource://gre/modules/AppConstants.jsm",
BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm",
BrowserUIUtils: "resource:///modules/BrowserUIUtils.jsm",
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm",
ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
@ -330,7 +331,7 @@ class UrlbarInput {
// only if there's no opener (bug 370555).
if (
this.window.isInitialPage(uri) &&
BrowserUtils.checkEmptyPageOrigin(
BrowserUIUtils.checkEmptyPageOrigin(
this.window.gBrowser.selectedBrowser,
uri
)
@ -349,7 +350,7 @@ class UrlbarInput {
!this.window.isBlankPageURL(uri.spec) || uri.schemeIs("moz-extension");
} else if (
this.window.isInitialPage(value) &&
BrowserUtils.checkEmptyPageOrigin(this.window.gBrowser.selectedBrowser)
BrowserUIUtils.checkEmptyPageOrigin(this.window.gBrowser.selectedBrowser)
) {
value = "";
valid = true;
@ -1076,10 +1077,10 @@ class UrlbarInput {
if (
result.type == UrlbarUtils.RESULT_TYPE.URL &&
UrlbarPrefs.get("trimURLs") &&
result.payload.url.startsWith(BrowserUtils.trimURLProtocol)
result.payload.url.startsWith(BrowserUIUtils.trimURLProtocol)
) {
let fixupInfo = this._getURIFixupInfo(
BrowserUtils.trimURL(result.payload.url)
BrowserUIUtils.trimURL(result.payload.url)
);
if (fixupInfo?.keywordAsSent) {
allowTrim = false;
@ -2089,12 +2090,12 @@ class UrlbarInput {
// url. First check for a trimmed value.
if (
!selectedVal.startsWith(BrowserUtils.trimURLProtocol) &&
!selectedVal.startsWith(BrowserUIUtils.trimURLProtocol) &&
// Note _trimValue may also trim a trailing slash, thus we can't just do
// a straight string compare to tell if the protocol was trimmed.
!displaySpec.startsWith(this._trimValue(displaySpec))
) {
selectedVal = BrowserUtils.trimURLProtocol + selectedVal;
selectedVal = BrowserUIUtils.trimURLProtocol + selectedVal;
}
return selectedVal;
@ -2176,7 +2177,7 @@ class UrlbarInput {
* The trimmed string
*/
_trimValue(val) {
return UrlbarPrefs.get("trimURLs") ? BrowserUtils.trimURL(val) : val;
return UrlbarPrefs.get("trimURLs") ? BrowserUIUtils.trimURL(val) : val;
}
/**

Просмотреть файл

@ -18,7 +18,7 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
BrowserUIUtils: "resource:///modules/BrowserUIUtils.jsm",
JsonSchemaValidator:
"resource://gre/modules/components-utils/JsonSchemaValidator.jsm",
Services: "resource://gre/modules/Services.jsm",
@ -226,7 +226,7 @@ class UrlbarResult {
payloadInfo.displayUrl = [...payloadInfo.url];
let url = payloadInfo.displayUrl[0];
if (url && UrlbarPrefs.get("trimURLs")) {
url = BrowserUtils.removeSingleTrailingSlashFromURL(url);
url = BrowserUIUtils.removeSingleTrailingSlashFromURL(url);
if (url.startsWith("https://")) {
url = url.substring(8);
if (url.startsWith("www.")) {

Просмотреть файл

@ -13,7 +13,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
AddonTestUtils: "resource://testing-common/AddonTestUtils.jsm",
AppConstants: "resource://gre/modules/AppConstants.jsm",
BrowserTestUtils: "resource://testing-common/BrowserTestUtils.jsm",
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
BrowserUIUtils: "resource:///modules/BrowserUIUtils.jsm",
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
FormHistoryTestUtils: "resource://testing-common/FormHistoryTestUtils.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
@ -113,7 +113,7 @@ var UrlbarTestUtils = {
window.gURLBar.inputField.focus();
// Using the value setter in some cases may trim and fetch unexpected
// results, then pick an alternate path.
if (UrlbarPrefs.get("trimURLs") && value != BrowserUtils.trimURL(value)) {
if (UrlbarPrefs.get("trimURLs") && value != BrowserUIUtils.trimURL(value)) {
window.gURLBar.inputField.value = value;
fireInputEvent = true;
} else {

Просмотреть файл

@ -102,7 +102,7 @@ function testVal(originalValue, targetValue) {
gURLBar.value = originalValue;
gURLBar.valueIsTyped = false;
let trimmedValue = UrlbarPrefs.get("trimURLs")
? BrowserUtils.trimURL(originalValue)
? BrowserUIUtils.trimURL(originalValue)
: originalValue;
Assert.equal(gURLBar.value, trimmedValue, "url bar value set");
// Now focus the urlbar and check the inputField value is properly set.

Просмотреть файл

@ -5,7 +5,7 @@
// modifies the selected url, or just closes the results pane, we do a visit
// rather than searching for the trimmed string.
const url = BrowserUtils.trimURLProtocol + "invalid.somehost/mytest";
const url = BrowserUIUtils.trimURLProtocol + "invalid.somehost/mytest";
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({

Просмотреть файл

@ -16,14 +16,14 @@ add_task(async function() {
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
is(
gURLBar.value,
BrowserUtils.trimURL(goodURL),
BrowserUIUtils.trimURL(goodURL),
"location bar reflects loaded page"
);
await typeAndSubmitAndStop(badURL);
is(
gURLBar.value,
BrowserUtils.trimURL(goodURL),
BrowserUIUtils.trimURL(goodURL),
"location bar reflects loaded page after stop()"
);
gBrowser.removeCurrentTab();
@ -34,7 +34,7 @@ add_task(async function() {
await typeAndSubmitAndStop(badURL);
is(
gURLBar.value,
BrowserUtils.trimURL(badURL),
BrowserUIUtils.trimURL(badURL),
"location bar reflects stopped page in an empty tab"
);
gBrowser.removeCurrentTab();

Просмотреть файл

@ -51,7 +51,7 @@ add_task(async function() {
BrowserTestUtils.loadURI(partialURLTab.linkedBrowser, testURL);
await Promise.all([loaded1, loaded2, loaded3]);
testURL = BrowserUtils.trimURL(testURL);
testURL = BrowserUIUtils.trimURL(testURL);
testPartialURL = testURL.substr(0, testURL.length - charsToDelete);
function cleanUp() {

Просмотреть файл

@ -0,0 +1,204 @@
/* -*- mode: js; 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/. */
"use strict";
var EXPORTED_SYMBOLS = ["BrowserUIUtils"];
var BrowserUIUtils = {
/**
* Check whether a page can be considered as 'empty', that its URI
* reflects its origin, and that if it's loaded in a tab, that tab
* could be considered 'empty' (e.g. like the result of opening
* a 'blank' new tab).
*
* We have to do more than just check the URI, because especially
* for things like about:blank, it is possible that the opener or
* some other page has control over the contents of the page.
*
* @param {Browser} browser
* The browser whose page we're checking.
* @param {nsIURI} [uri]
* The URI against which we're checking (the browser's currentURI
* if omitted).
*
* @return {boolean} false if the page was opened by or is controlled by
* arbitrary web content, unless that content corresponds with the URI.
* true if the page is blank and controlled by a principal matching
* that URI (or the system principal if the principal has no URI)
*/
checkEmptyPageOrigin(browser, uri = browser.currentURI) {
// If another page opened this page with e.g. window.open, this page might
// be controlled by its opener.
if (browser.hasContentOpener) {
return false;
}
let contentPrincipal = browser.contentPrincipal;
// Not all principals have URIs...
// There are two special-cases involving about:blank. One is where
// the user has manually loaded it and it got created with a null
// principal. The other involves the case where we load
// some other empty page in a browser and the current page is the
// initial about:blank page (which has that as its principal, not
// just URI in which case it could be web-based). Especially in
// e10s, we need to tackle that case specifically to avoid race
// conditions when updating the URL bar.
//
// Note that we check the documentURI here, since the currentURI on
// the browser might have been set by SessionStore in order to
// support switch-to-tab without having actually loaded the content
// yet.
let uriToCheck = browser.documentURI || uri;
if (
(uriToCheck.spec == "about:blank" && contentPrincipal.isNullPrincipal) ||
contentPrincipal.spec == "about:blank"
) {
return true;
}
if (contentPrincipal.isContentPrincipal) {
return contentPrincipal.equalsURI(uri);
}
// ... so for those that don't have them, enforce that the page has the
// system principal (this matches e.g. on about:newtab).
return contentPrincipal.isSystemPrincipal;
},
/**
* Sets the --toolbarbutton-button-height CSS property on the closest
* toolbar to the provided element. Useful if you need to vertically
* center a position:absolute element within a toolbar that uses
* -moz-pack-align:stretch, and thus a height which is dependant on
* the font-size.
*
* @param element An element within the toolbar whose height is desired.
*/
async setToolbarButtonHeightProperty(element) {
let window = element.ownerGlobal;
let dwu = window.windowUtils;
let toolbarItem = element;
let urlBarContainer = element.closest("#urlbar-container");
if (urlBarContainer) {
// The stop-reload-button, which is contained in #urlbar-container,
// needs to use #urlbar-container to calculate the bounds.
toolbarItem = urlBarContainer;
}
if (!toolbarItem) {
return;
}
let bounds = dwu.getBoundsWithoutFlushing(toolbarItem);
if (!bounds.height) {
await window.promiseDocumentFlushed(() => {
bounds = dwu.getBoundsWithoutFlushing(toolbarItem);
});
}
if (bounds.height) {
toolbarItem.style.setProperty(
"--toolbarbutton-height",
bounds.height + "px"
);
}
},
/**
* Generate a document fragment for a localized string that has DOM
* node replacements. This avoids using getFormattedString followed
* by assigning to innerHTML. Fluent can probably replace this when
* it is in use everywhere.
*
* @param {Document} doc
* @param {String} msg
* The string to put replacements in. Fetch from
* a stringbundle using getString or GetStringFromName,
* or even an inserted dtd string.
* @param {Node|String} nodesOrStrings
* The replacement items. Can be a mix of Nodes
* and Strings. However, for correct behaviour, the
* number of items provided needs to exactly match
* the number of replacement strings in the l10n string.
* @returns {DocumentFragment}
* A document fragment. In the trivial case (no
* replacements), this will simply be a fragment with 1
* child, a text node containing the localized string.
*/
getLocalizedFragment(doc, msg, ...nodesOrStrings) {
// Ensure replacement points are indexed:
for (let i = 1; i <= nodesOrStrings.length; i++) {
if (!msg.includes("%" + i + "$S")) {
msg = msg.replace(/%S/, "%" + i + "$S");
}
}
let numberOfInsertionPoints = msg.match(/%\d+\$S/g).length;
if (numberOfInsertionPoints != nodesOrStrings.length) {
Cu.reportError(
`Message has ${numberOfInsertionPoints} insertion points, ` +
`but got ${nodesOrStrings.length} replacement parameters!`
);
}
let fragment = doc.createDocumentFragment();
let parts = [msg];
let insertionPoint = 1;
for (let replacement of nodesOrStrings) {
let insertionString = "%" + insertionPoint++ + "$S";
let partIndex = parts.findIndex(
part => typeof part == "string" && part.includes(insertionString)
);
if (partIndex == -1) {
fragment.appendChild(doc.createTextNode(msg));
return fragment;
}
if (typeof replacement == "string") {
parts[partIndex] = parts[partIndex].replace(
insertionString,
replacement
);
} else {
let [firstBit, lastBit] = parts[partIndex].split(insertionString);
parts.splice(partIndex, 1, firstBit, replacement, lastBit);
}
}
// Put everything in a document fragment:
for (let part of parts) {
if (typeof part == "string") {
if (part) {
fragment.appendChild(doc.createTextNode(part));
}
} else {
fragment.appendChild(part);
}
}
return fragment;
},
removeSingleTrailingSlashFromURL(aURL) {
// remove single trailing slash for http/https/ftp URLs
return aURL.replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1");
},
/**
* Returns a URL which has been trimmed by removing 'http://' and any
* trailing slash (in http/https/ftp urls).
* Note that a trimmed url may not load the same page as the original url, so
* before loading it, it must be passed through URIFixup, to check trimming
* doesn't change its destination. We don't run the URIFixup check here,
* because trimURL is in the page load path (see onLocationChange), so it
* must be fast and simple.
*
* @param {string} aURL The URL to trim.
* @returns {string} The trimmed string.
*/
get trimURLProtocol() {
return "http://";
},
trimURL(aURL) {
let url = this.removeSingleTrailingSlashFromURL(aURL);
// Remove "http://" prefix.
return url.startsWith(this.trimURLProtocol)
? url.substring(this.trimURLProtocol.length)
: url;
},
};

Просмотреть файл

@ -128,6 +128,7 @@ EXTRA_JS_MODULES += [
"AboutNewTab.jsm",
"AppUpdater.jsm",
"AsyncTabSwitcher.jsm",
"BrowserUIUtils.jsm",
"BrowserUsageTelemetry.jsm",
"BrowserWindowTracker.jsm",
"ContentCrashHandlers.jsm",

Просмотреть файл

@ -36,7 +36,7 @@ toolbar[brighttext] {
animation-iteration-count: 1;
list-style-image: none;
/* Height must be equal to height of toolbarbutton padding-box. --toolbarbutton-height
is calculated and set during runtime by BrowserUtils.setToolbarButtonHeightProperty()
is calculated and set during runtime by BrowserUIUtils.setToolbarButtonHeightProperty()
before the animation begins. */
height: var(--toolbarbutton-height);
}

Просмотреть файл

@ -18,63 +18,6 @@ ChromeUtils.defineModuleGetter(
);
var BrowserUtils = {
/**
* Check whether a page can be considered as 'empty', that its URI
* reflects its origin, and that if it's loaded in a tab, that tab
* could be considered 'empty' (e.g. like the result of opening
* a 'blank' new tab).
*
* We have to do more than just check the URI, because especially
* for things like about:blank, it is possible that the opener or
* some other page has control over the contents of the page.
*
* @param {Browser} browser
* The browser whose page we're checking.
* @param {nsIURI} [uri]
* The URI against which we're checking (the browser's currentURI
* if omitted).
*
* @return {boolean} false if the page was opened by or is controlled by
* arbitrary web content, unless that content corresponds with the URI.
* true if the page is blank and controlled by a principal matching
* that URI (or the system principal if the principal has no URI)
*/
checkEmptyPageOrigin(browser, uri = browser.currentURI) {
// If another page opened this page with e.g. window.open, this page might
// be controlled by its opener.
if (browser.hasContentOpener) {
return false;
}
let contentPrincipal = browser.contentPrincipal;
// Not all principals have URIs...
// There are two special-cases involving about:blank. One is where
// the user has manually loaded it and it got created with a null
// principal. The other involves the case where we load
// some other empty page in a browser and the current page is the
// initial about:blank page (which has that as its principal, not
// just URI in which case it could be web-based). Especially in
// e10s, we need to tackle that case specifically to avoid race
// conditions when updating the URL bar.
//
// Note that we check the documentURI here, since the currentURI on
// the browser might have been set by SessionStore in order to
// support switch-to-tab without having actually loaded the content
// yet.
let uriToCheck = browser.documentURI || uri;
if (
(uriToCheck.spec == "about:blank" && contentPrincipal.isNullPrincipal) ||
contentPrincipal.spec == "about:blank"
) {
return true;
}
if (contentPrincipal.isContentPrincipal) {
return contentPrincipal.equalsURI(uri);
}
// ... so for those that don't have them, enforce that the page has the
// system principal (this matches e.g. on about:newtab).
return contentPrincipal.isSystemPrincipal;
},
/**
* urlSecurityCheck: JavaScript wrapper for checkLoadURIWithPrincipal
* and checkLoadURIStrWithPrincipal.
@ -348,42 +291,6 @@ var BrowserUtils = {
return !!toolbars && toolbars.has(which);
},
/**
* Sets the --toolbarbutton-button-height CSS property on the closest
* toolbar to the provided element. Useful if you need to vertically
* center a position:absolute element within a toolbar that uses
* -moz-pack-align:stretch, and thus a height which is dependant on
* the font-size.
*
* @param element An element within the toolbar whose height is desired.
*/
async setToolbarButtonHeightProperty(element) {
let window = element.ownerGlobal;
let dwu = window.windowUtils;
let toolbarItem = element;
let urlBarContainer = element.closest("#urlbar-container");
if (urlBarContainer) {
// The stop-reload-button, which is contained in #urlbar-container,
// needs to use #urlbar-container to calculate the bounds.
toolbarItem = urlBarContainer;
}
if (!toolbarItem) {
return;
}
let bounds = dwu.getBoundsWithoutFlushing(toolbarItem);
if (!bounds.height) {
await window.promiseDocumentFlushed(() => {
bounds = dwu.getBoundsWithoutFlushing(toolbarItem);
});
}
if (bounds.height) {
toolbarItem.style.setProperty(
"--toolbarbutton-height",
bounds.height + "px"
);
}
},
/**
* Track whether a toolbar is visible for a given a docShell.
*
@ -646,79 +553,6 @@ var BrowserUtils = {
return [url, postData];
},
/**
* Generate a document fragment for a localized string that has DOM
* node replacements. This avoids using getFormattedString followed
* by assigning to innerHTML. Fluent can probably replace this when
* it is in use everywhere.
*
* @param {Document} doc
* @param {String} msg
* The string to put replacements in. Fetch from
* a stringbundle using getString or GetStringFromName,
* or even an inserted dtd string.
* @param {Node|String} nodesOrStrings
* The replacement items. Can be a mix of Nodes
* and Strings. However, for correct behaviour, the
* number of items provided needs to exactly match
* the number of replacement strings in the l10n string.
* @returns {DocumentFragment}
* A document fragment. In the trivial case (no
* replacements), this will simply be a fragment with 1
* child, a text node containing the localized string.
*/
getLocalizedFragment(doc, msg, ...nodesOrStrings) {
// Ensure replacement points are indexed:
for (let i = 1; i <= nodesOrStrings.length; i++) {
if (!msg.includes("%" + i + "$S")) {
msg = msg.replace(/%S/, "%" + i + "$S");
}
}
let numberOfInsertionPoints = msg.match(/%\d+\$S/g).length;
if (numberOfInsertionPoints != nodesOrStrings.length) {
Cu.reportError(
`Message has ${numberOfInsertionPoints} insertion points, ` +
`but got ${nodesOrStrings.length} replacement parameters!`
);
}
let fragment = doc.createDocumentFragment();
let parts = [msg];
let insertionPoint = 1;
for (let replacement of nodesOrStrings) {
let insertionString = "%" + insertionPoint++ + "$S";
let partIndex = parts.findIndex(
part => typeof part == "string" && part.includes(insertionString)
);
if (partIndex == -1) {
fragment.appendChild(doc.createTextNode(msg));
return fragment;
}
if (typeof replacement == "string") {
parts[partIndex] = parts[partIndex].replace(
insertionString,
replacement
);
} else {
let [firstBit, lastBit] = parts[partIndex].split(insertionString);
parts.splice(partIndex, 1, firstBit, replacement, lastBit);
}
}
// Put everything in a document fragment:
for (let part of parts) {
if (typeof part == "string") {
if (part) {
fragment.appendChild(doc.createTextNode(part));
}
} else {
fragment.appendChild(part);
}
}
return fragment;
},
/**
* Returns a Promise which resolves when the given observer topic has been
* observed.
@ -742,34 +576,6 @@ var BrowserUtils = {
Services.obs.addObserver(observer, topic);
});
},
removeSingleTrailingSlashFromURL(aURL) {
// remove single trailing slash for http/https/ftp URLs
return aURL.replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1");
},
/**
* Returns a URL which has been trimmed by removing 'http://' and any
* trailing slash (in http/https/ftp urls).
* Note that a trimmed url may not load the same page as the original url, so
* before loading it, it must be passed through URIFixup, to check trimming
* doesn't change its destination. We don't run the URIFixup check here,
* because trimURL is in the page load path (see onLocationChange), so it
* must be fast and simple.
*
* @param {string} aURL The URL to trim.
* @returns {string} The trimmed string.
*/
get trimURLProtocol() {
return "http://";
},
trimURL(aURL) {
let url = this.removeSingleTrailingSlashFromURL(aURL);
// Remove "http://" prefix.
return url.startsWith(this.trimURLProtocol)
? url.substring(this.trimURLProtocol.length)
: url;
},
};
XPCOMUtils.defineLazyPreferenceGetter(