Update On Thu Jun 9 20:34:22 CEST 2022
This commit is contained in:
parent
c40cfe2487
commit
e2e2aeb2aa
1180 changed files with 22537 additions and 22376 deletions
53
Cargo.lock
generated
53
Cargo.lock
generated
|
@ -585,9 +585,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.9.1"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
|
@ -763,9 +763,9 @@ checksum = "bb7bdea464ae038f09197b82430b921c53619fc8d2bcaf7b151013b3ca008017"
|
|||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.3.2"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf6b561dcf059c85bbe388e0a7b0a1469acb3934cc0cfa148613a830629e3049"
|
||||
checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
|
@ -1080,7 +1080,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-epoch 0.9.6",
|
||||
"crossbeam-epoch 0.9.8",
|
||||
"crossbeam-utils 0.8.8",
|
||||
]
|
||||
|
||||
|
@ -1101,10 +1101,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.6"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762"
|
||||
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils 0.8.8",
|
||||
"lazy_static",
|
||||
|
@ -1655,13 +1656,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.23"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
|
||||
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crc32fast",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
|
@ -2186,6 +2185,7 @@ dependencies = [
|
|||
"mapped_hyph",
|
||||
"mdns_service",
|
||||
"midir_impl",
|
||||
"mio 0.8.0",
|
||||
"moz_asserts",
|
||||
"mozurl",
|
||||
"mp4parse_capi",
|
||||
|
@ -2509,9 +2509,9 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
|||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb"
|
||||
checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"fnv",
|
||||
|
@ -2576,9 +2576,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.18"
|
||||
version = "0.14.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
|
||||
checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures-channel",
|
||||
|
@ -2623,9 +2623,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.1"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
||||
checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -2664,7 +2664,7 @@ version = "0.1.0"
|
|||
source = "git+https://github.com/mozilla/application-services?rev=2689788cecf24c385e6b7440e3aa1a89c511f14a#2689788cecf24c385e6b7440e3aa1a89c511f14a"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.999",
|
||||
"rusqlite",
|
||||
]
|
||||
|
||||
|
@ -3962,6 +3962,13 @@ dependencies = [
|
|||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.999"
|
||||
dependencies = [
|
||||
"parking_lot 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.1"
|
||||
|
@ -4797,7 +4804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.1",
|
||||
"serial_test_derive",
|
||||
]
|
||||
|
||||
|
@ -5012,7 +5019,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"num_cpus",
|
||||
"owning_ref",
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.1",
|
||||
"precomputed-hash",
|
||||
"rayon",
|
||||
"regex",
|
||||
|
@ -6061,7 +6068,7 @@ dependencies = [
|
|||
"fxhash",
|
||||
"log",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.999",
|
||||
"profiling",
|
||||
"ron",
|
||||
"serde",
|
||||
|
@ -6096,7 +6103,7 @@ dependencies = [
|
|||
"metal",
|
||||
"naga",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.999",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
|
@ -6124,7 +6131,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bincode",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.1",
|
||||
"serde",
|
||||
"wgpu-core",
|
||||
"wgpu-hal",
|
||||
|
|
|
@ -128,6 +128,10 @@ cargo_metadata = { path = "build/rust/cargo_metadata" }
|
|||
# Patch nom 5 to nom 6
|
||||
nom = { path = "build/rust/nom" }
|
||||
|
||||
# Patch parking_lot 0.12 down to 0.11, which is compatible for most crates that use it, to avoid
|
||||
# dependencies on windows-sys.
|
||||
parking_lot = { path = "build/rust/parking_lot" }
|
||||
|
||||
# Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
|
||||
autocfg = { path = "third_party/rust/autocfg" }
|
||||
|
||||
|
|
48
accessible/docs/ColorsAndHighContrastMode.md
Normal file
48
accessible/docs/ColorsAndHighContrastMode.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
# Colors and High Contrast Mode
|
||||
Firefox offers several customisations to improve the accessibility of colors used to render web content and Firefox chrome. This document describes the customisation options available and their behaviour across platforms. It also describes how these options interact with one another. It is intended for developer reference :)
|
||||
|
||||
## The Colors Dialog
|
||||
In `about:preferences > Language and Appearance`, you'll find a button labelled "Colors". This button launches the colors dialog, which contains all of our user-facing color customisation options, as well as stylistic customisations like link underlining. This dialog also contains the select that controls what we'll refer to as "Firefox High Contrast Mode", or FF HCM. FF HCM can be enabled "Always", "Never", or "Only with High Contrast Themes".
|
||||
> Note: FF HCM only affects web content, so changing the option in this select will only alter color usage for web pages. It will not change FF chrome. Current behaviour on chrome pages (ie. `about:` pages) is undefined.
|
||||
|
||||
### User-customisable Colors
|
||||
Users can choose to override background color, foreground color, visited link color, and/or unvisited link color by selecting a new color from the color inputs in the dialog. Modifications to these colors are stored in their corresponding user preference:
|
||||
- `browser.background_color`
|
||||
- `browser.foreground_color`
|
||||
- `browser.visited_color`
|
||||
- `browser.anchor_color`
|
||||
|
||||
### Color Usage and System Colors
|
||||
Before we render any Firefox/web content, we need to select a color palette to render that content _with_. We don't always use the colors a user has selected in the colors dialog. In fact, there are three different sets of colors we can use to style Firefox and/or web content:
|
||||
- Stand-in colors
|
||||
- System colors
|
||||
- Colors-dialog colors
|
||||
|
||||
> Note: Web pages may supply their own style sheets, which override a user's chosen color palette. When FF HCM is set to "Always", or set to "With High Contrast Themes" and OS HCM is enabled, the chosen color palette is _forced_, meaning it cannot be overridden by web pages. FF HCM and OS HCM do not directly change the way a color palette is chosen, but they _do_ change how the color palette is used.
|
||||
|
||||
We decide which set of colors to use in `PreferenceSheet::Load`. If `resistFingerprinting` is enabled, we use stand-in colors. These colors are pre-defined constants and are not dynamically fetched from the operating system. Check out `nsXPLookAndFeel::GetStandinForNativeColor` for more information, as well as the constants themselves.
|
||||
|
||||
If we aren't using stand-in colors, we'll check `browser.display.use_system_colors`, which is set from the "Use system colors" checkbox in the colors dialog. If that pref is true, we'll use system colors to style web content and Firefox chrome.
|
||||
|
||||
System colors are colors queried from the operating system. They help Firefox adapt to OS-level changes that aren't strictly HCM (ie. light/dark themeing). Because these colors are OS-dependent, a user operating Firefox on a Windows machine with system colors enabled will see Firefox differently than a user with system colors enabled on MacOS.
|
||||
|
||||
So, how do we _get_ system colors? Our style system has a set of pre-defined `ColorID`'s in `ServoStyleConsts.h`, which are mapped to platform-specific colors in `widget/[cocoa | android | windows | gtk]/LookAndFeel.cpp`. Depending on the `ColorID` queried, we may do a dynamic fetch or simply return a constant. On MacOS, for example, `ColorID::TextForeground` and `ColorID::TextBackground` are hard-coded to return black and white respectively. `ColorID::Highlight`, on the other hand, queries the OS for `NSColor.selectedTextBackgroundColor`, which is set based on the accent color a user has selected in System Preferences.
|
||||
> Note: The colors we fetch here are theme-relative. If a user has set their OS to a dark theme, we'll fetch colors from that palette, and likewise for a light theme. Windows HCM, though not strictly a "theme", overrides the colors stored for Windows' light theme, leading to [some confusing code, like this](https://searchfox.org/mozilla-central/rev/b462b11e71b500e084f51e61fbd9e19ea0122c78/layout/style/PreferenceSheet.cpp#202-210).
|
||||
|
||||
Lastly, if we are _not_ using system colors AND we are _not_ styling Firefox chrome AND we are _not_ `resistFingerprinting`, we'll use colors-dialog colors to style web content.
|
||||
|
||||
By default, `browser.display.use_system_colors` is true on Windows and false elsewhere. This means users on Windows will _not_ see their selections in the colors dialog reflected automatically in Firefox. They'll need to uncheck "Use system colors" first.
|
||||
> Note: This is intentional. When Windows HCM is enabled, the system colors Windows exposes are pulled from the chosen HCM theme. With "Use system colors" checked, a Windows HCM user will see their HCM theme choices reflected in Firefox content automatically. Windows HCM is the most robust HCM offered among the operating systems we support, and so we cater to it here :)
|
||||
|
||||
Users on non-Windows platforms will see their selections in the colors dialog reflected automatically, but they will _not_ see OS changes until they check "Use system colors".
|
||||
|
||||
## High Contrast Mode
|
||||
|
||||
### Operating System High Contrast Mode (OS HCM)
|
||||
|
||||
Operating System HCM (or OS HCM) describes a high contrast customisation that is enabled outside of Firefox, in the settings of a user's operating system. Each of our major desktop operating systems has an OS HCM variant:
|
||||
- Windows: Settings > Accessibility > Increase Contrast > (select theme) > Apply
|
||||
- MacOS: System Preferences > Accessibility > Display > Increase Contrast
|
||||
- Linux: Settings > Themes > High Contrast
|
||||
|
||||
The presence of an OS HCM is stored in `IntID::UseAccessibilityTheme`.
|
|
@ -11,3 +11,4 @@ The `Accessibility page on the Mozilla Wiki <https://wiki.mozilla.org/Accessibil
|
|||
|
||||
DocumentAccessibilityLifecycle
|
||||
GeckoViewThreadTopography
|
||||
ColorsAndHighContrastMode
|
||||
|
|
|
@ -1213,11 +1213,10 @@ bool DocAccessible::PruneOrInsertSubtree(nsIContent* aRoot) {
|
|||
nsIContent* shadowHost =
|
||||
aRoot->GetShadowRoot() ? aRoot : aRoot->GetContainingShadowHost();
|
||||
if (shadowHost) {
|
||||
dom::ExplicitChildIterator iter(shadowHost);
|
||||
|
||||
// Check all explicit children in the host, if they are not slotted
|
||||
// then remove their accessibles and subtrees.
|
||||
while (nsIContent* childNode = iter.GetNextChild()) {
|
||||
for (nsIContent* childNode = shadowHost->GetFirstChild(); childNode;
|
||||
childNode = childNode->GetNextSibling()) {
|
||||
if (!childNode->GetPrimaryFrame() &&
|
||||
!nsCoreUtils::CanCreateAccessibleWithoutFrame(childNode)) {
|
||||
ContentRemoved(childNode);
|
||||
|
@ -2104,8 +2103,8 @@ void DocAccessible::ContentRemoved(nsIContent* aContentNode) {
|
|||
// ExplicitChildIterator in order to get its accessible children in the light
|
||||
// DOM, since they are not accessible anymore via AllChildrenIterator.
|
||||
if (aContentNode->GetShadowRoot()) {
|
||||
dom::ExplicitChildIterator iter = dom::ExplicitChildIterator(aContentNode);
|
||||
while (nsIContent* childNode = iter.GetNextChild()) {
|
||||
for (nsIContent* childNode = aContentNode->GetFirstChild(); childNode;
|
||||
childNode = childNode->GetNextSibling()) {
|
||||
ContentRemoved(childNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,9 +75,6 @@ skip-if = (os == 'win' && bits == 32) || (os == 'mac') # Disabled on Win32 becau
|
|||
[browser_urlbar_search.js]
|
||||
skip-if = (debug || ccov) && (os == 'linux' || os == 'win') || (os == 'win' && bits == 32) # Disabled on Linux and Windows debug and ccov due to intermittent timeouts. Bug 1414126, bug 1426611. Disabled on Win32 because of intermittent OOM failures (bug 1448241)
|
||||
[browser_vsync_accessibility.js]
|
||||
skip-if =
|
||||
os == "linux" # Bug 1772026
|
||||
win10_2004 && bits == 64 # Bug 1772026
|
||||
[browser_window_resize.js]
|
||||
[browser_windowclose.js]
|
||||
[browser_windowopen.js]
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,9 +13,6 @@ class ColorwaySelector extends HTMLFieldSetElement {
|
|||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||
BuiltInThemes: "resource:///modules/BuiltInThemes.jsm",
|
||||
});
|
||||
this.colorways;
|
||||
this.activeTheme;
|
||||
this.selectedTheme;
|
||||
window.addEventListener("unload", () => {
|
||||
this.AddonManager.removeAddonListener(this);
|
||||
});
|
||||
|
@ -54,6 +51,7 @@ class ColorwaySelector extends HTMLFieldSetElement {
|
|||
}
|
||||
}
|
||||
render() {
|
||||
let isFirst = true;
|
||||
for (const theme of this.colorways) {
|
||||
let input = document.createElement("input");
|
||||
input.type = "radio";
|
||||
|
@ -70,6 +68,11 @@ class ColorwaySelector extends HTMLFieldSetElement {
|
|||
if (theme.isActive) {
|
||||
input.classList.add("active");
|
||||
}
|
||||
if (isFirst) {
|
||||
input.checked = true;
|
||||
input.onclick();
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +87,7 @@ class ColorwaySelector extends HTMLFieldSetElement {
|
|||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.getColorways().then(value => {
|
||||
this.getColorways().then(() => {
|
||||
this.render();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
colorway-collection-life-in-color = Life In Color
|
||||
colorway-collection-true-colors = True Colors
|
||||
colorway-collection-independent-voices = Independent Voices
|
||||
|
||||
# Label for the button to start using the selected colorway in the browser
|
||||
set-colorway-button = Set Colorway
|
||||
|
||||
colorway-fx-home-link = Use { -brand-product-name } Home for colorful new tabs
|
||||
colorway-fx-home-link-success = { -brand-product-name } Home is now your home page
|
||||
colorway-fx-home-apply-button = Apply
|
||||
|
|
|
@ -25,10 +25,11 @@
|
|||
</header>
|
||||
<main>
|
||||
<section id="colorway-customization-panel">
|
||||
<fieldset is="colorway-selector"></fieldset>
|
||||
<fieldset id="colorway-selector" is="colorway-selector"></fieldset>
|
||||
<div id="colorway-details">
|
||||
<h2 id="colorway-name"></h2>
|
||||
<p id="colorway-description"></p>
|
||||
<button id="set-colorway" data-l10n-id="set-colorway-button" class="primary"></button>
|
||||
</div>
|
||||
</section>
|
||||
<section id="use-fx-home-controls" hidden>
|
||||
|
|
|
@ -7,6 +7,12 @@ const { BuiltInThemes } = ChromeUtils.import(
|
|||
);
|
||||
const { HomePage } = ChromeUtils.import("resource:///modules/HomePage.jsm");
|
||||
|
||||
const colorwaySelector = document.getElementById("colorway-selector");
|
||||
|
||||
document.getElementById("set-colorway").onclick = () => {
|
||||
colorwaySelector.selectedTheme.enable();
|
||||
};
|
||||
|
||||
function showUseFXHomeControls(fluentStrings) {
|
||||
let homeState;
|
||||
const useFXHomeControls = document.getElementById("use-fx-home-controls");
|
||||
|
|
|
@ -32,6 +32,8 @@ add_task(async function about_colorwaycloset_smoke_test() {
|
|||
"colorway description exists"
|
||||
);
|
||||
|
||||
ok(document.getElementById("set-colorway"), "Found Set Colorway button");
|
||||
|
||||
const useFXHomeControls = document.getElementById("use-fx-home-controls");
|
||||
ok(useFXHomeControls, "firefox home controls exists");
|
||||
useFXHomeControls.toggleAttribute("hidden", false);
|
||||
|
|
|
@ -17,7 +17,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
Preferences: "resource://gre/modules/Preferences.jsm",
|
||||
Region: "resource://gre/modules/Region.jsm",
|
||||
RemoteSettings: "resource://services-settings/remote-settings.js",
|
||||
|
@ -38,16 +40,16 @@ const kConfigPrefs = {
|
|||
|
||||
const kPrefChangedTopic = "nsPref:changed";
|
||||
|
||||
const gProvidersCollection = RemoteSettings("doh-providers");
|
||||
const gConfigCollection = RemoteSettings("doh-config");
|
||||
const gProvidersCollection = lazy.RemoteSettings("doh-providers");
|
||||
const gConfigCollection = lazy.RemoteSettings("doh-config");
|
||||
|
||||
function getPrefValueRegionFirst(prefName) {
|
||||
let regionalPrefName = `${kRegionPrefBranch}.${prefName}`;
|
||||
let regionalPrefValue = Preferences.get(regionalPrefName);
|
||||
let regionalPrefValue = lazy.Preferences.get(regionalPrefName);
|
||||
if (regionalPrefValue !== undefined) {
|
||||
return regionalPrefValue;
|
||||
}
|
||||
return Preferences.get(`${kGlobalPrefBranch}.${prefName}`);
|
||||
return lazy.Preferences.get(`${kGlobalPrefBranch}.${prefName}`);
|
||||
}
|
||||
|
||||
function getProviderListFromPref(prefName) {
|
||||
|
@ -171,7 +173,7 @@ const DoHConfigController = {
|
|||
// until the region is available.
|
||||
async loadRegion() {
|
||||
await new Promise(resolve => {
|
||||
let homeRegion = Preferences.get(`${kGlobalPrefBranch}.home-region`);
|
||||
let homeRegion = lazy.Preferences.get(`${kGlobalPrefBranch}.home-region`);
|
||||
if (homeRegion) {
|
||||
kRegionPrefBranch = `${kGlobalPrefBranch}.${homeRegion.toLowerCase()}`;
|
||||
resolve();
|
||||
|
@ -179,20 +181,23 @@ const DoHConfigController = {
|
|||
}
|
||||
|
||||
let updateRegionAndResolve = () => {
|
||||
kRegionPrefBranch = `${kGlobalPrefBranch}.${Region.home.toLowerCase()}`;
|
||||
Preferences.set(`${kGlobalPrefBranch}.home-region`, Region.home);
|
||||
kRegionPrefBranch = `${kGlobalPrefBranch}.${lazy.Region.home.toLowerCase()}`;
|
||||
lazy.Preferences.set(
|
||||
`${kGlobalPrefBranch}.home-region`,
|
||||
lazy.Region.home
|
||||
);
|
||||
resolve();
|
||||
};
|
||||
|
||||
if (Region.home) {
|
||||
if (lazy.Region.home) {
|
||||
updateRegionAndResolve();
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(function obs(sub, top, data) {
|
||||
Services.obs.removeObserver(obs, Region.REGION_TOPIC);
|
||||
Services.obs.removeObserver(obs, lazy.Region.REGION_TOPIC);
|
||||
updateRegionAndResolve();
|
||||
}, Region.REGION_TOPIC);
|
||||
}, lazy.Region.REGION_TOPIC);
|
||||
});
|
||||
|
||||
// Finally, reload config.
|
||||
|
@ -265,7 +270,7 @@ const DoHConfigController = {
|
|||
configByRegion.set(c.id, c);
|
||||
});
|
||||
|
||||
let homeRegion = Preferences.get(`${kGlobalPrefBranch}.home-region`);
|
||||
let homeRegion = lazy.Preferences.get(`${kGlobalPrefBranch}.home-region`);
|
||||
let localConfig =
|
||||
configByRegion.get(homeRegion?.toLowerCase()) ||
|
||||
configByRegion.get("global");
|
||||
|
|
|
@ -16,7 +16,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
|
||||
ClientID: "resource://gre/modules/ClientID.jsm",
|
||||
ExtensionStorageIDB: "resource://gre/modules/ExtensionStorageIDB.jsm",
|
||||
|
@ -30,7 +32,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
// When this is set we suppress automatic TRR selection beyond dry-run as well
|
||||
// as sending observer notifications during heuristics throttling.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"kIsInAutomation",
|
||||
"doh-rollout._testing",
|
||||
false
|
||||
|
@ -39,7 +41,7 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||
// We wait until the network has been stably up for this many milliseconds
|
||||
// before triggering a heuristics run.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"kNetworkDebounceTimeout",
|
||||
"doh-rollout.network-debounce-timeout",
|
||||
1000
|
||||
|
@ -52,7 +54,7 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||
// This throttling is necessary due to evidence of clients that experience
|
||||
// network volatility leading to thousands of runs per hour. See bug 1626083.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"kHeuristicsThrottleTimeout",
|
||||
"doh-rollout.heuristics-throttle-timeout",
|
||||
15000
|
||||
|
@ -63,28 +65,28 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||
// heuristics. Thus, heuristics are suppressed completely as long as the rate
|
||||
// exceeds this limit.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"kHeuristicsRateLimit",
|
||||
"doh-rollout.heuristics-throttle-rate-limit",
|
||||
2
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gCaptivePortalService",
|
||||
"@mozilla.org/network/captive-portal-service;1",
|
||||
"nsICaptivePortalService"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gDNSService",
|
||||
"@mozilla.org/network/dns-service;1",
|
||||
"nsIDNSService"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gNetworkLinkService",
|
||||
"@mozilla.org/network/network-link-service;1",
|
||||
"nsINetworkLinkService"
|
||||
|
@ -130,7 +132,7 @@ const kPrefChangedTopic = "nsPref:changed";
|
|||
// Helper function to hash the network ID concatenated with telemetry client ID.
|
||||
// This prevents us from being able to tell if 2 clients are on the same network.
|
||||
function getHashedNetworkID() {
|
||||
let currentNetworkID = gNetworkLinkService.networkID;
|
||||
let currentNetworkID = lazy.gNetworkLinkService.networkID;
|
||||
if (!currentNetworkID) {
|
||||
return "";
|
||||
}
|
||||
|
@ -141,7 +143,7 @@ function getHashedNetworkID() {
|
|||
|
||||
hasher.init(Ci.nsICryptoHash.SHA256);
|
||||
// Concat the client ID with the network ID before hashing.
|
||||
let clientNetworkID = ClientID.getClientID() + currentNetworkID;
|
||||
let clientNetworkID = lazy.ClientID.getClientID() + currentNetworkID;
|
||||
hasher.update(
|
||||
clientNetworkID.split("").map(c => c.charCodeAt(0)),
|
||||
clientNetworkID.length
|
||||
|
@ -166,15 +168,15 @@ const DoHController = {
|
|||
true
|
||||
);
|
||||
|
||||
await DoHConfigController.initComplete;
|
||||
await lazy.DoHConfigController.initComplete;
|
||||
|
||||
Services.obs.addObserver(this, DoHConfigController.kConfigUpdateTopic);
|
||||
Preferences.observe(NETWORK_TRR_MODE_PREF, this);
|
||||
Preferences.observe(NETWORK_TRR_URI_PREF, this);
|
||||
Services.obs.addObserver(this, lazy.DoHConfigController.kConfigUpdateTopic);
|
||||
lazy.Preferences.observe(NETWORK_TRR_MODE_PREF, this);
|
||||
lazy.Preferences.observe(NETWORK_TRR_URI_PREF, this);
|
||||
|
||||
if (DoHConfigController.currentConfig.enabled) {
|
||||
if (lazy.DoHConfigController.currentConfig.enabled) {
|
||||
await this.maybeEnableHeuristics();
|
||||
} else if (Preferences.get(FIRST_RUN_PREF, false)) {
|
||||
} else if (lazy.Preferences.get(FIRST_RUN_PREF, false)) {
|
||||
await this.rollback();
|
||||
}
|
||||
|
||||
|
@ -182,21 +184,26 @@ const DoHController = {
|
|||
await this.disableHeuristics("shutdown");
|
||||
};
|
||||
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
lazy.AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"DoHController: clear state and remove observers",
|
||||
this._asyncShutdownBlocker
|
||||
);
|
||||
|
||||
Preferences.set(FIRST_RUN_PREF, true);
|
||||
lazy.Preferences.set(FIRST_RUN_PREF, true);
|
||||
},
|
||||
|
||||
// Also used by tests to reset DoHController state (prefs are not cleared
|
||||
// here - tests do that when needed between _uninit and init).
|
||||
async _uninit() {
|
||||
Services.obs.removeObserver(this, DoHConfigController.kConfigUpdateTopic);
|
||||
Preferences.ignore(NETWORK_TRR_MODE_PREF, this);
|
||||
Preferences.ignore(NETWORK_TRR_URI_PREF, this);
|
||||
AsyncShutdown.profileBeforeChange.removeBlocker(this._asyncShutdownBlocker);
|
||||
Services.obs.removeObserver(
|
||||
this,
|
||||
lazy.DoHConfigController.kConfigUpdateTopic
|
||||
);
|
||||
lazy.Preferences.ignore(NETWORK_TRR_MODE_PREF, this);
|
||||
lazy.Preferences.ignore(NETWORK_TRR_URI_PREF, this);
|
||||
lazy.AsyncShutdown.profileBeforeChange.removeBlocker(
|
||||
this._asyncShutdownBlocker
|
||||
);
|
||||
await this.disableHeuristics("shutdown");
|
||||
},
|
||||
|
||||
|
@ -217,7 +224,10 @@ const DoHController = {
|
|||
const ADDON_ID = "doh-rollout@mozilla.org";
|
||||
|
||||
// Migrate updated local storage item names. If this has already been done once, skip the migration
|
||||
const isMigrated = Preferences.get(BALROG_MIGRATION_COMPLETED_PREF, false);
|
||||
const isMigrated = lazy.Preferences.get(
|
||||
BALROG_MIGRATION_COMPLETED_PREF,
|
||||
false
|
||||
);
|
||||
|
||||
if (isMigrated) {
|
||||
return;
|
||||
|
@ -228,10 +238,10 @@ const DoHController = {
|
|||
return;
|
||||
}
|
||||
|
||||
const storagePrincipal = ExtensionStorageIDB.getStoragePrincipal(
|
||||
const storagePrincipal = lazy.ExtensionStorageIDB.getStoragePrincipal(
|
||||
policy.extension
|
||||
);
|
||||
const idbConn = await ExtensionStorageIDB.open(storagePrincipal);
|
||||
const idbConn = await lazy.ExtensionStorageIDB.open(storagePrincipal);
|
||||
|
||||
// Previously, the DoH heuristics were bundled as an add-on. Early versions
|
||||
// of this add-on used local storage instead of prefs to persist state. This
|
||||
|
@ -254,7 +264,7 @@ const DoHController = {
|
|||
migratedName = "doh-rollout." + item;
|
||||
}
|
||||
|
||||
Preferences.set(migratedName, value);
|
||||
lazy.Preferences.set(migratedName, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,7 +272,7 @@ const DoHController = {
|
|||
await idbConn.close();
|
||||
|
||||
// Set pref to skip this function in the future.
|
||||
Preferences.set(BALROG_MIGRATION_COMPLETED_PREF, true);
|
||||
lazy.Preferences.set(BALROG_MIGRATION_COMPLETED_PREF, true);
|
||||
},
|
||||
|
||||
// Previous versions of the DoH frontend worked by setting network.trr.mode
|
||||
|
@ -271,14 +281,14 @@ const DoHController = {
|
|||
async migrateOldTrrMode() {
|
||||
const PREVIOUS_TRR_MODE_PREF = "doh-rollout.previous.trr.mode";
|
||||
|
||||
if (Preferences.get(PREVIOUS_TRR_MODE_PREF) === undefined) {
|
||||
if (lazy.Preferences.get(PREVIOUS_TRR_MODE_PREF) === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Preferences.get(NETWORK_TRR_MODE_PREF) !== 5) {
|
||||
Preferences.reset(NETWORK_TRR_MODE_PREF);
|
||||
if (lazy.Preferences.get(NETWORK_TRR_MODE_PREF) !== 5) {
|
||||
lazy.Preferences.reset(NETWORK_TRR_MODE_PREF);
|
||||
}
|
||||
Preferences.reset(PREVIOUS_TRR_MODE_PREF);
|
||||
lazy.Preferences.reset(PREVIOUS_TRR_MODE_PREF);
|
||||
},
|
||||
|
||||
async migrateNextDNSEndpoint() {
|
||||
|
@ -298,10 +308,13 @@ const DoHController = {
|
|||
];
|
||||
|
||||
for (let pref of prefsToMigrate) {
|
||||
if (!Preferences.isSet(pref)) {
|
||||
if (!lazy.Preferences.isSet(pref)) {
|
||||
continue;
|
||||
}
|
||||
Preferences.set(pref, Preferences.get(pref).replaceAll(oldURL, newURL));
|
||||
lazy.Preferences.set(
|
||||
pref,
|
||||
lazy.Preferences.get(pref).replaceAll(oldURL, newURL)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -310,36 +323,36 @@ const DoHController = {
|
|||
// detected this (i.e. DISABLED_PREF is true)
|
||||
// 2. If there are any non-DoH enterprise policies active
|
||||
async maybeEnableHeuristics() {
|
||||
if (Preferences.get(DISABLED_PREF)) {
|
||||
if (lazy.Preferences.get(DISABLED_PREF)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let policyResult = await Heuristics.checkEnterprisePolicy();
|
||||
let policyResult = await lazy.Heuristics.checkEnterprisePolicy();
|
||||
|
||||
if (["policy_without_doh", "disable_doh"].includes(policyResult)) {
|
||||
await this.setState("policyDisabled");
|
||||
Preferences.set(SKIP_HEURISTICS_PREF, true);
|
||||
lazy.Preferences.set(SKIP_HEURISTICS_PREF, true);
|
||||
return;
|
||||
}
|
||||
|
||||
Preferences.reset(SKIP_HEURISTICS_PREF);
|
||||
lazy.Preferences.reset(SKIP_HEURISTICS_PREF);
|
||||
|
||||
if (
|
||||
Preferences.isSet(NETWORK_TRR_MODE_PREF) ||
|
||||
Preferences.isSet(NETWORK_TRR_URI_PREF)
|
||||
lazy.Preferences.isSet(NETWORK_TRR_MODE_PREF) ||
|
||||
lazy.Preferences.isSet(NETWORK_TRR_URI_PREF)
|
||||
) {
|
||||
await this.setState("manuallyDisabled");
|
||||
Preferences.set(DISABLED_PREF, true);
|
||||
lazy.Preferences.set(DISABLED_PREF, true);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.runTRRSelection();
|
||||
// If we enter this branch it means that no automatic selection was possible.
|
||||
// In this case, we try to set a fallback (as defined by DoHConfigController).
|
||||
if (!Preferences.isSet(ROLLOUT_URI_PREF)) {
|
||||
Preferences.set(
|
||||
if (!lazy.Preferences.isSet(ROLLOUT_URI_PREF)) {
|
||||
lazy.Preferences.set(
|
||||
ROLLOUT_URI_PREF,
|
||||
DoHConfigController.currentConfig.fallbackProviderURI
|
||||
lazy.DoHConfigController.currentConfig.fallbackProviderURI
|
||||
);
|
||||
}
|
||||
this.runHeuristicsThrottled("startup");
|
||||
|
@ -352,7 +365,7 @@ const DoHController = {
|
|||
_runsWhileThrottling: 0,
|
||||
_wasThrottleExtended: false,
|
||||
_throttleHeuristics() {
|
||||
if (kHeuristicsThrottleTimeout < 0) {
|
||||
if (lazy.kHeuristicsThrottleTimeout < 0) {
|
||||
// Skip throttling in tests that set timeout to a negative value.
|
||||
return false;
|
||||
}
|
||||
|
@ -365,9 +378,9 @@ const DoHController = {
|
|||
|
||||
this._runsWhileThrottling = 0;
|
||||
|
||||
this._throttleTimer = setTimeout(
|
||||
this._throttleTimer = lazy.setTimeout(
|
||||
this._handleThrottleTimeout.bind(this),
|
||||
kHeuristicsThrottleTimeout
|
||||
lazy.kHeuristicsThrottleTimeout
|
||||
);
|
||||
|
||||
return false;
|
||||
|
@ -375,13 +388,13 @@ const DoHController = {
|
|||
|
||||
_handleThrottleTimeout() {
|
||||
delete this._throttleTimer;
|
||||
if (this._runsWhileThrottling > kHeuristicsRateLimit) {
|
||||
if (this._runsWhileThrottling > lazy.kHeuristicsRateLimit) {
|
||||
// During the throttle period, we saw that the rate limit was exceeded.
|
||||
// We extend the throttle period, and don't bother running heuristics yet.
|
||||
this._wasThrottleExtended = true;
|
||||
// Restart the throttle timer.
|
||||
this._throttleHeuristics();
|
||||
if (kIsInAutomation) {
|
||||
if (lazy.kIsInAutomation) {
|
||||
Services.obs.notifyObservers(null, "doh:heuristics-throttle-extend");
|
||||
}
|
||||
return;
|
||||
|
@ -396,7 +409,7 @@ const DoHController = {
|
|||
|
||||
this._wasThrottleExtended = false;
|
||||
|
||||
if (kIsInAutomation) {
|
||||
if (lazy.kIsInAutomation) {
|
||||
Services.obs.notifyObservers(null, "doh:heuristics-throttle-done");
|
||||
}
|
||||
},
|
||||
|
@ -416,12 +429,13 @@ const DoHController = {
|
|||
async runHeuristics(evaluateReason) {
|
||||
let start = Date.now();
|
||||
|
||||
let results = await Heuristics.run();
|
||||
let results = await lazy.Heuristics.run();
|
||||
|
||||
if (
|
||||
!gNetworkLinkService.isLinkUp ||
|
||||
!lazy.gNetworkLinkService.isLinkUp ||
|
||||
this._lastDebounceTimestamp > start ||
|
||||
gCaptivePortalService.state == gCaptivePortalService.LOCKED_PORTAL
|
||||
lazy.gCaptivePortalService.state ==
|
||||
lazy.gCaptivePortalService.LOCKED_PORTAL
|
||||
) {
|
||||
// If the network is currently down or there was a debounce triggered
|
||||
// while we were running heuristics, it means the network fluctuated
|
||||
|
@ -431,17 +445,17 @@ const DoHController = {
|
|||
return;
|
||||
}
|
||||
|
||||
let decision = Object.values(results).includes(Heuristics.DISABLE_DOH)
|
||||
? Heuristics.DISABLE_DOH
|
||||
: Heuristics.ENABLE_DOH;
|
||||
let decision = Object.values(results).includes(lazy.Heuristics.DISABLE_DOH)
|
||||
? lazy.Heuristics.DISABLE_DOH
|
||||
: lazy.Heuristics.ENABLE_DOH;
|
||||
|
||||
let getCaptiveStateString = () => {
|
||||
switch (gCaptivePortalService.state) {
|
||||
case gCaptivePortalService.NOT_CAPTIVE:
|
||||
switch (lazy.gCaptivePortalService.state) {
|
||||
case lazy.gCaptivePortalService.NOT_CAPTIVE:
|
||||
return "not_captive";
|
||||
case gCaptivePortalService.UNLOCKED_PORTAL:
|
||||
case lazy.gCaptivePortalService.UNLOCKED_PORTAL:
|
||||
return "unlocked";
|
||||
case gCaptivePortalService.LOCKED_PORTAL:
|
||||
case lazy.gCaptivePortalService.LOCKED_PORTAL:
|
||||
return "locked";
|
||||
default:
|
||||
return "unknown";
|
||||
|
@ -460,11 +474,11 @@ const DoHController = {
|
|||
};
|
||||
|
||||
if (results.steeredProvider) {
|
||||
gDNSService.setDetectedTrrURI(results.steeredProvider.uri);
|
||||
lazy.gDNSService.setDetectedTrrURI(results.steeredProvider.uri);
|
||||
resultsForTelemetry.steeredProvider = results.steeredProvider.id;
|
||||
}
|
||||
|
||||
if (decision === Heuristics.DISABLE_DOH) {
|
||||
if (decision === lazy.Heuristics.DISABLE_DOH) {
|
||||
await this.setState("disabled");
|
||||
} else {
|
||||
await this.setState("enabled");
|
||||
|
@ -479,7 +493,7 @@ const DoHController = {
|
|||
let platform = [];
|
||||
|
||||
for (let [heuristicName, result] of Object.entries(results)) {
|
||||
if (result !== Heuristics.DISABLE_DOH) {
|
||||
if (result !== lazy.Heuristics.DISABLE_DOH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -515,26 +529,26 @@ const DoHController = {
|
|||
async setState(state) {
|
||||
switch (state) {
|
||||
case "disabled":
|
||||
Preferences.set(ROLLOUT_MODE_PREF, 0);
|
||||
lazy.Preferences.set(ROLLOUT_MODE_PREF, 0);
|
||||
break;
|
||||
case "UIOk":
|
||||
Preferences.set(BREADCRUMB_PREF, true);
|
||||
lazy.Preferences.set(BREADCRUMB_PREF, true);
|
||||
break;
|
||||
case "enabled":
|
||||
Preferences.set(ROLLOUT_MODE_PREF, 2);
|
||||
Preferences.set(BREADCRUMB_PREF, true);
|
||||
lazy.Preferences.set(ROLLOUT_MODE_PREF, 2);
|
||||
lazy.Preferences.set(BREADCRUMB_PREF, true);
|
||||
break;
|
||||
case "policyDisabled":
|
||||
case "manuallyDisabled":
|
||||
case "UIDisabled":
|
||||
Preferences.reset(BREADCRUMB_PREF);
|
||||
lazy.Preferences.reset(BREADCRUMB_PREF);
|
||||
// Fall through.
|
||||
case "rollback":
|
||||
Preferences.reset(ROLLOUT_MODE_PREF);
|
||||
lazy.Preferences.reset(ROLLOUT_MODE_PREF);
|
||||
break;
|
||||
case "shutdown":
|
||||
if (Preferences.get(CLEAR_ON_SHUTDOWN_PREF, true)) {
|
||||
Preferences.reset(ROLLOUT_MODE_PREF);
|
||||
if (lazy.Preferences.get(CLEAR_ON_SHUTDOWN_PREF, true)) {
|
||||
lazy.Preferences.reset(ROLLOUT_MODE_PREF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -557,11 +571,11 @@ const DoHController = {
|
|||
Services.obs.removeObserver(this, kLinkStatusChangedTopic);
|
||||
Services.obs.removeObserver(this, kConnectivityTopic);
|
||||
if (this._debounceTimer) {
|
||||
clearTimeout(this._debounceTimer);
|
||||
lazy.clearTimeout(this._debounceTimer);
|
||||
delete this._debounceTimer;
|
||||
}
|
||||
if (this._throttleTimer) {
|
||||
clearTimeout(this._throttleTimer);
|
||||
lazy.clearTimeout(this._throttleTimer);
|
||||
delete this._throttleTimer;
|
||||
}
|
||||
this._heuristicsAreEnabled = false;
|
||||
|
@ -574,18 +588,18 @@ const DoHController = {
|
|||
async runTRRSelection() {
|
||||
// If persisting the selection is disabled, clear the existing
|
||||
// selection.
|
||||
if (!DoHConfigController.currentConfig.trrSelection.commitResult) {
|
||||
Preferences.reset(ROLLOUT_URI_PREF);
|
||||
if (!lazy.DoHConfigController.currentConfig.trrSelection.commitResult) {
|
||||
lazy.Preferences.reset(ROLLOUT_URI_PREF);
|
||||
}
|
||||
|
||||
if (!DoHConfigController.currentConfig.trrSelection.enabled) {
|
||||
if (!lazy.DoHConfigController.currentConfig.trrSelection.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
Preferences.isSet(ROLLOUT_URI_PREF) &&
|
||||
Preferences.get(ROLLOUT_URI_PREF) ==
|
||||
Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF)
|
||||
lazy.Preferences.isSet(ROLLOUT_URI_PREF) &&
|
||||
lazy.Preferences.get(ROLLOUT_URI_PREF) ==
|
||||
lazy.Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -593,22 +607,22 @@ const DoHController = {
|
|||
await this.runTRRSelectionDryRun();
|
||||
|
||||
// If persisting the selection is disabled, don't commit the value.
|
||||
if (!DoHConfigController.currentConfig.trrSelection.commitResult) {
|
||||
if (!lazy.DoHConfigController.currentConfig.trrSelection.commitResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
Preferences.set(
|
||||
lazy.Preferences.set(
|
||||
ROLLOUT_URI_PREF,
|
||||
Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF)
|
||||
lazy.Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF)
|
||||
);
|
||||
},
|
||||
|
||||
async runTRRSelectionDryRun() {
|
||||
if (Preferences.isSet(TRR_SELECT_DRY_RUN_RESULT_PREF)) {
|
||||
if (lazy.Preferences.isSet(TRR_SELECT_DRY_RUN_RESULT_PREF)) {
|
||||
// Check whether the existing dry-run-result is in the default
|
||||
// list of TRRs. If it is, all good. Else, run the dry run again.
|
||||
let dryRunResult = Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF);
|
||||
let dryRunResultIsValid = DoHConfigController.currentConfig.providerList.some(
|
||||
let dryRunResult = lazy.Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF);
|
||||
let dryRunResultIsValid = lazy.DoHConfigController.currentConfig.providerList.some(
|
||||
trr => trr.uri == dryRunResult
|
||||
);
|
||||
if (dryRunResultIsValid) {
|
||||
|
@ -617,7 +631,7 @@ const DoHController = {
|
|||
}
|
||||
|
||||
let setDryRunResultAndRecordTelemetry = trrUri => {
|
||||
Preferences.set(TRR_SELECT_DRY_RUN_RESULT_PREF, trrUri);
|
||||
lazy.Preferences.set(TRR_SELECT_DRY_RUN_RESULT_PREF, trrUri);
|
||||
Services.telemetry.recordEvent(
|
||||
TRRSELECT_TELEMETRY_CATEGORY,
|
||||
"trrselect",
|
||||
|
@ -626,7 +640,7 @@ const DoHController = {
|
|||
);
|
||||
};
|
||||
|
||||
if (kIsInAutomation) {
|
||||
if (lazy.kIsInAutomation) {
|
||||
// For mochitests, just record telemetry with a dummy result.
|
||||
// TRRPerformance.jsm is tested in xpcshell.
|
||||
setDryRunResultAndRecordTelemetry("https://example.com/dns-query");
|
||||
|
@ -639,7 +653,7 @@ const DoHController = {
|
|||
"resource:///modules/TRRPerformance.jsm"
|
||||
);
|
||||
await new Promise(resolve => {
|
||||
let trrList = DoHConfigController.currentConfig.trrSelection.providerList.map(
|
||||
let trrList = lazy.DoHConfigController.currentConfig.trrSelection.providerList.map(
|
||||
trr => trr.uri
|
||||
);
|
||||
let racer = new TRRRacer(() => {
|
||||
|
@ -661,7 +675,7 @@ const DoHController = {
|
|||
case kPrefChangedTopic:
|
||||
this.onPrefChanged(data);
|
||||
break;
|
||||
case DoHConfigController.kConfigUpdateTopic:
|
||||
case lazy.DoHConfigController.kConfigUpdateTopic:
|
||||
this.reset();
|
||||
break;
|
||||
}
|
||||
|
@ -671,7 +685,7 @@ const DoHController = {
|
|||
switch (pref) {
|
||||
case NETWORK_TRR_URI_PREF:
|
||||
case NETWORK_TRR_MODE_PREF:
|
||||
Preferences.set(DISABLED_PREF, true);
|
||||
lazy.Preferences.set(DISABLED_PREF, true);
|
||||
await this.disableHeuristics("manuallyDisabled");
|
||||
break;
|
||||
}
|
||||
|
@ -687,13 +701,13 @@ const DoHController = {
|
|||
return;
|
||||
}
|
||||
|
||||
clearTimeout(this._debounceTimer);
|
||||
lazy.clearTimeout(this._debounceTimer);
|
||||
this._debounceTimer = null;
|
||||
},
|
||||
|
||||
_lastDebounceTimestamp: 0,
|
||||
onConnectionChanged() {
|
||||
if (!gNetworkLinkService.isLinkUp) {
|
||||
if (!lazy.gNetworkLinkService.isLinkUp) {
|
||||
// Network is down - reset debounce timer.
|
||||
this._cancelDebounce();
|
||||
return;
|
||||
|
@ -704,25 +718,28 @@ const DoHController = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (kNetworkDebounceTimeout < 0) {
|
||||
if (lazy.kNetworkDebounceTimeout < 0) {
|
||||
// Skip debouncing in tests that set timeout to a negative value.
|
||||
this.onConnectionChangedDebounced();
|
||||
return;
|
||||
}
|
||||
|
||||
this._lastDebounceTimestamp = Date.now();
|
||||
this._debounceTimer = setTimeout(() => {
|
||||
this._debounceTimer = lazy.setTimeout(() => {
|
||||
this._cancelDebounce();
|
||||
this.onConnectionChangedDebounced();
|
||||
}, kNetworkDebounceTimeout);
|
||||
}, lazy.kNetworkDebounceTimeout);
|
||||
},
|
||||
|
||||
onConnectionChangedDebounced() {
|
||||
if (!gNetworkLinkService.isLinkUp) {
|
||||
if (!lazy.gNetworkLinkService.isLinkUp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gCaptivePortalService.state == gCaptivePortalService.LOCKED_PORTAL) {
|
||||
if (
|
||||
lazy.gCaptivePortalService.state ==
|
||||
lazy.gCaptivePortalService.LOCKED_PORTAL
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,35 +16,37 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gDNSService",
|
||||
"@mozilla.org/network/dns-service;1",
|
||||
"nsIDNSService"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gNetworkLinkService",
|
||||
"@mozilla.org/network/network-link-service;1",
|
||||
"nsINetworkLinkService"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gParentalControlsService",
|
||||
"@mozilla.org/parental-controls-service;1",
|
||||
"nsIParentalControlsService"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
lazy,
|
||||
"DoHConfigController",
|
||||
"resource:///modules/DoHConfig.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
lazy,
|
||||
"Preferences",
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
|
@ -140,7 +142,7 @@ async function dnsLookup(hostname, resolveCanonicalName = false) {
|
|||
Ci.nsIDNSService.RESOLVE_BYPASS_CACHE |
|
||||
Ci.nsIDNSService.RESOLVE_CANONICAL_NAME;
|
||||
try {
|
||||
request = gDNSService.asyncResolve(
|
||||
request = lazy.gDNSService.asyncResolve(
|
||||
hostname,
|
||||
Ci.nsIDNSService.RESOLVE_TYPE_DEFAULT,
|
||||
dnsFlags,
|
||||
|
@ -201,7 +203,7 @@ async function globalCanary() {
|
|||
|
||||
async function modifiedRoots() {
|
||||
// Check for presence of enterprise_roots cert pref. If enabled, disable DoH
|
||||
let rootsEnabled = Preferences.get(
|
||||
let rootsEnabled = lazy.Preferences.get(
|
||||
"security.enterprise_roots.enabled",
|
||||
false
|
||||
);
|
||||
|
@ -214,7 +216,7 @@ async function modifiedRoots() {
|
|||
}
|
||||
|
||||
async function parentalControls() {
|
||||
if (gParentalControlsService.parentalControlsEnabled) {
|
||||
if (lazy.gParentalControlsService.parentalControlsEnabled) {
|
||||
return "disable_doh";
|
||||
}
|
||||
|
||||
|
@ -338,7 +340,7 @@ async function platform() {
|
|||
|
||||
let indications = Ci.nsINetworkLinkService.NONE_DETECTED;
|
||||
try {
|
||||
let linkService = gNetworkLinkService;
|
||||
let linkService = lazy.gNetworkLinkService;
|
||||
if (Heuristics.mockLinkService) {
|
||||
linkService = Heuristics.mockLinkService;
|
||||
}
|
||||
|
@ -369,7 +371,7 @@ async function platform() {
|
|||
// provider if the check is successful, else null. Currently we only support
|
||||
// this for Comcast networks.
|
||||
async function providerSteering() {
|
||||
if (!DoHConfigController.currentConfig.providerSteering.enabled) {
|
||||
if (!lazy.DoHConfigController.currentConfig.providerSteering.enabled) {
|
||||
return null;
|
||||
}
|
||||
const TEST_DOMAIN = "doh.test.";
|
||||
|
@ -378,7 +380,7 @@ async function providerSteering() {
|
|||
// telemetry, canonicalName is the expected CNAME when looking up doh.test,
|
||||
// and uri is the provider's DoH endpoint.
|
||||
let steeredProviders =
|
||||
DoHConfigController.currentConfig.providerSteering.providerList;
|
||||
lazy.DoHConfigController.currentConfig.providerSteering.providerList;
|
||||
|
||||
if (!steeredProviders || !steeredProviders.length) {
|
||||
return null;
|
||||
|
|
|
@ -6,14 +6,16 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["DoHTestUtils"];
|
||||
|
||||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
lazy,
|
||||
"RemoteSettings",
|
||||
"resource://services-settings/remote-settings.js"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
lazy,
|
||||
"TestUtils",
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
@ -54,7 +56,7 @@ const DoHTestUtils = {
|
|||
async loadRemoteSettingsProviders(providers, waitForConfigFlushes = true) {
|
||||
let configFlushedPromise = this.waitForConfigFlush(waitForConfigFlushes);
|
||||
|
||||
let providerRS = RemoteSettings(kProviderCollectionKey);
|
||||
let providerRS = lazy.RemoteSettings(kProviderCollectionKey);
|
||||
let db = await providerRS.db;
|
||||
await db.importChanges({}, Date.now(), providers, { clear: true });
|
||||
|
||||
|
@ -67,7 +69,7 @@ const DoHTestUtils = {
|
|||
async loadRemoteSettingsConfig(config, waitForConfigFlushes = true) {
|
||||
let configFlushedPromise = this.waitForConfigFlush(waitForConfigFlushes);
|
||||
|
||||
let configRS = RemoteSettings(kConfigCollectionKey);
|
||||
let configRS = lazy.RemoteSettings(kConfigCollectionKey);
|
||||
let db = await configRS.db;
|
||||
await db.importChanges({}, Date.now(), [config]);
|
||||
|
||||
|
@ -100,8 +102,8 @@ const DoHTestUtils = {
|
|||
|
||||
// Clears existing config AND loads defaults.
|
||||
async resetRemoteSettingsConfig(waitForConfigFlushes = true) {
|
||||
let providerRS = RemoteSettings(kProviderCollectionKey);
|
||||
let configRS = RemoteSettings(kConfigCollectionKey);
|
||||
let providerRS = lazy.RemoteSettings(kProviderCollectionKey);
|
||||
let configRS = lazy.RemoteSettings(kConfigCollectionKey);
|
||||
for (let rs of [providerRS, configRS]) {
|
||||
let configFlushedPromise = this.waitForConfigFlush(waitForConfigFlushes);
|
||||
await rs.db.importChanges({}, Date.now(), [], { clear: true });
|
||||
|
@ -122,11 +124,11 @@ const DoHTestUtils = {
|
|||
},
|
||||
|
||||
waitForConfigUpdate() {
|
||||
return TestUtils.topicObserved(kConfigUpdateTopic);
|
||||
return lazy.TestUtils.topicObserved(kConfigUpdateTopic);
|
||||
},
|
||||
|
||||
waitForControllerReload() {
|
||||
return TestUtils.topicObserved(kControllerReloadedTopic);
|
||||
return lazy.TestUtils.topicObserved(kControllerReloadedTopic);
|
||||
},
|
||||
|
||||
waitForConfigFlush(shouldWait = true) {
|
||||
|
|
|
@ -30,22 +30,24 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gNetworkLinkService",
|
||||
"@mozilla.org/network/network-link-service;1",
|
||||
"nsINetworkLinkService"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gCaptivePortalService",
|
||||
"@mozilla.org/network/captive-portal-service;1",
|
||||
"nsICaptivePortalService"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gDNSService",
|
||||
"@mozilla.org/network/dns-service;1",
|
||||
"nsIDNSService"
|
||||
|
@ -53,7 +55,7 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
|
||||
// The canonical domain whose subdomains we will be resolving.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"kCanonicalDomain",
|
||||
"doh-rollout.trrRace.canonicalDomain",
|
||||
"firefox-dns-perf-test.net."
|
||||
|
@ -61,7 +63,7 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||
|
||||
// The number of random subdomains to resolve per TRR.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"kRepeats",
|
||||
"doh-rollout.trrRace.randomSubdomainCount",
|
||||
5
|
||||
|
@ -69,7 +71,7 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||
|
||||
// The "popular" domain that we expect the TRRs to have cached.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"kPopularDomains",
|
||||
"doh-rollout.trrRace.popularDomains",
|
||||
null,
|
||||
|
@ -91,7 +93,7 @@ function getRandomSubdomain() {
|
|||
.generateUUID()
|
||||
.toString()
|
||||
.slice(1, -1); // Discard surrounding braces
|
||||
return `${uuid}.${kCanonicalDomain}`;
|
||||
return `${uuid}.${lazy.kCanonicalDomain}`;
|
||||
}
|
||||
|
||||
// A wrapper around async DNS lookups. The results are passed on to the supplied
|
||||
|
@ -110,11 +112,11 @@ class DNSLookup {
|
|||
this.retryCount++;
|
||||
try {
|
||||
this.usedDomain = this._domain || getRandomSubdomain();
|
||||
gDNSService.asyncResolve(
|
||||
lazy.gDNSService.asyncResolve(
|
||||
this.usedDomain,
|
||||
Ci.nsIDNSService.RESOLVE_TYPE_DEFAULT,
|
||||
Ci.nsIDNSService.RESOLVE_BYPASS_CACHE,
|
||||
gDNSService.newAdditionalInfo(this.trrServer, -1),
|
||||
lazy.gDNSService.newAdditionalInfo(this.trrServer, -1),
|
||||
this,
|
||||
Services.tm.currentThread,
|
||||
{}
|
||||
|
@ -150,11 +152,11 @@ class LookupAggregator {
|
|||
this.captivePortal = false;
|
||||
|
||||
this.domains = [];
|
||||
for (let i = 0; i < kRepeats; ++i) {
|
||||
for (let i = 0; i < lazy.kRepeats; ++i) {
|
||||
// false-y domain will cause DNSLookup to generate a random one.
|
||||
this.domains.push(null);
|
||||
}
|
||||
this.domains.push(...kPopularDomains);
|
||||
this.domains.push(...lazy.kPopularDomains);
|
||||
this.totalLookups = this.trrList.length * this.domains.length;
|
||||
this.completedLookups = 0;
|
||||
this.results = [];
|
||||
|
@ -213,7 +215,10 @@ class LookupAggregator {
|
|||
|
||||
for (let { domain, trr, status, time, retryCount } of this.results) {
|
||||
if (
|
||||
!(kPopularDomains.includes(domain) || domain.includes(kCanonicalDomain))
|
||||
!(
|
||||
lazy.kPopularDomains.includes(domain) ||
|
||||
domain.includes(lazy.kCanonicalDomain)
|
||||
)
|
||||
) {
|
||||
Cu.reportError("Expected known domain for reporting, got " + domain);
|
||||
return;
|
||||
|
@ -255,12 +260,14 @@ class TRRRacer {
|
|||
|
||||
run() {
|
||||
if (
|
||||
gNetworkLinkService.isLinkUp &&
|
||||
gCaptivePortalService.state != gCaptivePortalService.LOCKED_PORTAL
|
||||
lazy.gNetworkLinkService.isLinkUp &&
|
||||
lazy.gCaptivePortalService.state !=
|
||||
lazy.gCaptivePortalService.LOCKED_PORTAL
|
||||
) {
|
||||
this._runNewAggregator();
|
||||
if (
|
||||
gCaptivePortalService.state == gCaptivePortalService.UNLOCKED_PORTAL
|
||||
lazy.gCaptivePortalService.state ==
|
||||
lazy.gCaptivePortalService.UNLOCKED_PORTAL
|
||||
) {
|
||||
this._aggregator.markCaptivePortal();
|
||||
}
|
||||
|
@ -385,7 +392,8 @@ class TRRRacer {
|
|||
case "ipc:network:captive-portal-set-state":
|
||||
if (
|
||||
this._aggregator &&
|
||||
gCaptivePortalService.state == gCaptivePortalService.LOCKED_PORTAL
|
||||
lazy.gCaptivePortalService.state ==
|
||||
lazy.gCaptivePortalService.LOCKED_PORTAL
|
||||
) {
|
||||
if (this._retryCount < 5) {
|
||||
this._aggregator.abort();
|
||||
|
@ -393,8 +401,8 @@ class TRRRacer {
|
|||
this._aggregator.markCaptivePortal();
|
||||
}
|
||||
} else if (
|
||||
gCaptivePortalService.state ==
|
||||
gCaptivePortalService.UNLOCKED_PORTAL &&
|
||||
lazy.gCaptivePortalService.state ==
|
||||
lazy.gCaptivePortalService.UNLOCKED_PORTAL &&
|
||||
(!this._aggregator || this._aggregator.aborted)
|
||||
) {
|
||||
this._runNewAggregator();
|
||||
|
|
|
@ -18,7 +18,9 @@ var { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
Downloads: "resource://gre/modules/Downloads.jsm",
|
||||
DownloadsCommon: "resource:///modules/DownloadsCommon.jsm",
|
||||
|
@ -36,9 +38,9 @@ class DownloadSpamProtection {
|
|||
* @type {Map<string, DownloadSpam>}
|
||||
*/
|
||||
this._blockedURLToDownloadSpam = new Map();
|
||||
this._browserWin = BrowserWindowTracker.getTopWindow();
|
||||
this._indicator = DownloadsCommon.getIndicatorData(this._browserWin);
|
||||
this.list = new DownloadList();
|
||||
this._browserWin = lazy.BrowserWindowTracker.getTopWindow();
|
||||
this._indicator = lazy.DownloadsCommon.getIndicatorData(this._browserWin);
|
||||
this.list = new lazy.DownloadList();
|
||||
}
|
||||
|
||||
get spamList() {
|
||||
|
@ -58,7 +60,7 @@ class DownloadSpamProtection {
|
|||
let downloadSpam = new DownloadSpam(url);
|
||||
this.spamList.add(downloadSpam);
|
||||
this._blockedURLToDownloadSpam.set(url, downloadSpam);
|
||||
let hasActiveDownloads = DownloadsCommon.summarizeDownloads(
|
||||
let hasActiveDownloads = lazy.DownloadsCommon.summarizeDownloads(
|
||||
this._indicator._activeDownloads()
|
||||
).numDownloading;
|
||||
if (!hasActiveDownloads) {
|
||||
|
@ -91,7 +93,7 @@ class DownloadSpam extends Download {
|
|||
this.stopped = true;
|
||||
this.error = new DownloadError({
|
||||
becauseBlockedByReputationCheck: true,
|
||||
reputationCheckVerdict: Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM,
|
||||
reputationCheckVerdict: lazy.Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM,
|
||||
});
|
||||
this.target = { path: "" };
|
||||
this.source = { url };
|
||||
|
|
|
@ -35,7 +35,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
NetUtil: "resource://gre/modules/NetUtil.jsm",
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
DownloadHistory: "resource://gre/modules/DownloadHistory.jsm",
|
||||
|
@ -45,7 +47,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||
XPCOMUtils.defineLazyServiceGetters(lazy, {
|
||||
gClipboardHelper: [
|
||||
"@mozilla.org/widget/clipboardhelper;1",
|
||||
"nsIClipboardHelper",
|
||||
|
@ -53,7 +55,7 @@ XPCOMUtils.defineLazyServiceGetters(this, {
|
|||
gMIMEService: ["@mozilla.org/mime;1", "nsIMIMEService"],
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DownloadsLogger", () => {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "DownloadsLogger", () => {
|
||||
let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm");
|
||||
let consoleOptions = {
|
||||
maxLogLevelPref: "browser.download.loglevel",
|
||||
|
@ -63,7 +65,7 @@ XPCOMUtils.defineLazyGetter(this, "DownloadsLogger", () => {
|
|||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gAlwaysOpenPanel",
|
||||
"browser.download.alwaysOpenPanel",
|
||||
true
|
||||
|
@ -228,17 +230,19 @@ var DownloadsCommon = {
|
|||
*/
|
||||
getData(window, history = false, privateAll = false, limited = false) {
|
||||
let isPrivate =
|
||||
window && PrivateBrowsingUtils.isContentWindowPrivate(window);
|
||||
window && lazy.PrivateBrowsingUtils.isContentWindowPrivate(window);
|
||||
if (isPrivate && !privateAll) {
|
||||
return PrivateDownloadsData;
|
||||
return lazy.PrivateDownloadsData;
|
||||
}
|
||||
if (history) {
|
||||
if (isPrivate && privateAll) {
|
||||
return LimitedPrivateHistoryDownloadData;
|
||||
return lazy.LimitedPrivateHistoryDownloadData;
|
||||
}
|
||||
return limited ? LimitedHistoryDownloadsData : HistoryDownloadsData;
|
||||
return limited
|
||||
? lazy.LimitedHistoryDownloadsData
|
||||
: lazy.HistoryDownloadsData;
|
||||
}
|
||||
return DownloadsData;
|
||||
return lazy.DownloadsData;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -246,8 +250,8 @@ var DownloadsCommon = {
|
|||
* private and non-private downloads data objects.
|
||||
*/
|
||||
initializeAllDataLinks() {
|
||||
DownloadsData.initializeDataLink();
|
||||
PrivateDownloadsData.initializeDataLink();
|
||||
lazy.DownloadsData.initializeDataLink();
|
||||
lazy.PrivateDownloadsData.initializeDataLink();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -256,10 +260,10 @@ var DownloadsCommon = {
|
|||
* the window in question.
|
||||
*/
|
||||
getIndicatorData(aWindow) {
|
||||
if (PrivateBrowsingUtils.isContentWindowPrivate(aWindow)) {
|
||||
return PrivateDownloadsIndicatorData;
|
||||
if (lazy.PrivateBrowsingUtils.isContentWindowPrivate(aWindow)) {
|
||||
return lazy.PrivateDownloadsIndicatorData;
|
||||
}
|
||||
return DownloadsIndicatorData;
|
||||
return lazy.DownloadsIndicatorData;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -273,7 +277,7 @@ var DownloadsCommon = {
|
|||
* from the summary.
|
||||
*/
|
||||
getSummary(aWindow, aNumToExclude) {
|
||||
if (PrivateBrowsingUtils.isContentWindowPrivate(aWindow)) {
|
||||
if (lazy.PrivateBrowsingUtils.isContentWindowPrivate(aWindow)) {
|
||||
if (this._privateSummary) {
|
||||
return this._privateSummary;
|
||||
}
|
||||
|
@ -338,11 +342,11 @@ var DownloadsCommon = {
|
|||
// that combine history and session downloads won't resurrect the history
|
||||
// download into the view just before it is deleted permanently.
|
||||
try {
|
||||
await PlacesUtils.history.remove(download.source.url);
|
||||
await lazy.PlacesUtils.history.remove(download.source.url);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
let list = await Downloads.getList(Downloads.ALL);
|
||||
let list = await lazy.Downloads.getList(lazy.Downloads.ALL);
|
||||
await list.remove(download);
|
||||
await download.finalize(true);
|
||||
},
|
||||
|
@ -362,18 +366,18 @@ var DownloadsCommon = {
|
|||
async deleteDownloadFiles(download, clearHistory = 0) {
|
||||
if (clearHistory > 1) {
|
||||
try {
|
||||
await PlacesUtils.history.remove(download.source.url);
|
||||
await lazy.PlacesUtils.history.remove(download.source.url);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
if (clearHistory > 0) {
|
||||
let list = await Downloads.getList(Downloads.ALL);
|
||||
let list = await lazy.Downloads.getList(lazy.Downloads.ALL);
|
||||
await list.remove(download);
|
||||
}
|
||||
await download.manuallyRemoveData();
|
||||
if (clearHistory < 2) {
|
||||
DownloadHistory.updateMetaData(download).catch(Cu.reportError);
|
||||
lazy.DownloadHistory.updateMetaData(download).catch(Cu.reportError);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -396,7 +400,7 @@ var DownloadsCommon = {
|
|||
// look at file extension if there's no contentType or it is generic
|
||||
if (!contentType || kGenericContentTypes.includes(contentType)) {
|
||||
try {
|
||||
contentType = gMIMEService.getTypeFromExtension(fileExtension);
|
||||
contentType = lazy.gMIMEService.getTypeFromExtension(fileExtension);
|
||||
} catch (ex) {
|
||||
DownloadsCommon.log(
|
||||
"Cant get mimeType from file extension: ",
|
||||
|
@ -409,7 +413,7 @@ var DownloadsCommon = {
|
|||
}
|
||||
let mimeInfo = null;
|
||||
try {
|
||||
mimeInfo = gMIMEService.getFromTypeAndExtension(
|
||||
mimeInfo = lazy.gMIMEService.getFromTypeAndExtension(
|
||||
contentType || "",
|
||||
fileExtension || ""
|
||||
);
|
||||
|
@ -442,7 +446,7 @@ var DownloadsCommon = {
|
|||
* Copies the source URI of the given Download object to the clipboard.
|
||||
*/
|
||||
copyDownloadLink(download) {
|
||||
gClipboardHelper.copyString(
|
||||
lazy.gClipboardHelper.copyString(
|
||||
download.source.originalUrl || download.source.url
|
||||
);
|
||||
},
|
||||
|
@ -578,7 +582,7 @@ var DownloadsCommon = {
|
|||
async openDownload(download, options) {
|
||||
// some download objects got serialized and need reconstituting
|
||||
if (typeof download.launch !== "function") {
|
||||
download = await Downloads.createDownload(download);
|
||||
download = await lazy.Downloads.createDownload(download);
|
||||
}
|
||||
return download.launch(options).catch(ex => Cu.reportError(ex));
|
||||
},
|
||||
|
@ -624,7 +628,7 @@ var DownloadsCommon = {
|
|||
Cc["@mozilla.org/uriloader/external-protocol-service;1"]
|
||||
.getService(Ci.nsIExternalProtocolService)
|
||||
.loadURI(
|
||||
NetUtil.newURI(aDirectory),
|
||||
lazy.NetUtil.newURI(aDirectory),
|
||||
Services.scriptSecurityManager.getSystemPrincipal()
|
||||
);
|
||||
}
|
||||
|
@ -699,13 +703,13 @@ var DownloadsCommon = {
|
|||
|
||||
let message;
|
||||
switch (verdict) {
|
||||
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
message = s.unblockTypeUncommon2;
|
||||
break;
|
||||
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
message = s.unblockTypePotentiallyUnwanted2;
|
||||
break;
|
||||
case Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
message = s.unblockInsecure;
|
||||
break;
|
||||
default:
|
||||
|
@ -755,10 +759,10 @@ var DownloadsCommon = {
|
|||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(DownloadsCommon, "log", () => {
|
||||
return DownloadsLogger.log.bind(DownloadsLogger);
|
||||
return lazy.DownloadsLogger.log.bind(lazy.DownloadsLogger);
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(DownloadsCommon, "error", () => {
|
||||
return DownloadsLogger.error.bind(DownloadsLogger);
|
||||
return lazy.DownloadsLogger.error.bind(lazy.DownloadsLogger);
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -799,14 +803,14 @@ function DownloadsDataCtor({ isPrivate, isHistory, maxHistoryResults } = {}) {
|
|||
// allowing the endTime property to be set correctly.
|
||||
if (isHistory) {
|
||||
if (isPrivate) {
|
||||
PrivateDownloadsData.initializeDataLink();
|
||||
lazy.PrivateDownloadsData.initializeDataLink();
|
||||
}
|
||||
DownloadsData.initializeDataLink();
|
||||
this._promiseList = DownloadsData._promiseList.then(() => {
|
||||
lazy.DownloadsData.initializeDataLink();
|
||||
this._promiseList = lazy.DownloadsData._promiseList.then(() => {
|
||||
// For history downloads in Private Browsing mode, we'll fetch the combined
|
||||
// list of public and private downloads.
|
||||
return DownloadHistory.getList({
|
||||
type: isPrivate ? Downloads.ALL : Downloads.PUBLIC,
|
||||
return lazy.DownloadHistory.getList({
|
||||
type: isPrivate ? lazy.Downloads.ALL : lazy.Downloads.PUBLIC,
|
||||
maxHistoryResults,
|
||||
});
|
||||
});
|
||||
|
@ -818,8 +822,8 @@ function DownloadsDataCtor({ isPrivate, isHistory, maxHistoryResults } = {}) {
|
|||
// underlying data to be loaded only when actually needed.
|
||||
this._promiseList = (async () => {
|
||||
await new Promise(resolve => (this.initializeDataLink = resolve));
|
||||
let list = await Downloads.getList(
|
||||
isPrivate ? Downloads.PRIVATE : Downloads.PUBLIC
|
||||
let list = await lazy.Downloads.getList(
|
||||
isPrivate ? lazy.Downloads.PRIVATE : lazy.Downloads.PUBLIC
|
||||
);
|
||||
await list.addView(this);
|
||||
return list;
|
||||
|
@ -864,7 +868,9 @@ DownloadsDataCtor.prototype = {
|
|||
* is only called after the data link has been initialized.
|
||||
*/
|
||||
removeFinished() {
|
||||
Downloads.getList(this._isPrivate ? Downloads.PRIVATE : Downloads.PUBLIC)
|
||||
lazy.Downloads.getList(
|
||||
this._isPrivate ? lazy.Downloads.PRIVATE : lazy.Downloads.PUBLIC
|
||||
)
|
||||
.then(list => list.removeFinished())
|
||||
.catch(Cu.reportError);
|
||||
},
|
||||
|
@ -903,7 +909,7 @@ DownloadsDataCtor.prototype = {
|
|||
|
||||
// This state transition code should actually be located in a Downloads
|
||||
// API module (bug 941009).
|
||||
DownloadHistory.updateMetaData(download).catch(Cu.reportError);
|
||||
lazy.DownloadHistory.updateMetaData(download).catch(Cu.reportError);
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -986,7 +992,7 @@ DownloadsDataCtor.prototype = {
|
|||
);
|
||||
|
||||
// Show the panel in the most recent browser window, if present.
|
||||
let browserWin = BrowserWindowTracker.getTopWindow({
|
||||
let browserWin = lazy.BrowserWindowTracker.getTopWindow({
|
||||
private: this._isPrivate,
|
||||
});
|
||||
if (!browserWin) {
|
||||
|
@ -1001,7 +1007,7 @@ DownloadsDataCtor.prototype = {
|
|||
) &&
|
||||
DownloadsCommon.summarizeDownloads(this._downloads).numDownloading <= 1 &&
|
||||
browserWin == Services.focus.activeWindow &&
|
||||
gAlwaysOpenPanel;
|
||||
lazy.gAlwaysOpenPanel;
|
||||
|
||||
if (
|
||||
this.panelHasShownBefore &&
|
||||
|
@ -1020,11 +1026,11 @@ DownloadsDataCtor.prototype = {
|
|||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "HistoryDownloadsData", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "HistoryDownloadsData", function() {
|
||||
return new DownloadsDataCtor({ isHistory: true });
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "LimitedHistoryDownloadsData", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "LimitedHistoryDownloadsData", function() {
|
||||
return new DownloadsDataCtor({
|
||||
isHistory: true,
|
||||
maxHistoryResults: kMaxHistoryResultsForLimitedView,
|
||||
|
@ -1032,7 +1038,7 @@ XPCOMUtils.defineLazyGetter(this, "LimitedHistoryDownloadsData", function() {
|
|||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this,
|
||||
lazy,
|
||||
"LimitedPrivateHistoryDownloadData",
|
||||
function() {
|
||||
return new DownloadsDataCtor({
|
||||
|
@ -1043,11 +1049,11 @@ XPCOMUtils.defineLazyGetter(
|
|||
}
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "PrivateDownloadsData", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "PrivateDownloadsData", function() {
|
||||
return new DownloadsDataCtor({ isPrivate: true });
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DownloadsData", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "DownloadsData", function() {
|
||||
return new DownloadsDataCtor();
|
||||
});
|
||||
|
||||
|
@ -1095,9 +1101,9 @@ const DownloadsViewPrototype = {
|
|||
// Start receiving events when the first of our views is registered.
|
||||
if (!this._views.length) {
|
||||
if (this._isPrivate) {
|
||||
PrivateDownloadsData.addView(this);
|
||||
lazy.PrivateDownloadsData.addView(this);
|
||||
} else {
|
||||
DownloadsData.addView(this);
|
||||
lazy.DownloadsData.addView(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1133,9 +1139,9 @@ const DownloadsViewPrototype = {
|
|||
// Stop receiving events when the last of our views is unregistered.
|
||||
if (!this._views.length) {
|
||||
if (this._isPrivate) {
|
||||
PrivateDownloadsData.removeView(this);
|
||||
lazy.PrivateDownloadsData.removeView(this);
|
||||
} else {
|
||||
DownloadsData.removeView(this);
|
||||
lazy.DownloadsData.removeView(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1328,15 +1334,15 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
download.error.reputationCheckVerdict
|
||||
) {
|
||||
switch (download.error.reputationCheckVerdict) {
|
||||
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
attention = DownloadsCommon.ATTENTION_INFO;
|
||||
break;
|
||||
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED: // fall-through
|
||||
case Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
case Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED: // fall-through
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM:
|
||||
attention = DownloadsCommon.ATTENTION_WARNING;
|
||||
break;
|
||||
case Downloads.Error.BLOCK_VERDICT_MALWARE:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_MALWARE:
|
||||
attention = DownloadsCommon.ATTENTION_SEVERE;
|
||||
break;
|
||||
default:
|
||||
|
@ -1449,8 +1455,8 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
*/
|
||||
*_activeDownloads() {
|
||||
let downloads = this._isPrivate
|
||||
? PrivateDownloadsData._downloads
|
||||
: DownloadsData._downloads;
|
||||
? lazy.PrivateDownloadsData._downloads
|
||||
: lazy.DownloadsData._downloads;
|
||||
for (let download of downloads) {
|
||||
if (!download.stopped || (download.canceled && download.hasPartialData)) {
|
||||
yield download;
|
||||
|
@ -1478,11 +1484,11 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "PrivateDownloadsIndicatorData", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "PrivateDownloadsIndicatorData", function() {
|
||||
return new DownloadsIndicatorDataCtor(true);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DownloadsIndicatorData", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "DownloadsIndicatorData", function() {
|
||||
return new DownloadsIndicatorDataCtor(false);
|
||||
});
|
||||
|
||||
|
@ -1648,7 +1654,7 @@ DownloadsSummaryData.prototype = {
|
|||
this._lastTimeLeft
|
||||
);
|
||||
}
|
||||
[this._details] = DownloadUtils.getDownloadStatusNoRate(
|
||||
[this._details] = lazy.DownloadUtils.getDownloadStatusNoRate(
|
||||
summary.totalTransferred,
|
||||
summary.totalSize,
|
||||
summary.slowestSpeed,
|
||||
|
|
|
@ -16,7 +16,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
Downloads: "resource://gre/modules/Downloads.jsm",
|
||||
});
|
||||
|
||||
|
@ -34,7 +36,9 @@ var DownloadsMacFinderProgress = {
|
|||
// Ensure to register only once per process and not for every window.
|
||||
if (!this._finderProgresses) {
|
||||
this._finderProgresses = new Map();
|
||||
Downloads.getList(Downloads.ALL).then(list => list.addView(this));
|
||||
lazy.Downloads.getList(lazy.Downloads.ALL).then(list =>
|
||||
list.addView(this)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -18,12 +18,13 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
Downloads: "resource://gre/modules/Downloads.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gWinTaskbar", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "gWinTaskbar", function() {
|
||||
if (!("@mozilla.org/windows-taskbar;1" in Cc)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -33,14 +34,14 @@ XPCOMUtils.defineLazyGetter(this, "gWinTaskbar", function() {
|
|||
return winTaskbar.available && winTaskbar;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gMacTaskbarProgress", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "gMacTaskbarProgress", function() {
|
||||
return (
|
||||
"@mozilla.org/widget/macdocksupport;1" in Cc &&
|
||||
Cc["@mozilla.org/widget/macdocksupport;1"].getService(Ci.nsITaskbarProgress)
|
||||
);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gGtkTaskbarProgress", function() {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "gGtkTaskbarProgress", function() {
|
||||
return (
|
||||
"@mozilla.org/widget/taskbarprogress/gtk;1" in Cc &&
|
||||
Cc["@mozilla.org/widget/taskbarprogress/gtk;1"].getService(
|
||||
|
@ -86,20 +87,20 @@ var DownloadsTaskbar = {
|
|||
*/
|
||||
registerIndicator(aBrowserWindow) {
|
||||
if (!this._taskbarProgress) {
|
||||
if (gMacTaskbarProgress) {
|
||||
if (lazy.gMacTaskbarProgress) {
|
||||
// On Mac OS X, we have to register the global indicator only once.
|
||||
this._taskbarProgress = gMacTaskbarProgress;
|
||||
this._taskbarProgress = lazy.gMacTaskbarProgress;
|
||||
// Free the XPCOM reference on shutdown, to prevent detecting a leak.
|
||||
Services.obs.addObserver(() => {
|
||||
this._taskbarProgress = null;
|
||||
gMacTaskbarProgress = null;
|
||||
lazy.gMacTaskbarProgress = null;
|
||||
}, "quit-application-granted");
|
||||
} else if (gWinTaskbar) {
|
||||
} else if (lazy.gWinTaskbar) {
|
||||
// On Windows, the indicator is currently hidden because we have no
|
||||
// previous browser window, thus we should attach the indicator now.
|
||||
this._attachIndicator(aBrowserWindow);
|
||||
} else if (gGtkTaskbarProgress) {
|
||||
this._taskbarProgress = gGtkTaskbarProgress;
|
||||
} else if (lazy.gGtkTaskbarProgress) {
|
||||
this._taskbarProgress = lazy.gGtkTaskbarProgress;
|
||||
|
||||
this._attachGtkTaskbarProgress(aBrowserWindow);
|
||||
} else {
|
||||
|
@ -110,7 +111,7 @@ var DownloadsTaskbar = {
|
|||
|
||||
// Ensure that the DownloadSummary object will be created asynchronously.
|
||||
if (!this._summary) {
|
||||
Downloads.getSummary(Downloads.ALL)
|
||||
lazy.Downloads.getSummary(lazy.Downloads.ALL)
|
||||
.then(summary => {
|
||||
// In case the method is re-entered, we simply ignore redundant
|
||||
// invocations of the callback, instead of keeping separate state.
|
||||
|
@ -130,7 +131,7 @@ var DownloadsTaskbar = {
|
|||
_attachIndicator(aWindow) {
|
||||
// Activate the indicator on the specified window.
|
||||
let { docShell } = aWindow.browsingContext.topChromeWindow;
|
||||
this._taskbarProgress = gWinTaskbar.getTaskbarProgress(docShell);
|
||||
this._taskbarProgress = lazy.gWinTaskbar.getTaskbarProgress(docShell);
|
||||
|
||||
// If the DownloadSummary object has already been created, we should update
|
||||
// the state of the new indicator, otherwise it will be updated as soon as
|
||||
|
@ -141,7 +142,7 @@ var DownloadsTaskbar = {
|
|||
|
||||
aWindow.addEventListener("unload", () => {
|
||||
// Locate another browser window, excluding the one being closed.
|
||||
let browserWindow = BrowserWindowTracker.getTopWindow();
|
||||
let browserWindow = lazy.BrowserWindowTracker.getTopWindow();
|
||||
if (browserWindow) {
|
||||
// Move the progress indicator to the other browser window.
|
||||
this._attachIndicator(browserWindow);
|
||||
|
@ -170,7 +171,7 @@ var DownloadsTaskbar = {
|
|||
|
||||
aWindow.addEventListener("unload", () => {
|
||||
// Locate another browser window, excluding the one being closed.
|
||||
let browserWindow = BrowserWindowTracker.getTopWindow();
|
||||
let browserWindow = lazy.BrowserWindowTracker.getTopWindow();
|
||||
if (browserWindow) {
|
||||
// Move the progress indicator to the other browser window.
|
||||
this._attachGtkTaskbarProgress(browserWindow);
|
||||
|
|
|
@ -15,7 +15,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
Downloads: "resource://gre/modules/Downloads.jsm",
|
||||
DownloadUtils: "resource://gre/modules/DownloadUtils.jsm",
|
||||
|
@ -25,14 +27,14 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"handlerSvc",
|
||||
"@mozilla.org/uriloader/handler-service;1",
|
||||
"nsIHandlerService"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"gReputationService",
|
||||
"@mozilla.org/reputationservice/application-reputation-service;1",
|
||||
Ci.nsIApplicationReputationService
|
||||
|
@ -42,9 +44,8 @@ const { Integration } = ChromeUtils.import(
|
|||
"resource://gre/modules/Integration.jsm"
|
||||
);
|
||||
|
||||
/* global DownloadIntegration */
|
||||
Integration.downloads.defineModuleGetter(
|
||||
this,
|
||||
lazy,
|
||||
"DownloadIntegration",
|
||||
"resource://gre/modules/DownloadIntegration.jsm"
|
||||
);
|
||||
|
@ -121,7 +122,7 @@ var DownloadsViewUI = {
|
|||
* Get source url of the download without'http' or'https' prefix.
|
||||
*/
|
||||
getStrippedUrl(download) {
|
||||
return UrlbarUtils.stripPrefixAndTrim(download?.source?.url, {
|
||||
return lazy.UrlbarUtils.stripPrefixAndTrim(download?.source?.url, {
|
||||
stripHttp: true,
|
||||
stripHttps: true,
|
||||
})[0];
|
||||
|
@ -136,7 +137,7 @@ var DownloadsViewUI = {
|
|||
getDisplayName(download) {
|
||||
if (
|
||||
download.error?.reputationCheckVerdict ==
|
||||
Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM
|
||||
lazy.Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM
|
||||
) {
|
||||
let l10n = {
|
||||
id: "downloads-blocked-from-url",
|
||||
|
@ -159,8 +160,10 @@ var DownloadsViewUI = {
|
|||
return "";
|
||||
}
|
||||
|
||||
let [size, unit] = DownloadUtils.convertByteUnits(download.target.size);
|
||||
return DownloadsCommon.strings.sizeWithUnits(size, unit);
|
||||
let [size, unit] = lazy.DownloadUtils.convertByteUnits(
|
||||
download.target.size
|
||||
);
|
||||
return lazy.DownloadsCommon.strings.sizeWithUnits(size, unit);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -184,7 +187,7 @@ var DownloadsViewUI = {
|
|||
DOWNLOAD_BLOCKED_PARENTAL,
|
||||
DOWNLOAD_DIRTY,
|
||||
DOWNLOAD_BLOCKED_POLICY,
|
||||
} = DownloadsCommon;
|
||||
} = lazy.DownloadsCommon;
|
||||
|
||||
contextMenu.querySelector(".downloadPauseMenuItem").hidden =
|
||||
state != DOWNLOAD_DOWNLOADING;
|
||||
|
@ -224,7 +227,7 @@ var DownloadsViewUI = {
|
|||
contextMenu.querySelector(".downloadShowMenuItem").hidden;
|
||||
|
||||
let download = element._shell.download;
|
||||
let mimeInfo = DownloadsCommon.getMimeInfo(download);
|
||||
let mimeInfo = lazy.DownloadsCommon.getMimeInfo(download);
|
||||
let { preferredAction, useSystemDefault, defaultDescription } = mimeInfo
|
||||
? mimeInfo
|
||||
: {};
|
||||
|
@ -251,12 +254,12 @@ var DownloadsViewUI = {
|
|||
);
|
||||
let canViewInternally = element.hasAttribute("viewable-internally");
|
||||
useSystemViewerItem.hidden =
|
||||
!DownloadsCommon.openInSystemViewerItemEnabled ||
|
||||
!lazy.DownloadsCommon.openInSystemViewerItemEnabled ||
|
||||
!canViewInternally ||
|
||||
!download.target?.exists;
|
||||
|
||||
alwaysUseSystemViewerItem.hidden =
|
||||
!DownloadsCommon.alwaysOpenInSystemViewerItemEnabled ||
|
||||
!lazy.DownloadsCommon.alwaysOpenInSystemViewerItemEnabled ||
|
||||
!canViewInternally;
|
||||
|
||||
// Set menuitem labels to display the system viewer's name. Stop the l10n
|
||||
|
@ -325,11 +328,11 @@ var DownloadsViewUI = {
|
|||
mimeInfo.type === "application/octet-stream" ||
|
||||
mimeInfo.type === "application/x-msdownload" ||
|
||||
mimeInfo.type === "application/x-msdos-program" ||
|
||||
gReputationService.isExecutable(
|
||||
lazy.gReputationService.isExecutable(
|
||||
PathUtils.filename(download.target.path)
|
||||
) ||
|
||||
(mimeInfo.type === "text/plain" &&
|
||||
gReputationService.isBinary(download.target.path));
|
||||
lazy.gReputationService.isBinary(download.target.path));
|
||||
|
||||
if (DownloadsViewUI.improvementsIsOn && !canViewInternally) {
|
||||
alwaysOpenSimilarFilesItem.hidden =
|
||||
|
@ -499,7 +502,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
},
|
||||
|
||||
get browserWindow() {
|
||||
return BrowserWindowTracker.getTopWindow();
|
||||
return lazy.BrowserWindowTracker.getTopWindow();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -605,16 +608,16 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
this.showStatus(stateLabel, hoverStatus);
|
||||
return;
|
||||
}
|
||||
let [displayHost] = DownloadUtils.getURIHost(this.download.source.url);
|
||||
let [displayDate] = DownloadUtils.getReadableDates(
|
||||
let [displayHost] = lazy.DownloadUtils.getURIHost(this.download.source.url);
|
||||
let [displayDate] = lazy.DownloadUtils.getReadableDates(
|
||||
new Date(this.download.endTime)
|
||||
);
|
||||
|
||||
let firstPart = DownloadsCommon.strings.statusSeparator(
|
||||
let firstPart = lazy.DownloadsCommon.strings.statusSeparator(
|
||||
stateLabel,
|
||||
displayHost
|
||||
);
|
||||
let fullStatus = DownloadsCommon.strings.statusSeparator(
|
||||
let fullStatus = lazy.DownloadsCommon.strings.statusSeparator(
|
||||
firstPart,
|
||||
displayDate
|
||||
);
|
||||
|
@ -672,7 +675,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
);
|
||||
this.element.setAttribute(
|
||||
"state",
|
||||
DownloadsCommon.stateOfDownload(this.download)
|
||||
lazy.DownloadsCommon.stateOfDownload(this.download)
|
||||
);
|
||||
|
||||
if (!this.download.stopped) {
|
||||
|
@ -713,7 +716,10 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
let totalBytes = this.download.hasProgress
|
||||
? this.download.totalBytes
|
||||
: -1;
|
||||
let [status, newEstimatedSecondsLeft] = DownloadUtils.getDownloadStatus(
|
||||
let [
|
||||
status,
|
||||
newEstimatedSecondsLeft,
|
||||
] = lazy.DownloadUtils.getDownloadStatus(
|
||||
this.download.currentBytes,
|
||||
totalBytes,
|
||||
this.download.speed,
|
||||
|
@ -725,7 +731,9 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
DownloadsViewUI.improvementsIsOn &&
|
||||
this.download.launchWhenSucceeded
|
||||
) {
|
||||
status = DownloadUtils.getFormattedTimeStatus(newEstimatedSecondsLeft);
|
||||
status = lazy.DownloadUtils.getFormattedTimeStatus(
|
||||
newEstimatedSecondsLeft
|
||||
);
|
||||
}
|
||||
let hoverStatus = DownloadsViewUI.improvementsIsOn
|
||||
? {
|
||||
|
@ -742,7 +750,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
if (this.download.deleted) {
|
||||
this.showDeletedOrMissing();
|
||||
} else if (this.download.succeeded) {
|
||||
DownloadsCommon.log(
|
||||
lazy.DownloadsCommon.log(
|
||||
"_updateStateInner, target exists? ",
|
||||
this.download.target.path,
|
||||
this.download.target.exists
|
||||
|
@ -753,8 +761,8 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
|
||||
this.element.toggleAttribute(
|
||||
"viewable-internally",
|
||||
DownloadIntegration.shouldViewDownloadInternally(
|
||||
DownloadsCommon.getMimeInfo(this.download)?.type
|
||||
lazy.DownloadIntegration.shouldViewDownloadInternally(
|
||||
lazy.DownloadsCommon.getMimeInfo(this.download)?.type
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -764,9 +772,9 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
// label, for example "Completed - 1.5 MB". When the pointer is over
|
||||
// the main area of the item, this label is replaced with a
|
||||
// description of the default action, which opens the file.
|
||||
let status = DownloadsCommon.strings.stateCompleted;
|
||||
let status = lazy.DownloadsCommon.strings.stateCompleted;
|
||||
if (sizeWithUnits) {
|
||||
status = DownloadsCommon.strings.statusSeparator(
|
||||
status = lazy.DownloadsCommon.strings.statusSeparator(
|
||||
status,
|
||||
sizeWithUnits
|
||||
);
|
||||
|
@ -776,7 +784,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
// In the Downloads View, we show the file size in place of the
|
||||
// state label, for example "1.5 MB - example.com - 1:45 PM".
|
||||
this.showStatusWithDetails(
|
||||
sizeWithUnits || DownloadsCommon.strings.sizeUnknown
|
||||
sizeWithUnits || lazy.DownloadsCommon.strings.sizeUnknown
|
||||
);
|
||||
}
|
||||
this.showButton("show");
|
||||
|
@ -789,7 +797,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
if (this.download.error.becauseBlockedByParentalControls) {
|
||||
// This download was blocked permanently by parental controls.
|
||||
this.showStatusWithDetails(
|
||||
DownloadsCommon.strings.stateBlockedParentalControls
|
||||
lazy.DownloadsCommon.strings.stateBlockedParentalControls
|
||||
);
|
||||
this.hideButton();
|
||||
} else if (this.download.error.becauseBlockedByReputationCheck) {
|
||||
|
@ -808,9 +816,9 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
// This download was blocked temporarily by reputation check. In the
|
||||
// Downloads View, the interface depends on the threat severity.
|
||||
switch (verdict) {
|
||||
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
case Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
// Keep the option the user chose on the save dialogue
|
||||
if (this.download.launchWhenSucceeded) {
|
||||
this.showButton("askOpenOrRemoveFile");
|
||||
|
@ -818,7 +826,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
this.showButton("askRemoveFileOrAllow");
|
||||
}
|
||||
break;
|
||||
case Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM:
|
||||
this.showButton("askRemoveFileOrAllow");
|
||||
break;
|
||||
default:
|
||||
|
@ -830,7 +838,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
this.showStatusWithDetails(this.rawBlockedTitleAndDetails[0], hover);
|
||||
} else {
|
||||
// This download failed without being blocked, and can be restarted.
|
||||
this.showStatusWithDetails(DownloadsCommon.strings.stateFailed);
|
||||
this.showStatusWithDetails(lazy.DownloadsCommon.strings.stateFailed);
|
||||
this.showButton("retry");
|
||||
}
|
||||
} else if (this.download.canceled) {
|
||||
|
@ -841,13 +849,13 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
let totalBytes = this.download.hasProgress
|
||||
? this.download.totalBytes
|
||||
: -1;
|
||||
let transfer = DownloadUtils.getTransferTotal(
|
||||
let transfer = lazy.DownloadUtils.getTransferTotal(
|
||||
this.download.currentBytes,
|
||||
totalBytes
|
||||
);
|
||||
this.showStatus(
|
||||
DownloadsCommon.strings.statusSeparatorBeforeNumber(
|
||||
DownloadsCommon.strings.statePaused,
|
||||
lazy.DownloadsCommon.strings.statusSeparatorBeforeNumber(
|
||||
lazy.DownloadsCommon.strings.statePaused,
|
||||
transfer
|
||||
)
|
||||
);
|
||||
|
@ -855,7 +863,9 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
progressPaused = true;
|
||||
} else {
|
||||
// This download was canceled.
|
||||
this.showStatusWithDetails(DownloadsCommon.strings.stateCanceled);
|
||||
this.showStatusWithDetails(
|
||||
lazy.DownloadsCommon.strings.stateCanceled
|
||||
);
|
||||
this.showButton("retry");
|
||||
}
|
||||
} else {
|
||||
|
@ -864,7 +874,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
// internally developed add-ons and regression tests, and should not
|
||||
// happen unless there is a bug. This means the stateStarting string can
|
||||
// probably be removed when converting the localization to Fluent.
|
||||
this.showStatus(DownloadsCommon.strings.stateStarting);
|
||||
this.showStatus(lazy.DownloadsCommon.strings.stateStarting);
|
||||
this.showButton("cancel");
|
||||
}
|
||||
|
||||
|
@ -896,7 +906,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
* The title or details could be raw strings or l10n objects.
|
||||
*/
|
||||
get rawBlockedTitleAndDetails() {
|
||||
let s = DownloadsCommon.strings;
|
||||
let s = lazy.DownloadsCommon.strings;
|
||||
if (
|
||||
!this.download.error ||
|
||||
!this.download.error.becauseBlockedByReputationCheck
|
||||
|
@ -904,22 +914,22 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
return [null, null];
|
||||
}
|
||||
switch (this.download.error.reputationCheckVerdict) {
|
||||
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
return [s.blockedUncommon2, [s.unblockTypeUncommon2, s.unblockTip2]];
|
||||
case Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_INSECURE:
|
||||
return [
|
||||
s.blockedPotentiallyInsecure,
|
||||
[s.unblockInsecure, s.unblockTip2],
|
||||
];
|
||||
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
return [
|
||||
s.blockedPotentiallyUnwanted,
|
||||
[s.unblockTypePotentiallyUnwanted2, s.unblockTip2],
|
||||
];
|
||||
case Downloads.Error.BLOCK_VERDICT_MALWARE:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_MALWARE:
|
||||
return [s.blockedMalware, [s.unblockTypeMalware, s.unblockTip2]];
|
||||
|
||||
case Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM:
|
||||
case lazy.Downloads.Error.BLOCK_VERDICT_DOWNLOAD_SPAM:
|
||||
let title = {
|
||||
id: "downloads-files-not-downloaded",
|
||||
args: {
|
||||
|
@ -941,7 +951,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
showDeletedOrMissing() {
|
||||
this.element.removeAttribute("exists");
|
||||
let label =
|
||||
DownloadsCommon.strings[
|
||||
lazy.DownloadsCommon.strings[
|
||||
this.download.deleted ? "fileDeleted" : "fileMovedOrMissing"
|
||||
];
|
||||
this.showStatusWithDetails(label, label);
|
||||
|
@ -959,7 +969,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
* Can be "unblock", "chooseUnblock", or "chooseOpen".
|
||||
*/
|
||||
confirmUnblock(window, dialogType) {
|
||||
DownloadsCommon.confirmUnblockDownload({
|
||||
lazy.DownloadsCommon.confirmUnblockDownload({
|
||||
verdict: this.download.error.reputationCheckVerdict,
|
||||
window,
|
||||
dialogType,
|
||||
|
@ -996,19 +1006,19 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
* The commands are implemented as functions on this object or derived ones.
|
||||
*/
|
||||
get currentDefaultCommandName() {
|
||||
switch (DownloadsCommon.stateOfDownload(this.download)) {
|
||||
case DownloadsCommon.DOWNLOAD_NOTSTARTED:
|
||||
switch (lazy.DownloadsCommon.stateOfDownload(this.download)) {
|
||||
case lazy.DownloadsCommon.DOWNLOAD_NOTSTARTED:
|
||||
return "downloadsCmd_cancel";
|
||||
case DownloadsCommon.DOWNLOAD_FAILED:
|
||||
case DownloadsCommon.DOWNLOAD_CANCELED:
|
||||
case lazy.DownloadsCommon.DOWNLOAD_FAILED:
|
||||
case lazy.DownloadsCommon.DOWNLOAD_CANCELED:
|
||||
return "downloadsCmd_retry";
|
||||
case DownloadsCommon.DOWNLOAD_PAUSED:
|
||||
case lazy.DownloadsCommon.DOWNLOAD_PAUSED:
|
||||
return "downloadsCmd_pauseResume";
|
||||
case DownloadsCommon.DOWNLOAD_FINISHED:
|
||||
case lazy.DownloadsCommon.DOWNLOAD_FINISHED:
|
||||
return "downloadsCmd_open";
|
||||
case DownloadsCommon.DOWNLOAD_BLOCKED_PARENTAL:
|
||||
case lazy.DownloadsCommon.DOWNLOAD_BLOCKED_PARENTAL:
|
||||
return "downloadsCmd_openReferrer";
|
||||
case DownloadsCommon.DOWNLOAD_DIRTY:
|
||||
case lazy.DownloadsCommon.DOWNLOAD_DIRTY:
|
||||
return "downloadsCmd_showBlockedInfo";
|
||||
}
|
||||
return "";
|
||||
|
@ -1063,8 +1073,8 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
return this.download.stopped;
|
||||
case "downloadsCmd_openInSystemViewer":
|
||||
case "downloadsCmd_alwaysOpenInSystemViewer":
|
||||
return DownloadIntegration.shouldViewDownloadInternally(
|
||||
DownloadsCommon.getMimeInfo(this.download)?.type
|
||||
return lazy.DownloadIntegration.shouldViewDownloadInternally(
|
||||
lazy.DownloadsCommon.getMimeInfo(this.download)?.type
|
||||
);
|
||||
}
|
||||
return DownloadsViewUI.isCommandName(aCommand) && !!this[aCommand];
|
||||
|
@ -1097,7 +1107,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
},
|
||||
|
||||
downloadsCmd_open(openWhere = "tab") {
|
||||
DownloadsCommon.openDownload(this.download, {
|
||||
lazy.DownloadsCommon.openDownload(this.download, {
|
||||
openWhere,
|
||||
});
|
||||
},
|
||||
|
@ -1117,8 +1127,8 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
},
|
||||
|
||||
downloadsCmd_show() {
|
||||
let file = new FileUtils.File(this.download.target.path);
|
||||
DownloadsCommon.showDownloadedFile(file);
|
||||
let file = new lazy.FileUtils.File(this.download.target.path);
|
||||
lazy.DownloadsCommon.showDownloadedFile(file);
|
||||
},
|
||||
|
||||
downloadsCmd_retry() {
|
||||
|
@ -1146,12 +1156,12 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
},
|
||||
|
||||
cmd_delete() {
|
||||
DownloadsCommon.deleteDownload(this.download).catch(Cu.reportError);
|
||||
lazy.DownloadsCommon.deleteDownload(this.download).catch(Cu.reportError);
|
||||
},
|
||||
|
||||
async downloadsCmd_deleteFile() {
|
||||
// Remove the download from the session and history downloads, delete part files.
|
||||
await DownloadsCommon.deleteDownloadFiles(
|
||||
await lazy.DownloadsCommon.deleteDownloadFiles(
|
||||
this.download,
|
||||
DownloadsViewUI.clearHistoryOnDelete
|
||||
);
|
||||
|
@ -1160,7 +1170,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
downloadsCmd_openInSystemViewer() {
|
||||
// For this interaction only, pass a flag to override the preferredAction for this
|
||||
// mime-type and open using the system viewer
|
||||
DownloadsCommon.openDownload(this.download, {
|
||||
lazy.DownloadsCommon.openDownload(this.download, {
|
||||
useSystemDefault: true,
|
||||
}).catch(Cu.reportError);
|
||||
},
|
||||
|
@ -1168,7 +1178,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
downloadsCmd_alwaysOpenInSystemViewer() {
|
||||
// this command toggles between setting preferredAction for this mime-type to open
|
||||
// using the system viewer, or to open the file in browser.
|
||||
const mimeInfo = DownloadsCommon.getMimeInfo(this.download);
|
||||
const mimeInfo = lazy.DownloadsCommon.getMimeInfo(this.download);
|
||||
if (!mimeInfo) {
|
||||
throw new Error(
|
||||
"Can't open download with unknown mime-type in system viewer"
|
||||
|
@ -1176,7 +1186,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
}
|
||||
if (mimeInfo.preferredAction !== mimeInfo.useSystemDefault) {
|
||||
// User has selected to open this mime-type with the system viewer from now on
|
||||
DownloadsCommon.log(
|
||||
lazy.DownloadsCommon.log(
|
||||
"downloadsCmd_alwaysOpenInSystemViewer command for download: ",
|
||||
this.download,
|
||||
"switching to use system default for " + mimeInfo.type
|
||||
|
@ -1184,7 +1194,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
mimeInfo.preferredAction = mimeInfo.useSystemDefault;
|
||||
mimeInfo.alwaysAskBeforeHandling = false;
|
||||
} else {
|
||||
DownloadsCommon.log(
|
||||
lazy.DownloadsCommon.log(
|
||||
"downloadsCmd_alwaysOpenInSystemViewer command for download: ",
|
||||
this.download,
|
||||
"currently uses system default, switching to handleInternally"
|
||||
|
@ -1192,12 +1202,12 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
// User has selected to not open this mime-type with the system viewer
|
||||
mimeInfo.preferredAction = mimeInfo.handleInternally;
|
||||
}
|
||||
handlerSvc.store(mimeInfo);
|
||||
DownloadsCommon.openDownload(this.download).catch(Cu.reportError);
|
||||
lazy.handlerSvc.store(mimeInfo);
|
||||
lazy.DownloadsCommon.openDownload(this.download).catch(Cu.reportError);
|
||||
},
|
||||
|
||||
downloadsCmd_alwaysOpenSimilarFiles() {
|
||||
const mimeInfo = DownloadsCommon.getMimeInfo(this.download);
|
||||
const mimeInfo = lazy.DownloadsCommon.getMimeInfo(this.download);
|
||||
if (!mimeInfo) {
|
||||
throw new Error("Can't open download with unknown mime-type");
|
||||
}
|
||||
|
@ -1207,13 +1217,13 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
|||
// file immediately after selecting the menu item like alwaysOpenInSystemViewer.
|
||||
if (mimeInfo.preferredAction !== mimeInfo.useSystemDefault) {
|
||||
mimeInfo.preferredAction = mimeInfo.useSystemDefault;
|
||||
handlerSvc.store(mimeInfo);
|
||||
DownloadsCommon.openDownload(this.download).catch(Cu.reportError);
|
||||
lazy.handlerSvc.store(mimeInfo);
|
||||
lazy.DownloadsCommon.openDownload(this.download).catch(Cu.reportError);
|
||||
} else {
|
||||
// Otherwise, if user unchecks this option after already enabling it from the
|
||||
// context menu, resort to saveToDisk.
|
||||
mimeInfo.preferredAction = mimeInfo.saveToDisk;
|
||||
handlerSvc.store(mimeInfo);
|
||||
lazy.handlerSvc.store(mimeInfo);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -23,21 +23,23 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"HandlerService",
|
||||
"@mozilla.org/uriloader/handler-service;1",
|
||||
"nsIHandlerService"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
lazy,
|
||||
"MIMEService",
|
||||
"@mozilla.org/mime;1",
|
||||
"nsIMIMEService"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
lazy,
|
||||
"Integration",
|
||||
"resource://gre/modules/Integration.jsm"
|
||||
);
|
||||
|
@ -78,7 +80,7 @@ let DownloadsViewableInternally = {
|
|||
this._updateAllHandlers();
|
||||
|
||||
// Register the check for use in DownloadIntegration
|
||||
Integration.downloads.register(base => ({
|
||||
lazy.Integration.downloads.register(base => ({
|
||||
shouldViewDownloadInternally: this._shouldViewDownloadInternally.bind(
|
||||
this
|
||||
),
|
||||
|
@ -250,10 +252,10 @@ let DownloadsViewableInternally = {
|
|||
PREF_BRANCH_PREVIOUS_ASK + handlerType.extension
|
||||
);
|
||||
handlerInfo.preferredAction = Services.prefs.getIntPref(prevActionPref);
|
||||
HandlerService.store(handlerInfo);
|
||||
lazy.HandlerService.store(handlerInfo);
|
||||
} else {
|
||||
// Nothing to restore, just remove the handler.
|
||||
HandlerService.remove(handlerInfo);
|
||||
lazy.HandlerService.remove(handlerInfo);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -295,10 +297,10 @@ let DownloadsViewableInternally = {
|
|||
handlerType.mimeTypes[0],
|
||||
handlerType.extension
|
||||
);
|
||||
if (!HandlerService.exists(fakeHandlerInfo)) {
|
||||
HandlerService.store(fakeHandlerInfo);
|
||||
if (!lazy.HandlerService.exists(fakeHandlerInfo)) {
|
||||
lazy.HandlerService.store(fakeHandlerInfo);
|
||||
} else {
|
||||
const handlerInfo = MIMEService.getFromTypeAndExtension(
|
||||
const handlerInfo = lazy.MIMEService.getFromTypeAndExtension(
|
||||
handlerType.mimeTypes[0],
|
||||
handlerType.extension
|
||||
);
|
||||
|
@ -326,7 +328,7 @@ let DownloadsViewableInternally = {
|
|||
handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally;
|
||||
handlerInfo.alwaysAskBeforeHandling = false;
|
||||
|
||||
HandlerService.store(handlerInfo);
|
||||
lazy.HandlerService.store(handlerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,7 +343,7 @@ let DownloadsViewableInternally = {
|
|||
_unbecomeHandler(handlerType) {
|
||||
let handlerInfo;
|
||||
try {
|
||||
handlerInfo = MIMEService.getFromTypeAndExtension(
|
||||
handlerInfo = lazy.MIMEService.getFromTypeAndExtension(
|
||||
handlerType.mimeTypes[0],
|
||||
handlerType.extension
|
||||
);
|
||||
|
|
|
@ -253,6 +253,10 @@ body[lwt-newtab-brighttext] {
|
|||
.onboardingContainer .welcome-text.fancy h1 {
|
||||
background-image: linear-gradient(90deg, #C688FF, #FF84C0, #FFBD4F, #FF84C0, #C688FF);
|
||||
}
|
||||
.onboardingContainer .welcome-text.fancy h1::selection {
|
||||
color: #FFF;
|
||||
background-color: #696977;
|
||||
}
|
||||
}
|
||||
.onboardingContainer .welcome-text.shine h1 {
|
||||
animation: shine 50s linear infinite;
|
||||
|
|
|
@ -276,6 +276,11 @@ body {
|
|||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-image: linear-gradient(90deg, #C688FF, #FF84C0, #FFBD4F, #FF84C0, #C688FF);
|
||||
|
||||
&::selection {
|
||||
color: #FFF;
|
||||
background-color: #696977;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
PartnerLinkAttribution: "resource:///modules/PartnerLinkAttribution.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
SearchSERPTelemetry: "resource:///modules/SearchSERPTelemetry.jsm",
|
||||
|
@ -57,7 +59,7 @@ class BrowserSearchTelemetryHandler {
|
|||
*/
|
||||
shouldRecordSearchCount(browser) {
|
||||
return (
|
||||
!PrivateBrowsingUtils.isWindowPrivate(browser.ownerGlobal) ||
|
||||
!lazy.PrivateBrowsingUtils.isWindowPrivate(browser.ownerGlobal) ||
|
||||
!Services.prefs.getBoolPref("browser.engagement.search_counts.pbm", false)
|
||||
);
|
||||
}
|
||||
|
@ -141,7 +143,7 @@ class BrowserSearchTelemetryHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
let scalarKey = UrlbarSearchUtils.getSearchModeScalarKey(searchMode);
|
||||
let scalarKey = lazy.UrlbarSearchUtils.getSearchModeScalarKey(searchMode);
|
||||
Services.telemetry.keyedScalarAdd(
|
||||
"urlbar.searchmode." + searchMode.entry,
|
||||
scalarKey,
|
||||
|
@ -254,14 +256,14 @@ class BrowserSearchTelemetryHandler {
|
|||
|
||||
_recordSearch(browser, engine, url, source, action = null) {
|
||||
if (url) {
|
||||
PartnerLinkAttribution.makeSearchEngineRequest(engine, url).catch(
|
||||
lazy.PartnerLinkAttribution.makeSearchEngineRequest(engine, url).catch(
|
||||
Cu.reportError
|
||||
);
|
||||
}
|
||||
|
||||
let scalarSource = KNOWN_SEARCH_SOURCES.get(source);
|
||||
|
||||
SearchSERPTelemetry.recordBrowserSource(browser, scalarSource);
|
||||
lazy.SearchSERPTelemetry.recordBrowserSource(browser, scalarSource);
|
||||
|
||||
let scalarKey = action ? "search_" + action : "search";
|
||||
Services.telemetry.keyedScalarAdd(
|
||||
|
|
|
@ -10,7 +10,8 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
SearchUIUtils: "resource:///modules/SearchUIUtils.jsm",
|
||||
});
|
||||
|
@ -349,7 +350,7 @@ class SearchOneOffs {
|
|||
}
|
||||
|
||||
this._engineInfo = {};
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(this.window)) {
|
||||
if (lazy.PrivateBrowsingUtils.isWindowPrivate(this.window)) {
|
||||
this._engineInfo.default = await Services.search.getDefaultPrivate();
|
||||
} else {
|
||||
this._engineInfo.default = await Services.search.getDefault();
|
||||
|
@ -1031,7 +1032,7 @@ class SearchOneOffs {
|
|||
if (target.classList.contains("searchbar-engine-one-off-add-engine")) {
|
||||
// On success, hide the panel and tell event listeners to reshow it to
|
||||
// show the new engine.
|
||||
SearchUIUtils.addOpenSearchEngine(
|
||||
lazy.SearchUIUtils.addOpenSearchEngine(
|
||||
target.getAttribute("uri"),
|
||||
target.getAttribute("image"),
|
||||
this.window.gBrowser.selectedBrowser.browsingContext
|
||||
|
@ -1064,7 +1065,9 @@ class SearchOneOffs {
|
|||
: "defaultEngine";
|
||||
let currentEngine = Services.search[engineType];
|
||||
|
||||
const isPrivateWin = PrivateBrowsingUtils.isWindowPrivate(this.window);
|
||||
const isPrivateWin = lazy.PrivateBrowsingUtils.isWindowPrivate(
|
||||
this.window
|
||||
);
|
||||
if (
|
||||
!this.getAttribute("includecurrentengine") &&
|
||||
isPrivateButton == isPrivateWin
|
||||
|
|
|
@ -11,7 +11,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm",
|
||||
RemoteSettings: "resource://services-settings/remote-settings.js",
|
||||
SearchUtils: "resource://gre/modules/SearchUtils.jsm",
|
||||
|
@ -29,10 +31,10 @@ const SEARCH_TELEMETRY_PRIVATE_BROWSING_KEY_SUFFIX = "pb";
|
|||
|
||||
const TELEMETRY_SETTINGS_KEY = "search-telemetry-v2";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logConsole", () => {
|
||||
XPCOMUtils.defineLazyGetter(lazy, "logConsole", () => {
|
||||
return console.createInstance({
|
||||
prefix: "SearchTelemetry",
|
||||
maxLogLevel: SearchUtils.loggingEnabled ? "Debug" : "Warn",
|
||||
maxLogLevel: lazy.SearchUtils.loggingEnabled ? "Debug" : "Warn",
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -96,12 +98,12 @@ class TelemetryHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
this._telemetrySettings = RemoteSettings(TELEMETRY_SETTINGS_KEY);
|
||||
this._telemetrySettings = lazy.RemoteSettings(TELEMETRY_SETTINGS_KEY);
|
||||
let rawProviderInfo = [];
|
||||
try {
|
||||
rawProviderInfo = await this._telemetrySettings.get();
|
||||
} catch (ex) {
|
||||
logConsole.error("Could not get settings:", ex);
|
||||
lazy.logConsole.error("Could not get settings:", ex);
|
||||
}
|
||||
|
||||
// Send the provider info to the child handler.
|
||||
|
@ -217,7 +219,9 @@ class TelemetryHandler {
|
|||
*/
|
||||
updateTrackingStatus(browser, url, loadType) {
|
||||
if (
|
||||
!BrowserSearchTelemetry.shouldRecordSearchCount(browser.getTabBrowser())
|
||||
!lazy.BrowserSearchTelemetry.shouldRecordSearchCount(
|
||||
browser.getTabBrowser()
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -565,7 +569,7 @@ class TelemetryHandler {
|
|||
SEARCH_COUNTS_HISTOGRAM_KEY
|
||||
);
|
||||
histogram.add(payload);
|
||||
logConsole.debug("Counting", payload, "for", url);
|
||||
lazy.logConsole.debug("Counting", payload, "for", url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -720,7 +724,7 @@ class ContentHandler {
|
|||
|
||||
let wrappedChannel = ChannelWrapper.get(channel);
|
||||
if (wrappedChannel._adClickRecorded) {
|
||||
logConsole.debug("Ad click already recorded");
|
||||
lazy.logConsole.debug("Ad click already recorded");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -729,7 +733,7 @@ class ContentHandler {
|
|||
// update beacons. They used to lead to double-counting ad-clicks, so let's
|
||||
// ignore them.
|
||||
if (wrappedChannel.statusCode == 204) {
|
||||
logConsole.debug("Ignoring activity from ambiguous responses");
|
||||
lazy.logConsole.debug("Ignoring activity from ambiguous responses");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -748,7 +752,7 @@ class ContentHandler {
|
|||
}
|
||||
|
||||
try {
|
||||
logConsole.debug(
|
||||
lazy.logConsole.debug(
|
||||
"Counting ad click in page for",
|
||||
info.telemetryId,
|
||||
item.source,
|
||||
|
@ -787,7 +791,7 @@ class ContentHandler {
|
|||
_reportPageWithAds(info, browser) {
|
||||
let item = this._findBrowserItemForURL(info.url);
|
||||
if (!item) {
|
||||
logConsole.warn(
|
||||
lazy.logConsole.warn(
|
||||
"Expected to report URI for",
|
||||
info.url,
|
||||
"with ads but couldn't find the information"
|
||||
|
@ -797,14 +801,14 @@ class ContentHandler {
|
|||
|
||||
let adReportState = item.browsers.get(browser);
|
||||
if (adReportState == "ad reported") {
|
||||
logConsole.debug(
|
||||
lazy.logConsole.debug(
|
||||
"Ad was previously reported for browser with URI",
|
||||
info.url
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
logConsole.debug(
|
||||
lazy.logConsole.debug(
|
||||
"Counting ads in page for",
|
||||
item.info.provider,
|
||||
item.info.type,
|
||||
|
|
|
@ -13,7 +13,9 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "SearchUIUtilsL10n", () => {
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(lazy, "SearchUIUtilsL10n", () => {
|
||||
return new Localization(["browser/search.ftl", "branding/brand.ftl"]);
|
||||
});
|
||||
|
||||
|
@ -54,7 +56,7 @@ var SearchUIUtils = {
|
|||
break;
|
||||
}
|
||||
|
||||
let [title, text] = await SearchUIUtilsL10n.formatValues([
|
||||
let [title, text] = await lazy.SearchUIUtilsL10n.formatValues([
|
||||
{
|
||||
id: titleMsgName,
|
||||
},
|
||||
|
|
|
@ -383,10 +383,7 @@ class UrlbarInput {
|
|||
this.valueIsTyped = !valid;
|
||||
this.removeAttribute("usertyping");
|
||||
|
||||
if (!this.focused) {
|
||||
// When setURI is called while the input is not focused, reset the caret.
|
||||
this.selectionStart = this.selectionEnd = 0;
|
||||
} else if (value != previousUntrimmedValue) {
|
||||
if (this.focused && value != previousUntrimmedValue) {
|
||||
if (
|
||||
previousSelectionStart != previousSelectionEnd &&
|
||||
value.substring(previousSelectionStart, previousSelectionEnd) ===
|
||||
|
@ -397,8 +394,10 @@ class UrlbarInput {
|
|||
) {
|
||||
// If the same text is in the same place as the previously selected text,
|
||||
// the selection is kept.
|
||||
this.selectionStart = previousSelectionStart;
|
||||
this.selectionEnd = previousSelectionEnd;
|
||||
this.inputField.setSelectionRange(
|
||||
previousSelectionStart,
|
||||
previousSelectionEnd
|
||||
);
|
||||
} else if (
|
||||
previousSelectionEnd &&
|
||||
(previousUntrimmedValue.length === previousSelectionEnd ||
|
||||
|
@ -407,11 +406,14 @@ class UrlbarInput {
|
|||
// If the previous end caret is not 0 and the caret is at the end of the
|
||||
// input or its position is beyond the end of the new value, keep the
|
||||
// position at the end.
|
||||
this.selectionStart = this.selectionEnd = value.length;
|
||||
this.inputField.setSelectionRange(value.length, value.length);
|
||||
} else {
|
||||
// Otherwise clear selection and set the caret position to the previous
|
||||
// caret end position.
|
||||
this.selectionStart = this.selectionEnd = previousSelectionEnd;
|
||||
this.inputField.setSelectionRange(
|
||||
previousSelectionEnd,
|
||||
previousSelectionEnd
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -354,6 +354,9 @@ support-files =
|
|||
urlbarTelemetrySearchSuggestions.xml
|
||||
[browser_UrlbarInput_formatValue.js]
|
||||
[browser_UrlbarInput_formatValue_detachedTab.js]
|
||||
skip-if =
|
||||
apple_catalina && debug # Bug 1756585
|
||||
os == 'win' # Bug 1756585
|
||||
[browser_UrlbarInput_hiddenFocus.js]
|
||||
[browser_UrlbarInput_overflow.js]
|
||||
[browser_UrlbarInput_overflow_resize.js]
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const LARGE_DATA_URL =
|
||||
"data:text/plain," + [...Array(1000)].map(() => "0123456789").join("");
|
||||
|
||||
// Tests for the caret position after gURLBar.setURI().
|
||||
add_task(async function setURI() {
|
||||
const testData = [
|
||||
|
@ -182,32 +185,72 @@ add_task(async function setURI() {
|
|||
expectedSelectionStart: 0,
|
||||
expectedSelectionEnd: 0,
|
||||
},
|
||||
{
|
||||
firstURL: "about:blank",
|
||||
secondURL: LARGE_DATA_URL,
|
||||
initialSelectionStart: 0,
|
||||
initialSelectionEnd: 0,
|
||||
expectedSelectionStart: 0,
|
||||
expectedSelectionEnd: 0,
|
||||
},
|
||||
{
|
||||
firstURL: "about:telemetry",
|
||||
secondURL: LARGE_DATA_URL,
|
||||
initialSelectionStart: "about:telemetry".length,
|
||||
initialSelectionEnd: "about:telemetry".length,
|
||||
expectedSelectionStart: LARGE_DATA_URL.length,
|
||||
expectedSelectionEnd: LARGE_DATA_URL.length,
|
||||
},
|
||||
];
|
||||
|
||||
for (const data of testData) {
|
||||
info(
|
||||
`Test for ${data.firstURL} -> ${data.secondURL} with initial selection: ${data.initialSelectionStart}, ${data.initialSelectionEnd}`
|
||||
);
|
||||
|
||||
info("Check the caret position after setting second URL");
|
||||
gURLBar.setURI(makeURI(data.firstURL));
|
||||
gURLBar.selectionStart = data.initialSelectionStart;
|
||||
gURLBar.selectionEnd = data.initialSelectionEnd;
|
||||
|
||||
// The change of the scroll amount dependent on the selection change will be
|
||||
// ignored if the previous processing is unfinished yet. Therefore, make the
|
||||
// processing finalize explicitly here.
|
||||
await flushScrollStyle();
|
||||
|
||||
gURLBar.focus();
|
||||
gURLBar.setURI(makeURI(data.secondURL));
|
||||
await flushScrollStyle();
|
||||
|
||||
Assert.equal(gURLBar.selectionStart, data.expectedSelectionStart);
|
||||
Assert.equal(gURLBar.selectionEnd, data.expectedSelectionEnd);
|
||||
if (data.secondURL.length === data.expectedSelectionStart) {
|
||||
// If the caret is at the end of url, the input field shows the end of
|
||||
// text.
|
||||
Assert.equal(
|
||||
gURLBar.inputField.scrollLeft,
|
||||
gURLBar.inputField.scrollLeftMax
|
||||
);
|
||||
}
|
||||
|
||||
info("Check the caret position while the input is not focused");
|
||||
gURLBar.setURI(makeURI(data.firstURL));
|
||||
gURLBar.selectionStart = data.initialSelectionStart;
|
||||
gURLBar.selectionEnd = data.initialSelectionEnd;
|
||||
|
||||
await flushScrollStyle();
|
||||
|
||||
gURLBar.blur();
|
||||
gURLBar.setURI(makeURI(data.secondURL));
|
||||
Assert.equal(gURLBar.selectionStart, 0);
|
||||
Assert.equal(gURLBar.selectionEnd, 0);
|
||||
await flushScrollStyle();
|
||||
|
||||
if (data.firstURL === data.secondURL) {
|
||||
Assert.equal(gURLBar.selectionStart, data.initialSelectionStart);
|
||||
Assert.equal(gURLBar.selectionEnd, data.initialSelectionEnd);
|
||||
} else {
|
||||
Assert.equal(gURLBar.selectionStart, gURLBar.value.length);
|
||||
Assert.equal(gURLBar.selectionEnd, gURLBar.value.length);
|
||||
}
|
||||
Assert.equal(gURLBar.inputField.scrollLeft, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -304,3 +347,13 @@ function checkIfKeyStartsQuery(key, shouldStartQuery, win) {
|
|||
`${key}: Should${shouldStartQuery ? "" : "n't"} have started a query`
|
||||
);
|
||||
}
|
||||
|
||||
async function flushScrollStyle() {
|
||||
// Flush pending notifications for the style.
|
||||
/* eslint-disable no-unused-expressions */
|
||||
gURLBar.inputField.scrollLeft;
|
||||
// Ensure to apply the style.
|
||||
await new Promise(resolve =>
|
||||
gURLBar.inputField.ownerGlobal.requestAnimationFrame(resolve)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -148,6 +148,25 @@ const AVAILABLE_SHIMS = [
|
|||
],
|
||||
onlyIfBlockedByETP: true,
|
||||
},
|
||||
{
|
||||
id: "AdSafeProtectedFavIcon",
|
||||
platform: "all",
|
||||
name: "Ad Safe Protected favicon",
|
||||
bug: "1717806",
|
||||
matches: [
|
||||
{
|
||||
patterns: ["*://static.adsafeprotected.com/favicon.ico"],
|
||||
target: "https://redirect.firefox.etp/adsafeprotected_favicon",
|
||||
types: ["image", "imageset", "xmlhttprequest"],
|
||||
},
|
||||
{
|
||||
patterns: ["https://redirect.firefox.etp/adsafeprotected_favicon"],
|
||||
target: "tracking-pixel.png",
|
||||
types: ["image", "imageset", "xmlhttprequest"],
|
||||
},
|
||||
],
|
||||
onlyIfDFPIActive: true,
|
||||
},
|
||||
{
|
||||
id: "AdSafeProtectedGoogleIMAAdapter",
|
||||
platform: "all",
|
||||
|
@ -487,6 +506,28 @@ const AVAILABLE_SHIMS = [
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "StickyAdsTV",
|
||||
platform: "all",
|
||||
name: "StickyAdsTV",
|
||||
bug: "1717806",
|
||||
matches: [
|
||||
{
|
||||
patterns: [
|
||||
"*://ads.stickyadstv.com/auto-user-sync*",
|
||||
"*://ads.stickyadstv.com/user-matching*",
|
||||
],
|
||||
target: "https://redirect.firefox.etp/stickadstv",
|
||||
types: ["image", "imageset", "xmlhttprequest"],
|
||||
},
|
||||
{
|
||||
patterns: ["https://redirect.firefox.etp/stickadstv"],
|
||||
target: "tracking-pixel.png",
|
||||
types: ["image", "imageset", "xmlhttprequest"],
|
||||
},
|
||||
],
|
||||
onlyIfDFPIActive: true,
|
||||
},
|
||||
{
|
||||
id: "Vidible",
|
||||
branch: ["nightly"],
|
||||
|
|
|
@ -986,6 +986,10 @@ class Shims {
|
|||
}
|
||||
} catch (_) {}
|
||||
|
||||
if (!redirect.indexOf("http://") || !redirect.indexOf("https://")) {
|
||||
return { redirectUrl: redirect };
|
||||
}
|
||||
|
||||
// If any shims matched the request to replace it, then redirect to the local
|
||||
// file bundled with SmartBlock, so the request never hits the network.
|
||||
return { redirectUrl: browser.runtime.getURL(`shims/${redirect}`) };
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
"name": "Web Compatibility Interventions",
|
||||
"description": "Urgent post-release fixes for web compatibility.",
|
||||
"version": "102.6.0",
|
||||
"version": "102.7.0",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "webcompat@mozilla.org",
|
||||
|
|
|
@ -879,7 +879,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "1faa5fcbdacbf9be9fccda604aa5f36ec2a6befe"
|
||||
"revision": "30b0c7e24236cdc2b67820a6cd93d126f126ad75"
|
||||
},
|
||||
"ia": {
|
||||
"pin": false,
|
||||
|
@ -951,7 +951,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "3c5a5798bfe718a55222643a1b3618c59e04040d"
|
||||
"revision": "af61d6bf43f8f481f2aa291f74530840ce06edcb"
|
||||
},
|
||||
"ja": {
|
||||
"pin": false,
|
||||
|
@ -1407,7 +1407,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "ef2c188ad6e295e5063651923cced9b2f7a7f659"
|
||||
"revision": "76f8e893b63502d6edae7320c10e30ddee518286"
|
||||
},
|
||||
"pt-PT": {
|
||||
"pin": false,
|
||||
|
@ -1749,7 +1749,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "f476ebaec678aa08dab8e5571974b732a703d533"
|
||||
"revision": "a6813e2c1e6fade3eb8e287739c329d5de20bb49"
|
||||
},
|
||||
"th": {
|
||||
"pin": false,
|
||||
|
@ -1785,7 +1785,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "53e56b5e2a9dc6a6b0e3c761a2801d469aeb61b5"
|
||||
"revision": "11c52d8c62012ea90c35eb65b26899463e71d750"
|
||||
},
|
||||
"tr": {
|
||||
"pin": false,
|
||||
|
|
11
build/rust/parking_lot/Cargo.toml
Normal file
11
build/rust/parking_lot/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "parking_lot"
|
||||
version = "0.12.999"
|
||||
edition = "2018"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.11"
|
5
build/rust/parking_lot/lib.rs
Normal file
5
build/rust/parking_lot/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* 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/. */
|
||||
|
||||
pub use parking_lot::*;
|
|
@ -36,7 +36,7 @@
|
|||
#include "prnetdb.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "mozilla/dom/StorageUtils.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIURIMutator.h"
|
||||
#include "mozilla/PermissionManager.h"
|
||||
|
@ -785,8 +785,7 @@ BasePrincipal::HasFirstpartyStorageAccess(mozIDOMWindow* aCheckWindow,
|
|||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
*aOutAllowed =
|
||||
ContentBlocking::ShouldAllowAccessFor(win, uri, aRejectedReason);
|
||||
*aOutAllowed = ShouldAllowAccessFor(win, uri, aRejectedReason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ auto READ_CONTROL;
|
|||
auto WRITE_DAC;
|
||||
auto WRITE_OWNER;
|
||||
auto SYNCHRONIZE;
|
||||
auto TRANSPARENT;
|
||||
|
||||
auto MAXIMUM_ALLOWED;
|
||||
auto GENERIC_READ;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`preview queued previews (w/ the 1st finishing first) 1`] = `null`;
|
||||
|
||||
exports[`preview should generate previews 1`] = `null`;
|
||||
|
|
|
@ -117,9 +117,7 @@ export function showSource(cx, sourceId) {
|
|||
|
||||
dispatch(setPrimaryPaneTab("sources"));
|
||||
|
||||
dispatch({ type: "SHOW_SOURCE", source: null });
|
||||
dispatch(selectSource(cx, source.id));
|
||||
dispatch({ type: "SHOW_SOURCE", source });
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,8 @@ import { connect } from "../../utils/connect";
|
|||
|
||||
// Selectors
|
||||
import {
|
||||
getShownSource,
|
||||
getSelectedSource,
|
||||
getDebuggeeUrl,
|
||||
getMainThreadHost,
|
||||
getExpandedState,
|
||||
getProjectDirectoryRoot,
|
||||
getDisplayedSources,
|
||||
|
@ -40,25 +39,23 @@ import {
|
|||
getAllSources,
|
||||
getSourcesInsideGroup,
|
||||
} from "../../utils/sources-tree";
|
||||
import { parse } from "../../utils/url";
|
||||
import { getRawSourceURL } from "../../utils/source";
|
||||
|
||||
function shouldAutoExpand(depth, item, debuggeeUrl, projectRoot) {
|
||||
function shouldAutoExpand(depth, item, mainThreadHost, projectRoot) {
|
||||
if (projectRoot != "" || depth !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { host } = parse(debuggeeUrl);
|
||||
return item.name === host;
|
||||
return item.name === mainThreadHost;
|
||||
}
|
||||
|
||||
class SourcesTree extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { debuggeeUrl, sources, threads } = this.props;
|
||||
const { mainThreadHost, sources, threads } = this.props;
|
||||
|
||||
this.state = createTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
sources,
|
||||
threads,
|
||||
});
|
||||
|
@ -67,7 +64,7 @@ class SourcesTree extends Component {
|
|||
static get propTypes() {
|
||||
return {
|
||||
cx: PropTypes.object.isRequired,
|
||||
debuggeeUrl: PropTypes.string.isRequired,
|
||||
mainThreadHost: PropTypes.string.isRequired,
|
||||
expanded: PropTypes.object.isRequired,
|
||||
focusItem: PropTypes.func.isRequired,
|
||||
focused: PropTypes.object,
|
||||
|
@ -75,7 +72,6 @@ class SourcesTree extends Component {
|
|||
selectSource: PropTypes.func.isRequired,
|
||||
selectedSource: PropTypes.object,
|
||||
setExpandedState: PropTypes.func.isRequired,
|
||||
shownSource: PropTypes.object,
|
||||
sourceCount: PropTypes.number,
|
||||
sources: PropTypes.object.isRequired,
|
||||
threads: PropTypes.array.isRequired,
|
||||
|
@ -85,9 +81,8 @@ class SourcesTree extends Component {
|
|||
componentWillReceiveProps(nextProps) {
|
||||
const {
|
||||
projectRoot,
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
sources,
|
||||
shownSource,
|
||||
selectedSource,
|
||||
threads,
|
||||
} = this.props;
|
||||
|
@ -95,7 +90,7 @@ class SourcesTree extends Component {
|
|||
|
||||
if (
|
||||
projectRoot != nextProps.projectRoot ||
|
||||
debuggeeUrl != nextProps.debuggeeUrl ||
|
||||
mainThreadHost != nextProps.mainThreadHost ||
|
||||
threads != nextProps.threads ||
|
||||
nextProps.sourceCount === 0
|
||||
) {
|
||||
|
@ -104,17 +99,12 @@ class SourcesTree extends Component {
|
|||
return this.setState(
|
||||
createTree({
|
||||
sources: nextProps.sources,
|
||||
debuggeeUrl: nextProps.debuggeeUrl,
|
||||
mainThreadHost: nextProps.mainThreadHost,
|
||||
threads: nextProps.threads,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (nextProps.shownSource && nextProps.shownSource != shownSource) {
|
||||
const listItems = getDirectories(nextProps.shownSource, sourceTree);
|
||||
return this.setState({ listItems });
|
||||
}
|
||||
|
||||
if (
|
||||
nextProps.selectedSource &&
|
||||
nextProps.selectedSource != selectedSource
|
||||
|
@ -133,7 +123,7 @@ class SourcesTree extends Component {
|
|||
newSources: nextProps.sources,
|
||||
threads: nextProps.threads,
|
||||
prevSources: sources,
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
uncollapsedTree,
|
||||
sourceTree,
|
||||
});
|
||||
|
@ -215,7 +205,7 @@ class SourcesTree extends Component {
|
|||
};
|
||||
|
||||
renderItem = (item, depth, focused, _, expanded, { setExpanded }) => {
|
||||
const { debuggeeUrl, projectRoot, threads } = this.props;
|
||||
const { mainThreadHost, projectRoot, threads } = this.props;
|
||||
|
||||
return (
|
||||
<SourcesTreeItem
|
||||
|
@ -223,12 +213,11 @@ class SourcesTree extends Component {
|
|||
threads={threads}
|
||||
depth={depth}
|
||||
focused={focused}
|
||||
autoExpand={shouldAutoExpand(depth, item, debuggeeUrl, projectRoot)}
|
||||
autoExpand={shouldAutoExpand(depth, item, mainThreadHost, projectRoot)}
|
||||
expanded={expanded}
|
||||
focusItem={this.onFocus}
|
||||
selectItem={this.selectItem}
|
||||
source={getSource(item, this.props)}
|
||||
debuggeeUrl={debuggeeUrl}
|
||||
projectRoot={projectRoot}
|
||||
setExpanded={setExpanded}
|
||||
getSourcesGroups={this.getSourcesGroups}
|
||||
|
@ -307,15 +296,13 @@ function getSourceForTree(state, displayedSources, source) {
|
|||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const selectedSource = getSelectedSource(state);
|
||||
const shownSource = getShownSource(state);
|
||||
const displayedSources = getDisplayedSources(state);
|
||||
|
||||
return {
|
||||
threads: props.threads,
|
||||
cx: getContext(state),
|
||||
shownSource: getSourceForTree(state, displayedSources, shownSource),
|
||||
selectedSource: getSourceForTree(state, displayedSources, selectedSource),
|
||||
debuggeeUrl: getDebuggeeUrl(state),
|
||||
mainThreadHost: getMainThreadHost(state),
|
||||
expanded: getExpandedState(state),
|
||||
focused: getFocusedSourceItem(state),
|
||||
projectRoot: getProjectDirectoryRoot(state),
|
||||
|
|
|
@ -44,7 +44,6 @@ class SourceTreeItem extends Component {
|
|||
blackBoxSources: PropTypes.func.isRequired,
|
||||
clearProjectDirectoryRoot: PropTypes.func.isRequired,
|
||||
cx: PropTypes.object.isRequired,
|
||||
debuggeeUrl: PropTypes.string.isRequired,
|
||||
depth: PropTypes.number.isRequired,
|
||||
expanded: PropTypes.bool.isRequired,
|
||||
extensionName: PropTypes.string,
|
||||
|
@ -279,13 +278,7 @@ class SourceTreeItem extends Component {
|
|||
}
|
||||
|
||||
renderIcon(item, depth) {
|
||||
const {
|
||||
debuggeeUrl,
|
||||
projectRoot,
|
||||
source,
|
||||
hasPrettyTab,
|
||||
threads,
|
||||
} = this.props;
|
||||
const { projectRoot, source, hasPrettyTab, threads } = this.props;
|
||||
|
||||
if (item.name === "webpack://") {
|
||||
return <AccessibleImage className="webpack" />;
|
||||
|
@ -301,13 +294,7 @@ class SourceTreeItem extends Component {
|
|||
|
||||
if (thread) {
|
||||
const icon = thread.targetType.includes("worker") ? "worker" : "window";
|
||||
return (
|
||||
<AccessibleImage
|
||||
className={classnames(icon, {
|
||||
debuggee: debuggeeUrl && debuggeeUrl.includes(item.name),
|
||||
})}
|
||||
/>
|
||||
);
|
||||
return <AccessibleImage className={classnames(icon)} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ describe("SourcesTree", () => {
|
|||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("recreates tree if debuggeeUrl is changed", async () => {
|
||||
it("recreates tree if mainThreadHost is changed", async () => {
|
||||
const { component, props, defaultState } = render();
|
||||
const sources = {
|
||||
FakeThread: {
|
||||
|
@ -157,7 +157,7 @@ describe("SourcesTree", () => {
|
|||
|
||||
await component.setProps({
|
||||
...props,
|
||||
debuggeeUrl: "mozilla",
|
||||
mainThreadHost: "mozilla",
|
||||
sources,
|
||||
});
|
||||
|
||||
|
@ -173,7 +173,8 @@ describe("SourcesTree", () => {
|
|||
const newSource = createMockDisplaySource(
|
||||
"server1.conn13.child1/43",
|
||||
"http://mdn.com/four.js",
|
||||
true
|
||||
true,
|
||||
"FakeThread1"
|
||||
);
|
||||
|
||||
const newThreadSources = {
|
||||
|
@ -387,7 +388,7 @@ function generateDefaults(overrides) {
|
|||
selectSource: jest.fn(),
|
||||
setExpandedState: jest.fn(),
|
||||
sources: defaultSources,
|
||||
debuggeeUrl: "http://mdn.com",
|
||||
mainThreadHost: "mdn.com",
|
||||
clearProjectDirectoryRoot: jest.fn(),
|
||||
setProjectDirectoryRoot: jest.fn(),
|
||||
focusItem: jest.fn(),
|
||||
|
@ -417,9 +418,9 @@ function render(overrides = {}) {
|
|||
return { component, props, defaultState, instance };
|
||||
}
|
||||
|
||||
function createMockDisplaySource(id, url, isBlackBoxed = false) {
|
||||
function createMockDisplaySource(id, url, isBlackBoxed = false, thread) {
|
||||
return {
|
||||
...makeMockDisplaySource(url, id),
|
||||
...makeMockDisplaySource(url, id, thread),
|
||||
isBlackBoxed,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -554,7 +554,6 @@ function generateDefaults(overrides) {
|
|||
expanded: false,
|
||||
item,
|
||||
source,
|
||||
debuggeeUrl: "http://mdn.com",
|
||||
projectRoot: "",
|
||||
clearProjectDirectoryRoot: jest.fn(),
|
||||
setProjectDirectoryRoot: jest.fn(),
|
||||
|
|
|
@ -135,7 +135,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
Array [
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/three.js",
|
||||
"displayURL": Object {
|
||||
"filename": "three.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/three.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/41",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -143,6 +148,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "three.js",
|
||||
"path": "FakeThread/mdn.com/three.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/three.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/three.js",
|
||||
|
@ -155,7 +177,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"contents": Array [
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/four.js",
|
||||
"displayURL": Object {
|
||||
"filename": "four.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/four.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/42",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -163,6 +190,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "four.js",
|
||||
"path": "FakeThread/mdn.com/four.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/four.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/four.js",
|
||||
|
@ -173,7 +217,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/four.js [original]",
|
||||
"displayURL": Object {
|
||||
"filename": "four.js [original]",
|
||||
"group": "mdn.com",
|
||||
"path": "/four.js%20[original]",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/42/originalSource-sha",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -181,6 +230,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": true,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "four.js%20[original]",
|
||||
"path": "FakeThread/mdn.com/four.js%20[original]",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/four.js [original]",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/four.js [original]",
|
||||
|
@ -191,7 +257,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/one.js",
|
||||
"displayURL": Object {
|
||||
"filename": "one.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/one.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/39",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -199,6 +270,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "one.js",
|
||||
"path": "FakeThread/mdn.com/one.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/one.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/one.js",
|
||||
|
@ -209,7 +297,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/three.js",
|
||||
"displayURL": Object {
|
||||
"filename": "three.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/three.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/41",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -217,6 +310,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "three.js",
|
||||
"path": "FakeThread/mdn.com/three.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/three.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/three.js",
|
||||
|
@ -227,7 +337,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/two.js",
|
||||
"displayURL": Object {
|
||||
"filename": "two.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/two.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/40",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -235,6 +350,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "two.js",
|
||||
"path": "FakeThread/mdn.com/two.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/two.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/two.js",
|
||||
|
@ -254,7 +386,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"contents": Array [
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/four.js",
|
||||
"displayURL": Object {
|
||||
"filename": "four.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/four.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/42",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -262,6 +399,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "four.js",
|
||||
"path": "FakeThread/mdn.com/four.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/four.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/four.js",
|
||||
|
@ -272,7 +426,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/four.js [original]",
|
||||
"displayURL": Object {
|
||||
"filename": "four.js [original]",
|
||||
"group": "mdn.com",
|
||||
"path": "/four.js%20[original]",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/42/originalSource-sha",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -280,6 +439,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": true,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "four.js%20[original]",
|
||||
"path": "FakeThread/mdn.com/four.js%20[original]",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/four.js [original]",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/four.js [original]",
|
||||
|
@ -290,7 +466,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/one.js",
|
||||
"displayURL": Object {
|
||||
"filename": "one.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/one.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/39",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -298,6 +479,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "one.js",
|
||||
"path": "FakeThread/mdn.com/one.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/one.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/one.js",
|
||||
|
@ -308,7 +506,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/three.js",
|
||||
"displayURL": Object {
|
||||
"filename": "three.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/three.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/41",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -316,6 +519,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "three.js",
|
||||
"path": "FakeThread/mdn.com/three.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/three.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/three.js",
|
||||
|
@ -326,7 +546,12 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
},
|
||||
Object {
|
||||
"contents": Object {
|
||||
"displayURL": "http://mdn.com/two.js",
|
||||
"displayURL": Object {
|
||||
"filename": "two.js",
|
||||
"group": "mdn.com",
|
||||
"path": "/two.js",
|
||||
"search": "",
|
||||
},
|
||||
"extensionName": null,
|
||||
"id": "server1.conn13.child1/40",
|
||||
"isBlackBoxed": false,
|
||||
|
@ -334,6 +559,23 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
|
|||
"isOriginal": false,
|
||||
"isPrettyPrinted": false,
|
||||
"isWasm": false,
|
||||
"parts": Array [
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "FakeThread",
|
||||
"path": "FakeThread",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": "http://www.example.com",
|
||||
"part": "mdn.com",
|
||||
"path": "FakeThread/mdn.com",
|
||||
},
|
||||
Object {
|
||||
"mainThreadHostIfRoot": null,
|
||||
"part": "two.js",
|
||||
"path": "FakeThread/mdn.com/two.js",
|
||||
},
|
||||
],
|
||||
"relativeUrl": "http://mdn.com/two.js",
|
||||
"thread": "FakeThread",
|
||||
"url": "http://mdn.com/two.js",
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,7 +26,6 @@ class ManagedTree extends Component {
|
|||
focused: PropTypes.any,
|
||||
getPath: PropTypes.func.isRequired,
|
||||
highlightItems: PropTypes.array,
|
||||
listItems: PropTypes.array,
|
||||
onCollapse: PropTypes.func.isRequired,
|
||||
onExpand: PropTypes.func.isRequired,
|
||||
onFocus: PropTypes.func.isRequired,
|
||||
|
@ -35,11 +34,7 @@ class ManagedTree extends Component {
|
|||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { listItems, highlightItems } = this.props;
|
||||
if (nextProps.listItems && nextProps.listItems != listItems) {
|
||||
this.expandListItems(nextProps.listItems);
|
||||
}
|
||||
|
||||
const { highlightItems } = this.props;
|
||||
if (
|
||||
nextProps.highlightItems &&
|
||||
nextProps.highlightItems != highlightItems &&
|
||||
|
@ -85,32 +80,14 @@ class ManagedTree extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
expandListItems(listItems) {
|
||||
const { expanded } = this.state;
|
||||
listItems.forEach(item => expanded.add(this.props.getPath(item)));
|
||||
this.props.onFocus(listItems[0]);
|
||||
this.setState({ expanded });
|
||||
}
|
||||
|
||||
highlightItem(highlightItems) {
|
||||
const { expanded } = this.state;
|
||||
// This file is visible, so we highlight it.
|
||||
if (expanded.has(this.props.getPath(highlightItems[0]))) {
|
||||
this.props.onFocus(highlightItems[0]);
|
||||
} else {
|
||||
// Look at folders starting from the top-level until finds a
|
||||
// closed folder and highlights this folder
|
||||
const index = highlightItems
|
||||
.reverse()
|
||||
.findIndex(
|
||||
item =>
|
||||
!expanded.has(this.props.getPath(item)) && item.name !== "root"
|
||||
);
|
||||
|
||||
if (highlightItems[index]) {
|
||||
this.props.onFocus(highlightItems[index]);
|
||||
}
|
||||
}
|
||||
highlightItems.forEach(item => {
|
||||
expanded.add(this.props.getPath(item));
|
||||
});
|
||||
this.props.onFocus(highlightItems[0]);
|
||||
this.setState({ expanded });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -68,14 +68,6 @@ describe("ManagedTree", () => {
|
|||
expect(
|
||||
shallow(<ManagedTree {...getTestContent().props} />)
|
||||
).toMatchSnapshot());
|
||||
it("expands list items", () => {
|
||||
const { props, testTree } = getTestContent();
|
||||
const wrapper = shallow(<ManagedTree {...props} />);
|
||||
wrapper.setProps({
|
||||
listItems: testTree.b.children,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
it("highlights list items", () => {
|
||||
const { props, testTree } = getTestContent();
|
||||
const wrapper = shallow(<ManagedTree {...props} />);
|
||||
|
|
|
@ -1,62 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ManagedTree expands list items 1`] = `
|
||||
<div
|
||||
className="managed-tree"
|
||||
>
|
||||
<Tree
|
||||
autoExpandAll={true}
|
||||
autoExpandDepth={1}
|
||||
getChildren={[Function]}
|
||||
getKey={[Function]}
|
||||
getParent={[Function]}
|
||||
getPath={[Function]}
|
||||
getRoots={[Function]}
|
||||
isExpanded={[Function]}
|
||||
itemHeight={24}
|
||||
listItems={
|
||||
Array [
|
||||
Object {
|
||||
"value": "A",
|
||||
},
|
||||
Object {
|
||||
"value": "B",
|
||||
},
|
||||
Object {
|
||||
"value": "C",
|
||||
},
|
||||
Object {
|
||||
"value": "D",
|
||||
},
|
||||
Object {
|
||||
"value": "E",
|
||||
},
|
||||
]
|
||||
}
|
||||
onCollapse={[Function]}
|
||||
onExpand={[Function]}
|
||||
onFocus={
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"value": "A",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
renderItem={[Function]}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ManagedTree highlights list items 1`] = `
|
||||
<div
|
||||
className="managed-tree"
|
||||
|
@ -72,19 +15,19 @@ exports[`ManagedTree highlights list items 1`] = `
|
|||
highlightItems={
|
||||
Array [
|
||||
Object {
|
||||
"value": 5,
|
||||
},
|
||||
Object {
|
||||
"value": 4,
|
||||
},
|
||||
Object {
|
||||
"value": 3,
|
||||
"value": 1,
|
||||
},
|
||||
Object {
|
||||
"value": 2,
|
||||
},
|
||||
Object {
|
||||
"value": 1,
|
||||
"value": 3,
|
||||
},
|
||||
Object {
|
||||
"value": 4,
|
||||
},
|
||||
Object {
|
||||
"value": 5,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -97,7 +40,7 @@ exports[`ManagedTree highlights list items 1`] = `
|
|||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"value": 5,
|
||||
"value": 1,
|
||||
},
|
||||
],
|
||||
],
|
||||
|
|
|
@ -14,7 +14,6 @@ import { prefs, features } from "../utils/prefs";
|
|||
export const initialUIState = () => ({
|
||||
selectedPrimaryPaneTab: "sources",
|
||||
activeSearch: null,
|
||||
shownSource: null,
|
||||
startPanelCollapsed: prefs.startPanelCollapsed,
|
||||
endPanelCollapsed: prefs.endPanelCollapsed,
|
||||
frameworkGroupingOn: prefs.frameworkGroupingOn,
|
||||
|
@ -64,10 +63,6 @@ function update(state = initialUIState(), action) {
|
|||
return { ...state, orientation: action.orientation };
|
||||
}
|
||||
|
||||
case "SHOW_SOURCE": {
|
||||
return { ...state, shownSource: action.source };
|
||||
}
|
||||
|
||||
case "TOGGLE_PANE": {
|
||||
if (action.position == "start") {
|
||||
prefs.startPanelCollapsed = action.paneCollapsed;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
import { createSelector } from "reselect";
|
||||
import { shallowEqual } from "../utils/shallow-equal";
|
||||
import { getPathParts, getFileExtension } from "../utils/sources-tree/utils";
|
||||
import { getDisplayURL } from "../utils/sources-tree/getURL";
|
||||
|
||||
import {
|
||||
getPrettySourceURL,
|
||||
|
@ -29,7 +31,10 @@ import {
|
|||
getBreakableLinesForSourceActors,
|
||||
} from "./source-actors";
|
||||
import { getSourceTextContent } from "./sources-content";
|
||||
import { getAllThreads } from "./threads";
|
||||
import { getAllThreads, getMainThreadHost } from "./threads";
|
||||
|
||||
const IGNORED_URLS = ["debugger eval code", "XStringBundle"];
|
||||
const IGNORED_EXTENSIONS = ["css", "svg", "png"];
|
||||
|
||||
export function hasSource(state, id) {
|
||||
return state.sources.sources.has(id);
|
||||
|
@ -237,7 +242,8 @@ const getDisplayedSourceIDs = createSelector(
|
|||
isDescendantOfRoot(source, rootWithoutThreadActor) &&
|
||||
(!source.isExtension ||
|
||||
chromeAndExtensionsEnabled ||
|
||||
debuggeeIsWebExtension);
|
||||
debuggeeIsWebExtension) &&
|
||||
!isSourceHiddenInSourceTree(source);
|
||||
if (!displayed) {
|
||||
continue;
|
||||
}
|
||||
|
@ -255,25 +261,35 @@ const getDisplayedSourceIDs = createSelector(
|
|||
export const getDisplayedSources = createSelector(
|
||||
getSourcesMap,
|
||||
getDisplayedSourceIDs,
|
||||
(sourcesMap, idsByThread) => {
|
||||
getMainThreadHost,
|
||||
(sourcesMap, idsByThread, mainThreadHost) => {
|
||||
const result = {};
|
||||
|
||||
for (const thread of Object.keys(idsByThread)) {
|
||||
const entriesByNoQueryURL = Object.create(null);
|
||||
|
||||
for (const id of idsByThread[thread]) {
|
||||
if (!result[thread]) {
|
||||
result[thread] = {};
|
||||
}
|
||||
const source = sourcesMap.get(id);
|
||||
const displayURL = getDisplayURL(source.url, mainThreadHost);
|
||||
|
||||
// Ignore source which have not been able to be sorted in a group by getDisplayURL
|
||||
// It should be only javascript: URLs and weird URLs without protocols.
|
||||
if (!displayURL.group) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const entry = {
|
||||
...source,
|
||||
displayURL: source.url,
|
||||
displayURL,
|
||||
parts: getPathParts(displayURL, thread, mainThreadHost),
|
||||
};
|
||||
|
||||
if (!result[thread]) {
|
||||
result[thread] = {};
|
||||
}
|
||||
result[thread][id] = entry;
|
||||
|
||||
const noQueryURL = stripQuery(entry.displayURL);
|
||||
const noQueryURL = stripQuery(entry.url);
|
||||
if (!entriesByNoQueryURL[noQueryURL]) {
|
||||
entriesByNoQueryURL[noQueryURL] = [];
|
||||
}
|
||||
|
@ -286,7 +302,7 @@ export const getDisplayedSources = createSelector(
|
|||
for (const noQueryURL in entriesByNoQueryURL) {
|
||||
const entries = entriesByNoQueryURL[noQueryURL];
|
||||
if (entries.length === 1) {
|
||||
entries[0].displayURL = noQueryURL;
|
||||
entries[0].displayURL = getDisplayURL(noQueryURL, mainThreadHost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +311,14 @@ export const getDisplayedSources = createSelector(
|
|||
}
|
||||
);
|
||||
|
||||
function isSourceHiddenInSourceTree(source) {
|
||||
return (
|
||||
IGNORED_EXTENSIONS.includes(getFileExtension(source)) ||
|
||||
IGNORED_URLS.includes(source.url) ||
|
||||
isPretty(source)
|
||||
);
|
||||
}
|
||||
|
||||
export function getSourceActorsForSource(state, id) {
|
||||
const actors = state.sources.actors[id];
|
||||
if (!actors) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
import { createSelector } from "reselect";
|
||||
import { parse } from "../utils/url";
|
||||
|
||||
export const getThreads = createSelector(
|
||||
state => state.threads.threads,
|
||||
|
@ -31,8 +32,19 @@ export function getMainThread(state) {
|
|||
return state.threads.threads.find(isMainThread);
|
||||
}
|
||||
|
||||
export function getDebuggeeUrl(state) {
|
||||
return getMainThread(state)?.url || "";
|
||||
/*
|
||||
* Gets domain from the main thread url (without www prefix)
|
||||
*/
|
||||
export function getMainThreadHost(state) {
|
||||
const url = getMainThread(state)?.url;
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
const { host } = parse(url);
|
||||
if (!host) {
|
||||
return null;
|
||||
}
|
||||
return host.startsWith("www.") ? host.substring("www.".length) : host;
|
||||
}
|
||||
|
||||
export function getThread(state, threadActor) {
|
||||
|
|
|
@ -14,10 +14,6 @@ export function getFrameworkGroupingState(state) {
|
|||
return state.ui.frameworkGroupingOn;
|
||||
}
|
||||
|
||||
export function getShownSource(state) {
|
||||
return state.ui.shownSource;
|
||||
}
|
||||
|
||||
export function getPaneCollapse(state, position) {
|
||||
if (position == "start") {
|
||||
return state.ui.startPanelCollapsed;
|
||||
|
|
|
@ -5,14 +5,11 @@
|
|||
import {
|
||||
nodeHasChildren,
|
||||
isPathDirectory,
|
||||
isInvalidUrl,
|
||||
partIsFile,
|
||||
createSourceNode,
|
||||
createDirectoryNode,
|
||||
getPathParts,
|
||||
} from "./utils";
|
||||
import { createTreeNodeMatcher, findNodeInContents } from "./treeOrder";
|
||||
import { getDisplayURL } from "./getURL";
|
||||
|
||||
function createNodeInTree(part, path, tree, index) {
|
||||
const node = createDirectoryNode(part, path, []);
|
||||
|
@ -30,21 +27,12 @@ function createNodeInTree(part, path, tree, index) {
|
|||
* 1. if it exists return it
|
||||
* 2. if it does not exist create it
|
||||
*/
|
||||
function findOrCreateNode(
|
||||
parts,
|
||||
subTree,
|
||||
path,
|
||||
part,
|
||||
index,
|
||||
url,
|
||||
debuggeeHost,
|
||||
source
|
||||
) {
|
||||
const addedPartIsFile = partIsFile(index, parts, url);
|
||||
function findOrCreateNode(source, subTree, path, part, index, mainThreadHost) {
|
||||
const addedPartIsFile = partIsFile(index, source.parts, source.displayURL);
|
||||
|
||||
const { found: childFound, index: childIndex } = findNodeInContents(
|
||||
subTree,
|
||||
createTreeNodeMatcher(part, !addedPartIsFile, debuggeeHost)
|
||||
createTreeNodeMatcher(part, !addedPartIsFile, mainThreadHost)
|
||||
);
|
||||
|
||||
// we create and enter the new node
|
||||
|
@ -62,7 +50,13 @@ function findOrCreateNode(
|
|||
// pass true to findNodeInContents to sort node by url
|
||||
const { index: insertIndex } = findNodeInContents(
|
||||
subTree,
|
||||
createTreeNodeMatcher(part, !addedPartIsFile, debuggeeHost, source, true)
|
||||
createTreeNodeMatcher(
|
||||
part,
|
||||
!addedPartIsFile,
|
||||
mainThreadHost,
|
||||
source,
|
||||
true
|
||||
)
|
||||
);
|
||||
return createNodeInTree(part, path, subTree, insertIndex);
|
||||
}
|
||||
|
@ -75,19 +69,16 @@ function findOrCreateNode(
|
|||
* walk the source tree to the final node for a given url,
|
||||
* adding new nodes along the way
|
||||
*/
|
||||
function traverseTree(url, tree, debuggeeHost, source, thread) {
|
||||
const parts = getPathParts(url, thread, debuggeeHost);
|
||||
return parts.reduce(
|
||||
(subTree, { part, path, debuggeeHostIfRoot }, index) =>
|
||||
function traverseTree(source, tree) {
|
||||
return source.parts.reduce(
|
||||
(subTree, { part, path, mainThreadHostIfRoot }, index) =>
|
||||
findOrCreateNode(
|
||||
parts,
|
||||
source,
|
||||
subTree,
|
||||
path,
|
||||
part,
|
||||
index,
|
||||
url,
|
||||
debuggeeHostIfRoot,
|
||||
source
|
||||
mainThreadHostIfRoot
|
||||
),
|
||||
tree
|
||||
);
|
||||
|
@ -96,7 +87,8 @@ function traverseTree(url, tree, debuggeeHost, source, thread) {
|
|||
/*
|
||||
* Add a source file to a directory node in the tree
|
||||
*/
|
||||
function addSourceToNode(node, url, source) {
|
||||
function addSourceToNode(node, source) {
|
||||
const url = source.displayURL;
|
||||
const isFile = !isPathDirectory(url.path);
|
||||
|
||||
if (node.type == "source" && !isFile) {
|
||||
|
@ -145,14 +137,8 @@ function addSourceToNode(node, url, source) {
|
|||
* @memberof utils/sources-tree
|
||||
* @static
|
||||
*/
|
||||
export function addToTree(tree, source, debuggeeHost, thread) {
|
||||
const url = getDisplayURL(source, debuggeeHost);
|
||||
export function addToTree(tree, source) {
|
||||
const finalNode = traverseTree(source, tree);
|
||||
|
||||
if (isInvalidUrl(url, source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const finalNode = traverseTree(url, tree, debuggeeHost, source, thread);
|
||||
|
||||
finalNode.contents = addSourceToNode(finalNode, url, source);
|
||||
finalNode.contents = addSourceToNode(finalNode, source);
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/* 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/>. */
|
||||
|
||||
export function formatTree(tree, depth = 0, str = "") {
|
||||
const whitespace = new Array(depth * 2).join(" ");
|
||||
|
||||
if (tree.type === "directory") {
|
||||
str += `${whitespace} - ${tree.name} path=${tree.path} \n`;
|
||||
tree.contents.forEach(t => {
|
||||
str = formatTree(t, depth + 1, str);
|
||||
});
|
||||
} else {
|
||||
str += `${whitespace} - ${tree.name} path=${tree.path} source_id=${tree.contents.id} \n`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
|
@ -24,20 +24,29 @@ export function getFilenameFromPath(pathname) {
|
|||
const NoDomain = "(no domain)";
|
||||
const def = { path: "", search: "", group: "", filename: "" };
|
||||
|
||||
export function getURL(source, defaultDomain = "") {
|
||||
export function getURL(source) {
|
||||
const { url } = source;
|
||||
if (!url) {
|
||||
return def;
|
||||
}
|
||||
return getURLInternal(url, defaultDomain);
|
||||
return getURLInternal(url);
|
||||
}
|
||||
|
||||
export function getDisplayURL(source, defaultDomain = "") {
|
||||
const { displayURL } = source;
|
||||
if (!displayURL) {
|
||||
/**
|
||||
* Compute the URL which may be displayed in the Source Tree.
|
||||
*
|
||||
* @param {String} url
|
||||
* The source absolute URL as a string
|
||||
* @param {String} defaultDomain
|
||||
* The host of the currently debugged web page.
|
||||
* @return URL Object
|
||||
* A URL object to represent this source.
|
||||
*/
|
||||
export function getDisplayURL(url, defaultDomain = "") {
|
||||
if (!url) {
|
||||
return def;
|
||||
}
|
||||
return getURLInternal(displayURL, defaultDomain);
|
||||
return getURLInternal(url, defaultDomain);
|
||||
}
|
||||
|
||||
function getURLInternal(url, defaultDomain) {
|
||||
|
|
|
@ -9,10 +9,8 @@
|
|||
|
||||
export { addToTree } from "./addToTree";
|
||||
export { collapseTree } from "./collapseTree";
|
||||
export { formatTree } from "./formatTree";
|
||||
export { getDirectories, findSourceTreeNodes } from "./getDirectories";
|
||||
export { getFilenameFromPath, getURL } from "./getURL";
|
||||
export { sortTree } from "./sortTree";
|
||||
export { createTree, updateTree } from "./updateTree";
|
||||
|
||||
export * from "./utils";
|
||||
|
|
|
@ -8,11 +8,9 @@ DIRS += []
|
|||
CompiledModules(
|
||||
"addToTree.js",
|
||||
"collapseTree.js",
|
||||
"formatTree.js",
|
||||
"getDirectories.js",
|
||||
"getURL.js",
|
||||
"index.js",
|
||||
"sortTree.js",
|
||||
"treeOrder.js",
|
||||
"updateTree.js",
|
||||
"utils.js",
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/* 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 { nodeHasChildren, isExactUrlMatch } from "./utils";
|
||||
|
||||
/**
|
||||
* Look at the nodes in the source tree, and determine the index of where to
|
||||
* insert a new node. The ordering is index -> folder -> file.
|
||||
* @memberof utils/sources-tree
|
||||
* @static
|
||||
*/
|
||||
export function sortTree(tree, debuggeeUrl = "") {
|
||||
return tree.contents.sort((previousNode, currentNode) => {
|
||||
const currentNodeIsDir = nodeHasChildren(currentNode);
|
||||
const previousNodeIsDir = nodeHasChildren(previousNode);
|
||||
if (currentNode.name === "(index)") {
|
||||
return 1;
|
||||
} else if (previousNode.name === "(index)") {
|
||||
return -1;
|
||||
} else if (isExactUrlMatch(currentNode.name, debuggeeUrl)) {
|
||||
return 1;
|
||||
} else if (isExactUrlMatch(previousNode.name, debuggeeUrl)) {
|
||||
return -1;
|
||||
// If neither is the case, continue to compare alphabetically
|
||||
} else if (previousNodeIsDir && !currentNodeIsDir) {
|
||||
return -1;
|
||||
} else if (!previousNodeIsDir && currentNodeIsDir) {
|
||||
return 1;
|
||||
}
|
||||
return previousNode.name.localeCompare(currentNode.name);
|
||||
});
|
||||
}
|
|
@ -52,14 +52,6 @@ exports[`sources-tree addToTree does not mangle encoded URLs 1`] = `
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`sources-tree addToTree excludes javascript: URLs from the tree 1`] = `
|
||||
" - root path=
|
||||
- FakeThread path=FakeThread
|
||||
- example.com path=FakeThread/example.com
|
||||
- source1.js path=FakeThread/example.com/source1.js source_id=actor2
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`sources-tree addToTree name does include query params 1`] = `
|
||||
" - root path=
|
||||
- FakeThread path=FakeThread
|
||||
|
|
|
@ -31,7 +31,24 @@ exports[`calls updateTree.js adds one source 1`] = `
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/\\",
|
||||
\\"search\\": \\"\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"(index)\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -49,7 +66,29 @@ exports[`calls updateTree.js adds one source 1`] = `
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/source1.js\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/source1.js\\",
|
||||
\\"search\\": \\"\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"source1.js\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"source1.js\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name/source1.js\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -91,7 +130,24 @@ exports[`calls updateTree.js adds two sources 1`] = `
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/\\",
|
||||
\\"search\\": \\"\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"(index)\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -109,7 +165,29 @@ exports[`calls updateTree.js adds two sources 1`] = `
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/source1.js\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/source1.js\\",
|
||||
\\"search\\": \\"\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"source1.js\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"source1.js\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name/source1.js\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -127,7 +205,29 @@ exports[`calls updateTree.js adds two sources 1`] = `
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/source2.js\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/source2.js\\",
|
||||
\\"search\\": \\"\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"source2.js\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"source2.js\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name/source2.js\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -169,7 +269,24 @@ exports[`calls updateTree.js shows all the sources 1`] = `
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/\\",
|
||||
\\"search\\": \\"\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"(index)\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -187,7 +304,29 @@ exports[`calls updateTree.js shows all the sources 1`] = `
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/source1.js\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/source1.js\\",
|
||||
\\"search\\": \\"\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"source1.js\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"source1.js\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name/source1.js\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -229,7 +368,29 @@ exports[`calls updateTree.js update sources that change their display URL 1`] =
|
|||
\\"extensionName\\": null,
|
||||
\\"isExtension\\": false,
|
||||
\\"isOriginal\\": false,
|
||||
\\"displayURL\\": \\"https://davidwalsh.name/?param\\"
|
||||
\\"displayURL\\": {
|
||||
\\"path\\": \\"/\\",
|
||||
\\"search\\": \\"?param\\",
|
||||
\\"group\\": \\"davidwalsh.name\\",
|
||||
\\"filename\\": \\"(index)\\"
|
||||
},
|
||||
\\"parts\\": [
|
||||
{
|
||||
\\"part\\": \\"FakeThread\\",
|
||||
\\"path\\": \\"FakeThread\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"davidwalsh.name\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name\\",
|
||||
\\"mainThreadHostIfRoot\\": \\"http://www.example.com\\"
|
||||
},
|
||||
{
|
||||
\\"part\\": \\"?param\\",
|
||||
\\"path\\": \\"FakeThread/davidwalsh.name/?param\\",
|
||||
\\"mainThreadHostIfRoot\\": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -4,20 +4,23 @@
|
|||
|
||||
/* eslint max-nested-callbacks: ["error", 4]*/
|
||||
|
||||
import { makeMockDisplaySource } from "../../../utils/test-mockup";
|
||||
import { makeMockDisplaySource, formatTree } from "../../../utils/test-mockup";
|
||||
|
||||
import {
|
||||
addToTree,
|
||||
createDirectoryNode,
|
||||
createSourceNode,
|
||||
createTree,
|
||||
formatTree,
|
||||
nodeHasChildren,
|
||||
} from "../index";
|
||||
|
||||
function createSourcesMap(sources) {
|
||||
const sourcesMap = sources.reduce((map, source) => {
|
||||
map[source.id] = makeMockDisplaySource(source.url, source.id);
|
||||
map[source.id] = makeMockDisplaySource(
|
||||
source.url,
|
||||
source.id,
|
||||
source.thread
|
||||
);
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
|
@ -62,7 +65,7 @@ describe("sources-tree", () => {
|
|||
);
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source1, "http://example.com/", "FakeThread");
|
||||
addToTree(tree, source1);
|
||||
expect(tree.contents).toHaveLength(1);
|
||||
|
||||
const base = tree.contents[0].contents[0];
|
||||
|
@ -80,11 +83,12 @@ describe("sources-tree", () => {
|
|||
it("builds a path-based tree for webpack URLs", () => {
|
||||
const source1 = makeMockDisplaySource(
|
||||
"webpack:///foo/source1.js",
|
||||
"actor1"
|
||||
"actor1",
|
||||
""
|
||||
);
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source1, "http://example.com/", "");
|
||||
addToTree(tree, source1);
|
||||
expect(tree.contents).toHaveLength(1);
|
||||
|
||||
const base = tree.contents[0];
|
||||
|
@ -102,11 +106,12 @@ describe("sources-tree", () => {
|
|||
it("builds a path-based tree for webpack URLs with absolute path", () => {
|
||||
const source1 = makeMockDisplaySource(
|
||||
"webpack:////Users/foo/source1.js",
|
||||
"actor1"
|
||||
"actor1",
|
||||
""
|
||||
);
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source1, "http://example.com/", "");
|
||||
addToTree(tree, source1);
|
||||
expect(tree.contents).toHaveLength(1);
|
||||
|
||||
const base = tree.contents[0];
|
||||
|
@ -126,10 +131,14 @@ describe("sources-tree", () => {
|
|||
});
|
||||
|
||||
it("handles url with no filename", function() {
|
||||
const source1 = makeMockDisplaySource("http://example.com/", "actor1");
|
||||
const source1 = makeMockDisplaySource(
|
||||
"http://example.com/",
|
||||
"actor1",
|
||||
""
|
||||
);
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source1, "http://example.com/", "");
|
||||
addToTree(tree, source1);
|
||||
expect(tree.contents).toHaveLength(1);
|
||||
|
||||
const base = tree.contents[0];
|
||||
|
@ -151,7 +160,7 @@ describe("sources-tree", () => {
|
|||
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source1, "http://example.com/", "FakeThread");
|
||||
addToTree(tree, source1);
|
||||
const childNode = getChildNode(tree, 0, 0, 0, 0);
|
||||
expect(childNode.name).toEqual(sourceName);
|
||||
expect(formatTree(tree)).toMatchSnapshot();
|
||||
|
@ -167,7 +176,7 @@ describe("sources-tree", () => {
|
|||
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source1, "http://example.com/", "FakeThread");
|
||||
addToTree(tree, source1);
|
||||
expect(formatTree(tree)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -186,7 +195,7 @@ describe("sources-tree", () => {
|
|||
const sourceMap = { FakeThread: createSourcesMap(sources) };
|
||||
const tree = createTree({
|
||||
sources: sourceMap,
|
||||
debuggeeUrl: "",
|
||||
mainThreadHost: "",
|
||||
threads: [
|
||||
{
|
||||
actor: "FakeThread",
|
||||
|
@ -215,7 +224,7 @@ describe("sources-tree", () => {
|
|||
const sourceMap = { FakeThread: createSourcesMap(sources) };
|
||||
const tree = createTree({
|
||||
sources: sourceMap,
|
||||
debuggeeUrl: "",
|
||||
mainThreadHost: "",
|
||||
threads: [
|
||||
{
|
||||
actor: "FakeThread",
|
||||
|
@ -240,15 +249,22 @@ describe("sources-tree", () => {
|
|||
url: "https://davidwalsh.name/util.js",
|
||||
},
|
||||
];
|
||||
const sources2 = [
|
||||
{
|
||||
id: "server1.conn13.child1/37",
|
||||
url: "https://davidwalsh.name/util.js",
|
||||
thread: "FakeThread2",
|
||||
},
|
||||
];
|
||||
|
||||
const sourceMap = {
|
||||
FakeThread: createSourcesMap(sources),
|
||||
FakeThread2: createSourcesMap([sources[1]]),
|
||||
FakeThread2: createSourcesMap(sources2),
|
||||
};
|
||||
|
||||
const tree = createTree({
|
||||
sources: sourceMap,
|
||||
debuggeeUrl: "https://davidwalsh.name",
|
||||
mainThreadHost: "davidwalsh.name",
|
||||
threads: [
|
||||
{
|
||||
actor: "FakeThread",
|
||||
|
@ -275,38 +291,11 @@ describe("sources-tree", () => {
|
|||
expect(formatTree(tree)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("excludes javascript: URLs from the tree", () => {
|
||||
const source1 = makeMockDisplaySource(
|
||||
"javascript:alert('Hello World')",
|
||||
"actor1"
|
||||
);
|
||||
const source2 = makeMockDisplaySource(
|
||||
"http://example.com/source1.js",
|
||||
"actor2"
|
||||
);
|
||||
const source3 = makeMockDisplaySource(
|
||||
"javascript:let i = 10; while (i > 0) i--; console.log(i);",
|
||||
"actor3"
|
||||
);
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source1, "http://example.com/", "FakeThread");
|
||||
addToTree(tree, source2, "http://example.com/", "FakeThread");
|
||||
addToTree(tree, source3, "http://example.com/", "FakeThread");
|
||||
|
||||
const base = tree.contents[0].contents[0];
|
||||
expect(tree.contents).toHaveLength(1);
|
||||
|
||||
const source1Node = base.contents[0];
|
||||
expect(source1Node.name).toBe("source1.js");
|
||||
expect(formatTree(tree)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("correctly parses file sources", () => {
|
||||
const source = makeMockDisplaySource("file:///a/b.js", "actor1");
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
|
||||
addToTree(tree, source, "file:///a/index.html", "FakeThread");
|
||||
addToTree(tree, source);
|
||||
expect(tree.contents).toHaveLength(1);
|
||||
|
||||
const base = tree.contents[0].contents[0];
|
||||
|
@ -336,9 +325,7 @@ describe("sources-tree", () => {
|
|||
|
||||
const sources = createSourcesList(testData);
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
sources.forEach(source =>
|
||||
addToTree(tree, source, "https://unpkg.com/", "FakeThread")
|
||||
);
|
||||
sources.forEach(source => addToTree(tree, source));
|
||||
expect(formatTree(tree)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -357,9 +344,7 @@ describe("sources-tree", () => {
|
|||
|
||||
const sources = createSourcesList(testData);
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
sources.forEach(source =>
|
||||
addToTree(tree, source, "https://unpkg.com/", "FakeThread")
|
||||
);
|
||||
sources.forEach(source => addToTree(tree, source));
|
||||
expect(formatTree(tree)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,33 +2,31 @@
|
|||
* 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 { makeMockDisplaySource } from "../../../utils/test-mockup";
|
||||
import { makeMockDisplaySource, formatTree } from "../../../utils/test-mockup";
|
||||
|
||||
import {
|
||||
collapseTree,
|
||||
formatTree,
|
||||
addToTree,
|
||||
createDirectoryNode,
|
||||
} from "../index";
|
||||
import { collapseTree, addToTree, createDirectoryNode } from "../index";
|
||||
|
||||
const abcSource = makeMockDisplaySource(
|
||||
"http://example.com/a/b/c.js",
|
||||
"actor1"
|
||||
"actor1",
|
||||
"Main Thread"
|
||||
);
|
||||
const abcdeSource = makeMockDisplaySource(
|
||||
"http://example.com/a/b/c/d/e.js",
|
||||
"actor2"
|
||||
"actor2",
|
||||
"Main Thread"
|
||||
);
|
||||
const abxSource = makeMockDisplaySource(
|
||||
"http://example.com/a/b/x.js",
|
||||
"actor3"
|
||||
"actor3",
|
||||
"Main Thread"
|
||||
);
|
||||
|
||||
describe("sources tree", () => {
|
||||
describe("collapseTree", () => {
|
||||
it("can collapse a single source", () => {
|
||||
const fullTree = createDirectoryNode("root", "", []);
|
||||
addToTree(fullTree, abcSource, "http://example.com/", "Main Thread");
|
||||
addToTree(fullTree, abcSource);
|
||||
expect(fullTree.contents).toHaveLength(1);
|
||||
const tree = collapseTree(fullTree);
|
||||
|
||||
|
@ -48,7 +46,7 @@ describe("sources tree", () => {
|
|||
|
||||
it("correctly merges in a collapsed source with a deeper level", () => {
|
||||
const fullTree = createDirectoryNode("root", "", []);
|
||||
addToTree(fullTree, abcSource, "http://example.com/", "Main Thread");
|
||||
addToTree(fullTree, abcSource);
|
||||
addToTree(fullTree, abcdeSource, "http://example.com/", "Main Thread");
|
||||
const tree = collapseTree(fullTree);
|
||||
|
||||
|
@ -73,8 +71,8 @@ describe("sources tree", () => {
|
|||
|
||||
it("correctly merges in a collapsed source with a shallower level", () => {
|
||||
const fullTree = createDirectoryNode("root", "", []);
|
||||
addToTree(fullTree, abcSource, "http://example.com/", "Main Thread");
|
||||
addToTree(fullTree, abxSource, "http://example.com/", "Main Thread");
|
||||
addToTree(fullTree, abcSource);
|
||||
addToTree(fullTree, abxSource);
|
||||
const tree = collapseTree(fullTree);
|
||||
|
||||
expect(tree.contents).toHaveLength(1);
|
||||
|
@ -97,7 +95,7 @@ describe("sources tree", () => {
|
|||
|
||||
it("correctly merges in a collapsed source with the same level", () => {
|
||||
const fullTree = createDirectoryNode("root", "", []);
|
||||
addToTree(fullTree, abcdeSource, "http://example.com/", "Main Thread");
|
||||
addToTree(fullTree, abcdeSource);
|
||||
addToTree(fullTree, abcSource, "http://example.com/", "Main Thread");
|
||||
const tree = collapseTree(fullTree);
|
||||
|
||||
|
|
|
@ -39,10 +39,10 @@ describe("getDirectories", () => {
|
|||
},
|
||||
];
|
||||
|
||||
const debuggeeUrl = "http://a/";
|
||||
const mainThreadHost = "a";
|
||||
const { sourceTree } = createTree({
|
||||
sources,
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
threads,
|
||||
});
|
||||
|
||||
|
@ -83,10 +83,10 @@ describe("findSourceTreeNodes", () => {
|
|||
},
|
||||
];
|
||||
|
||||
const debuggeeUrl = "http://a/";
|
||||
const mainThreadHost = "a";
|
||||
const { sourceTree } = createTree({
|
||||
sources,
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
threads,
|
||||
});
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/* 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 { getDomain } from "../treeOrder";
|
||||
|
||||
describe("getDomain", () => {
|
||||
it("parses a url and returns the host name", () => {
|
||||
expect(getDomain("http://www.mozilla.com")).toBe("mozilla.com");
|
||||
});
|
||||
|
||||
it("returns null for an undefined string", () => {
|
||||
expect(getDomain(undefined)).toBe(null);
|
||||
});
|
||||
|
||||
it("returns null for an empty string", () => {
|
||||
expect(getDomain("")).toBe(null);
|
||||
});
|
||||
|
||||
it("returns null for a poorly formed string", () => {
|
||||
expect(getDomain("\\/~`?,.{}[]!@$%^&*")).toBe(null);
|
||||
});
|
||||
});
|
|
@ -46,19 +46,19 @@ const threads = [
|
|||
},
|
||||
];
|
||||
|
||||
const debuggeeUrl = "blah";
|
||||
const mainThreadHost = "blah";
|
||||
|
||||
describe("calls updateTree.js", () => {
|
||||
it("adds one source", () => {
|
||||
const prevSources = createSourcesMap([sources[0]]);
|
||||
const { sourceTree, uncollapsedTree } = createTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
sources: prevSources,
|
||||
threads,
|
||||
});
|
||||
|
||||
const newTree = updateTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
prevSources,
|
||||
newSources: createSourcesMap([sources[0], sources[1]]),
|
||||
uncollapsedTree,
|
||||
|
@ -73,13 +73,13 @@ describe("calls updateTree.js", () => {
|
|||
const prevSources = createSourcesMap([sources[0]]);
|
||||
|
||||
const { sourceTree, uncollapsedTree } = createTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
sources: prevSources,
|
||||
threads,
|
||||
});
|
||||
|
||||
const newTree = updateTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
prevSources,
|
||||
newSources: createSourcesMap([sources[0], sources[1], sources[2]]),
|
||||
uncollapsedTree,
|
||||
|
@ -95,13 +95,13 @@ describe("calls updateTree.js", () => {
|
|||
const prevSources = createSourcesMap([sources[0]]);
|
||||
|
||||
const { sourceTree, uncollapsedTree } = createTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
sources: prevSources,
|
||||
threads,
|
||||
});
|
||||
|
||||
const newTree = updateTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
prevSources,
|
||||
newSources: createSourcesMap([
|
||||
{
|
||||
|
@ -124,13 +124,13 @@ describe("calls updateTree.js", () => {
|
|||
const prevSources = createSourcesMap([sources[0]]);
|
||||
|
||||
const { sourceTree, uncollapsedTree } = createTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
sources: prevSources,
|
||||
threads,
|
||||
});
|
||||
|
||||
const newTree = updateTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
prevSources,
|
||||
newSources: createSourcesMap([sources[0], sources[1]]),
|
||||
uncollapsedTree,
|
||||
|
|
|
@ -7,10 +7,8 @@ import { makeMockDisplaySource } from "../../test-mockup";
|
|||
|
||||
import {
|
||||
createDirectoryNode,
|
||||
isExactUrlMatch,
|
||||
isDirectory,
|
||||
addToTree,
|
||||
isNotJavaScript,
|
||||
getPathWithoutThread,
|
||||
createTree,
|
||||
getSourcesInsideGroup,
|
||||
|
@ -19,7 +17,11 @@ import {
|
|||
|
||||
function createSourcesMap(sources) {
|
||||
const sourcesMap = sources.reduce((map, source) => {
|
||||
map[source.id] = makeMockDisplaySource(source.url, source.id);
|
||||
map[source.id] = makeMockDisplaySource(
|
||||
source.url,
|
||||
source.id,
|
||||
source.thread
|
||||
);
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
|
@ -27,27 +29,6 @@ function createSourcesMap(sources) {
|
|||
}
|
||||
|
||||
describe("sources tree", () => {
|
||||
describe("isExactUrlMatch", () => {
|
||||
it("recognizes root url match", () => {
|
||||
const rootA = "http://example.com/path/to/file.html";
|
||||
const rootB = "https://www.demo.com/index.html";
|
||||
|
||||
expect(isExactUrlMatch("example.com", rootA)).toBe(true);
|
||||
expect(isExactUrlMatch("www.example.com", rootA)).toBe(true);
|
||||
expect(isExactUrlMatch("api.example.com", rootA)).toBe(false);
|
||||
expect(isExactUrlMatch("example.example.com", rootA)).toBe(false);
|
||||
expect(isExactUrlMatch("www.example.example.com", rootA)).toBe(false);
|
||||
expect(isExactUrlMatch("demo.com", rootA)).toBe(false);
|
||||
|
||||
expect(isExactUrlMatch("demo.com", rootB)).toBe(true);
|
||||
expect(isExactUrlMatch("www.demo.com", rootB)).toBe(true);
|
||||
expect(isExactUrlMatch("maps.demo.com", rootB)).toBe(false);
|
||||
expect(isExactUrlMatch("demo.demo.com", rootB)).toBe(false);
|
||||
expect(isExactUrlMatch("www.demo.demo.com", rootB)).toBe(false);
|
||||
expect(isExactUrlMatch("example.com", rootB)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isDirectory", () => {
|
||||
it("identifies directories correctly", () => {
|
||||
const sources = [
|
||||
|
@ -56,9 +37,7 @@ describe("sources tree", () => {
|
|||
];
|
||||
|
||||
const tree = createDirectoryNode("root", "", []);
|
||||
sources.forEach(source =>
|
||||
addToTree(tree, source, "http://example.com/", "Main Thread")
|
||||
);
|
||||
sources.forEach(source => addToTree(tree, source));
|
||||
const [bFolderNode, aFileNode] = tree.contents[0].contents[0].contents;
|
||||
const [cFolderNode] = bFolderNode.contents;
|
||||
const [dFileNode] = cFolderNode.contents;
|
||||
|
@ -70,28 +49,6 @@ describe("sources tree", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("isNotJavaScript", () => {
|
||||
it("js file", () => {
|
||||
const source = makeMockDisplaySource("http://example.com/foo.js");
|
||||
expect(isNotJavaScript(source)).toBe(false);
|
||||
});
|
||||
|
||||
it("css file", () => {
|
||||
const source = makeMockDisplaySource("http://example.com/foo.css");
|
||||
expect(isNotJavaScript(source)).toBe(true);
|
||||
});
|
||||
|
||||
it("svg file", () => {
|
||||
const source = makeMockDisplaySource("http://example.com/foo.svg");
|
||||
expect(isNotJavaScript(source)).toBe(true);
|
||||
});
|
||||
|
||||
it("png file", () => {
|
||||
const source = makeMockDisplaySource("http://example.com/foo.png");
|
||||
expect(isNotJavaScript(source)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getPathWithoutThread", () => {
|
||||
it("main thread pattern", () => {
|
||||
const path = getPathWithoutThread("server1.conn0.child1/context18");
|
||||
|
@ -153,10 +110,12 @@ describe("sources tree", () => {
|
|||
{
|
||||
id: "server1.conn13.child1/33",
|
||||
url: "https://example.com/d.js",
|
||||
thread: "OtherThread",
|
||||
},
|
||||
{
|
||||
id: "server1.conn13.child1/31",
|
||||
url: "https://example.com/e.js",
|
||||
thread: "OtherThread",
|
||||
},
|
||||
];
|
||||
const sources = {
|
||||
|
@ -182,7 +141,7 @@ describe("sources tree", () => {
|
|||
|
||||
const tree = createTree({
|
||||
sources,
|
||||
debuggeeUrl: "https://example.com/",
|
||||
mainThreadHost: "example.com",
|
||||
threads,
|
||||
}).sourceTree;
|
||||
|
||||
|
|
|
@ -2,31 +2,15 @@
|
|||
* 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 { parse } from "../url";
|
||||
|
||||
import { nodeHasChildren } from "./utils";
|
||||
|
||||
/*
|
||||
* Gets domain from url (without www prefix)
|
||||
*/
|
||||
export function getDomain(url) {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
const { host } = parse(url);
|
||||
if (!host) {
|
||||
return null;
|
||||
}
|
||||
return host.startsWith("www.") ? host.substr("www.".length) : host;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if node name matches debugger host/domain.
|
||||
*/
|
||||
function isExactDomainMatch(part, debuggeeHost) {
|
||||
function isExactDomainMatch(part, mainThreadHost) {
|
||||
return part.startsWith("www.")
|
||||
? part.substr("www.".length) === debuggeeHost
|
||||
: part === debuggeeHost;
|
||||
? part.substr("www.".length) === mainThreadHost
|
||||
: part === mainThreadHost;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -92,28 +76,28 @@ const matcherFunctions = [isIndexName, isExactDomainMatch];
|
|||
export function createTreeNodeMatcher(
|
||||
part,
|
||||
isDir,
|
||||
debuggeeHost,
|
||||
mainThreadHost,
|
||||
source,
|
||||
sortByUrl
|
||||
) {
|
||||
return node => {
|
||||
for (let i = 0; i < matcherFunctions.length; i++) {
|
||||
// Check part against exceptions
|
||||
if (matcherFunctions[i](part, debuggeeHost)) {
|
||||
if (matcherFunctions[i](part, mainThreadHost)) {
|
||||
for (let j = 0; j < i; j++) {
|
||||
// Check node.name against exceptions
|
||||
if (matcherFunctions[j](node.name, debuggeeHost)) {
|
||||
if (matcherFunctions[j](node.name, mainThreadHost)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// If part and node.name share the same exception, return 0
|
||||
if (matcherFunctions[i](node.name, debuggeeHost)) {
|
||||
if (matcherFunctions[i](node.name, mainThreadHost)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// Check node.name against exceptions if part is not exception
|
||||
if (matcherFunctions[i](node.name, debuggeeHost)) {
|
||||
if (matcherFunctions[i](node.name, mainThreadHost)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,8 @@
|
|||
|
||||
import { addToTree } from "./addToTree";
|
||||
import { collapseTree } from "./collapseTree";
|
||||
import {
|
||||
createDirectoryNode,
|
||||
createParentMap,
|
||||
getPathParts,
|
||||
isInvalidUrl,
|
||||
} from "./utils";
|
||||
import {
|
||||
getDomain,
|
||||
createTreeNodeMatcher,
|
||||
findNodeInContents,
|
||||
} from "./treeOrder";
|
||||
|
||||
import { getDisplayURL } from "./getURL";
|
||||
import { createDirectoryNode, createParentMap } from "./utils";
|
||||
import { createTreeNodeMatcher, findNodeInContents } from "./treeOrder";
|
||||
|
||||
function getSourcesDiff(newSources, prevSources) {
|
||||
const toAdd = [];
|
||||
|
@ -35,10 +24,10 @@ function getSourcesDiff(newSources, prevSources) {
|
|||
return { toAdd, toUpdate };
|
||||
}
|
||||
|
||||
export function createTree({ debuggeeUrl, sources, threads }) {
|
||||
export function createTree({ mainThreadHost, sources, threads }) {
|
||||
const uncollapsedTree = createDirectoryNode("root", "", []);
|
||||
const result = updateTree({
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
newSources: sources,
|
||||
prevSources: {},
|
||||
threads,
|
||||
|
@ -55,13 +44,12 @@ export function createTree({ debuggeeUrl, sources, threads }) {
|
|||
export function updateTree({
|
||||
newSources,
|
||||
prevSources,
|
||||
debuggeeUrl,
|
||||
mainThreadHost,
|
||||
uncollapsedTree,
|
||||
threads,
|
||||
create,
|
||||
sourceTree,
|
||||
}) {
|
||||
const debuggeeHost = getDomain(debuggeeUrl);
|
||||
const contexts = Object.keys(newSources);
|
||||
|
||||
let shouldUpdate = !sourceTree;
|
||||
|
@ -78,7 +66,7 @@ export function updateTree({
|
|||
|
||||
for (const source of toAdd) {
|
||||
shouldUpdate = true;
|
||||
addToTree(uncollapsedTree, source, debuggeeHost, thread.actor);
|
||||
addToTree(uncollapsedTree, source);
|
||||
}
|
||||
|
||||
for (const [prevSource, newSource] of toUpdate) {
|
||||
|
@ -87,7 +75,7 @@ export function updateTree({
|
|||
uncollapsedTree,
|
||||
prevSource,
|
||||
newSource,
|
||||
debuggeeHost,
|
||||
mainThreadHost,
|
||||
thread.actor
|
||||
);
|
||||
}
|
||||
|
@ -118,45 +106,34 @@ export function updateInTree(
|
|||
tree,
|
||||
prevSource,
|
||||
newSource,
|
||||
debuggeeHost,
|
||||
mainThreadHost,
|
||||
thread
|
||||
) {
|
||||
const newUrl = getDisplayURL(newSource, debuggeeHost);
|
||||
const prevUrl = getDisplayURL(prevSource, debuggeeHost);
|
||||
|
||||
const prevEntries = findEntries(
|
||||
tree,
|
||||
prevUrl,
|
||||
prevSource,
|
||||
thread,
|
||||
debuggeeHost
|
||||
);
|
||||
const prevEntries = findEntries(tree, prevSource, mainThreadHost);
|
||||
if (!prevEntries) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isInvalidUrl(newUrl, newSource)) {
|
||||
const parts = getPathParts(newUrl, thread, debuggeeHost);
|
||||
const { parts } = newSource;
|
||||
|
||||
if (parts.length === prevEntries.length) {
|
||||
let match = true;
|
||||
for (let i = 0; i < parts.length - 2; i++) {
|
||||
if (parts[i].path !== prevEntries[i + 1].node.path) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
if (parts.length === prevEntries.length) {
|
||||
let match = true;
|
||||
for (let i = 0; i < parts.length - 2; i++) {
|
||||
if (parts[i].path !== prevEntries[i + 1].node.path) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
const { node, index } = prevEntries.pop();
|
||||
// This is guaranteed to be a TreeSource or else findEntries would
|
||||
// not have returned anything.
|
||||
const fileNode = node.contents[index];
|
||||
fileNode.name = parts[parts.length - 1].part;
|
||||
fileNode.path = parts[parts.length - 1].path;
|
||||
fileNode.contents = newSource;
|
||||
return;
|
||||
}
|
||||
if (match) {
|
||||
const { node, index } = prevEntries.pop();
|
||||
// This is guaranteed to be a TreeSource or else findEntries would
|
||||
// not have returned anything.
|
||||
const fileNode = node.contents[index];
|
||||
fileNode.name = parts[parts.length - 1].part;
|
||||
fileNode.path = parts[parts.length - 1].path;
|
||||
fileNode.contents = newSource;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,11 +149,12 @@ export function updateInTree(
|
|||
break;
|
||||
}
|
||||
}
|
||||
addToTree(tree, newSource, debuggeeHost, thread);
|
||||
addToTree(tree, newSource);
|
||||
}
|
||||
|
||||
function findEntries(tree, url, source, thread, debuggeeHost) {
|
||||
const parts = getPathParts(url, thread, debuggeeHost);
|
||||
function findEntries(tree, source, mainThreadHost) {
|
||||
// Copy the array to avoid mutating it on the next instruction.
|
||||
const parts = Array.from(source.parts);
|
||||
|
||||
// We're searching for the directory containing the file so we pop off the
|
||||
// potential filename. This is because the tree has some logic to inject
|
||||
|
@ -190,7 +168,7 @@ function findEntries(tree, url, source, thread, debuggeeHost) {
|
|||
for (const { part } of parts) {
|
||||
const { found: childFound, index: childIndex } = findNodeInContents(
|
||||
currentNode,
|
||||
createTreeNodeMatcher(part, true, debuggeeHost)
|
||||
createTreeNodeMatcher(part, true, mainThreadHost)
|
||||
);
|
||||
|
||||
if (!childFound || currentNode.type !== "directory") {
|
||||
|
|
|
@ -2,13 +2,10 @@
|
|||
* 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 { getURL } from "./getURL";
|
||||
import { parse } from "../../utils/url";
|
||||
|
||||
import { isPretty } from "../source";
|
||||
import { getURL } from "./getURL";
|
||||
const IGNORED_URLS = ["debugger eval code", "XStringBundle"];
|
||||
|
||||
export function getPathParts(url, thread, debuggeeHost) {
|
||||
export function getPathParts(url, thread, mainThreadHost) {
|
||||
const parts = url.path.split("/");
|
||||
if (parts.length > 1 && parts[parts.length - 1] === "") {
|
||||
parts.pop();
|
||||
|
@ -32,12 +29,12 @@ export function getPathParts(url, thread, debuggeeHost) {
|
|||
path = `${path}/${part}`;
|
||||
}
|
||||
|
||||
const debuggeeHostIfRoot = index === 1 ? debuggeeHost : null;
|
||||
const mainThreadHostIfRoot = index === 1 ? mainThreadHost : null;
|
||||
|
||||
return {
|
||||
part,
|
||||
path,
|
||||
debuggeeHostIfRoot,
|
||||
mainThreadHostIfRoot,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -46,18 +43,6 @@ export function nodeHasChildren(item) {
|
|||
return item.type == "directory" && Array.isArray(item.contents);
|
||||
}
|
||||
|
||||
export function isExactUrlMatch(pathPart, debuggeeUrl) {
|
||||
// compare to hostname with an optional 'www.' prefix
|
||||
const { host } = parse(debuggeeUrl);
|
||||
if (!host) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
host === pathPart ||
|
||||
host.replace(/^www\./, "") === pathPart.replace(/^www\./, "")
|
||||
);
|
||||
}
|
||||
|
||||
export function isPathDirectory(path) {
|
||||
// Assume that all urls point to files except when they end with '/'
|
||||
// Or directory node has children
|
||||
|
@ -118,20 +103,6 @@ export function getFileExtension(source) {
|
|||
return lastIndex !== -1 ? path.slice(lastIndex + 1) : "";
|
||||
}
|
||||
|
||||
export function isNotJavaScript(source) {
|
||||
return ["css", "svg", "png"].includes(getFileExtension(source));
|
||||
}
|
||||
|
||||
export function isInvalidUrl(url, source) {
|
||||
return (
|
||||
!source.url ||
|
||||
!url.group ||
|
||||
isNotJavaScript(source) ||
|
||||
IGNORED_URLS.includes(url) ||
|
||||
isPretty(source)
|
||||
);
|
||||
}
|
||||
|
||||
export function partIsFile(index, parts, url) {
|
||||
const isLastPart = index === parts.length - 1;
|
||||
return isLastPart && !isDirectory(url);
|
||||
|
|
|
@ -13,6 +13,9 @@ import * as asyncValue from "./async-value";
|
|||
|
||||
import { initialState } from "../reducers/index";
|
||||
|
||||
import { getPathParts } from "./sources-tree/utils";
|
||||
import { getDisplayURL } from "./sources-tree/getURL";
|
||||
|
||||
function makeMockSource(url = "url", id = "source", thread = "FakeThread") {
|
||||
return {
|
||||
id,
|
||||
|
@ -28,10 +31,16 @@ function makeMockSource(url = "url", id = "source", thread = "FakeThread") {
|
|||
};
|
||||
}
|
||||
|
||||
function makeMockDisplaySource(url = "url", id = "source") {
|
||||
function makeMockDisplaySource(
|
||||
url = "url",
|
||||
id = "source",
|
||||
thread = "FakeThread"
|
||||
) {
|
||||
const displayURL = getDisplayURL(url);
|
||||
return {
|
||||
...makeMockSource(url, id),
|
||||
displayURL: url,
|
||||
...makeMockSource(url, id, thread),
|
||||
displayURL,
|
||||
parts: getPathParts(displayURL, thread, "http://www.example.com"),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -223,6 +232,21 @@ function makeMockState(state) {
|
|||
};
|
||||
}
|
||||
|
||||
function formatTree(tree, depth = 0, str = "") {
|
||||
const whitespace = new Array(depth * 2).join(" ");
|
||||
|
||||
if (tree.type === "directory") {
|
||||
str += `${whitespace} - ${tree.name} path=${tree.path} \n`;
|
||||
tree.contents.forEach(t => {
|
||||
str = formatTree(t, depth + 1, str);
|
||||
});
|
||||
} else {
|
||||
str += `${whitespace} - ${tree.name} path=${tree.path} source_id=${tree.contents.id} \n`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export {
|
||||
makeMockDisplaySource,
|
||||
makeMockSource,
|
||||
|
@ -243,4 +267,5 @@ export {
|
|||
makeMockState,
|
||||
makeMockThread,
|
||||
makeFullfilledMockSourceContent,
|
||||
formatTree,
|
||||
};
|
||||
|
|
|
@ -25,21 +25,17 @@ const NODE_SELECTORS = {
|
|||
};
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-blackbox-all.html");
|
||||
|
||||
info("Loads the source file and sets a breakpoint at line 2.");
|
||||
await waitForSources(
|
||||
dbg,
|
||||
const dbg = await initDebugger(
|
||||
"doc-blackbox-all.html",
|
||||
SOURCE_FILES.nestedSource,
|
||||
SOURCE_FILES.codeReload1
|
||||
);
|
||||
|
||||
info("Loads the source file and sets a breakpoint at line 2.");
|
||||
await selectSource(dbg, SOURCE_FILES.nestedSource);
|
||||
await addBreakpoint(dbg, SOURCE_FILES.nestedSource, 2);
|
||||
|
||||
info("Expands the whole source tree.");
|
||||
rightClickElement(dbg, "sourceTreeRootNode");
|
||||
await waitForContextMenu(dbg);
|
||||
selectContextMenuItem(dbg, "#node-menu-expand-all");
|
||||
info("Selecting the source will highlight it and expand the tree down to it");
|
||||
await waitForAllElements(dbg, "sourceTreeFolderNode", 3);
|
||||
const sourceTreeFolderNodeEls = findAllElements(dbg, "sourceTreeFolderNode");
|
||||
const sourceTreeRootNodeEl = findElement(dbg, "sourceTreeRootNode");
|
||||
|
|
|
@ -8,21 +8,17 @@
|
|||
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
const dbg = await initDebugger("doc-sourcemaps3.html");
|
||||
const dbg = await initDebugger(
|
||||
"doc-sourcemaps3.html",
|
||||
"bundle.js",
|
||||
"sorted.js",
|
||||
"test.js"
|
||||
);
|
||||
dbg.actions.toggleMapScopes();
|
||||
|
||||
await waitForSources(dbg, "bundle.js", "sorted.js", "test.js");
|
||||
|
||||
const sortedSrc = findSource(dbg, "sorted.js");
|
||||
|
||||
await selectSource(dbg, sortedSrc);
|
||||
|
||||
// Show the source in source tree in primiany panel for blackBox icon check
|
||||
rightClickElement(dbg, "CodeMirrorLines");
|
||||
await waitForContextMenu(dbg);
|
||||
selectContextMenuItem(dbg, "#node-menu-show-source");
|
||||
await waitForDispatch(dbg.store, "SHOW_SOURCE");
|
||||
|
||||
await clickElement(dbg, "blackbox");
|
||||
await waitForDispatch(dbg.store, "BLACKBOX");
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ add_task(async function testBreakableLinesOverReloads() {
|
|||
);
|
||||
|
||||
info("Assert breakable lines of the first html page load");
|
||||
await assertBreakableLines(dbg, "index.html", 62, [
|
||||
await assertBreakableLines(dbg, "index.html", 65, [
|
||||
[16, 17],
|
||||
[21],
|
||||
[23],
|
||||
|
|
|
@ -30,7 +30,7 @@ add_task(async function testBreakableLinesOverReloads() {
|
|||
);
|
||||
|
||||
info("Assert breakable lines of the first html page load");
|
||||
await assertBreakablePositions(dbg, "index.html", 62, [
|
||||
await assertBreakablePositions(dbg, "index.html", 65, [
|
||||
{ line: 16, columns: [6, 14] },
|
||||
{ line: 17, columns: [] },
|
||||
{ line: 21, columns: [6, 14] },
|
||||
|
|
|
@ -46,6 +46,9 @@
|
|||
<script src="query.js?x=1"></script>
|
||||
<script src="query.js?x=2"></script>
|
||||
|
||||
<!-- A javascript: URL, which should not be shown in the SourceTree -->
|
||||
<script src="javascript:console.log('foo')"></script>
|
||||
|
||||
<!-- A bundle/generated source that contains original.js -->
|
||||
<script src="bundle.js"></script>
|
||||
|
||||
|
|
|
@ -46,6 +46,9 @@
|
|||
<script src="query.js?x=1"></script>
|
||||
<script src="query.js?x=2"></script>
|
||||
|
||||
<!-- A javascript: URL, which should not be shown in the SourceTree -->
|
||||
<script src="javascript:console.log('foo')"></script>
|
||||
|
||||
<!-- A bundle/generated source that contains original.js -->
|
||||
<script src="bundle.js"></script>
|
||||
|
||||
|
|
|
@ -45,11 +45,13 @@ support-files =
|
|||
doc_inactive_css_xul.xhtml
|
||||
head.js
|
||||
sjs_imported_stylesheet_edit.sjs
|
||||
square_svg.sjs
|
||||
!/devtools/client/inspector/test/head.js
|
||||
!/devtools/client/inspector/test/shared-head.js
|
||||
!/devtools/client/shared/test/shared-head.js
|
||||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
!/devtools/client/shared/test/highlighter-test-actor.js
|
||||
!/devtools/client/webconsole/test/browser/shared-head.js
|
||||
|
||||
[browser_rules_css-compatibility-add-rename-rule.js]
|
||||
skip-if = bits == 64 && (os == "linux" || os == "win") #bug 1657807
|
||||
|
@ -198,6 +200,7 @@ fail-if = a11y_checks # bug 1687723 ruleview-shapeswatch is not accessible
|
|||
[browser_rules_strict-search-filter_02.js]
|
||||
[browser_rules_strict-search-filter_03.js]
|
||||
[browser_rules_style-editor-link.js]
|
||||
[browser_rules_update_mask_image_cors.js]
|
||||
[browser_rules_url-click-opens-new-tab.js]
|
||||
[browser_rules_urls-clickable.js]
|
||||
[browser_rules_user-agent-styles.js]
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from ../../../webconsole/test/browser/shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/webconsole/test/browser/shared-head.js",
|
||||
this
|
||||
);
|
||||
|
||||
// The mask image is served from example.com while the test page is served from
|
||||
// example.org.
|
||||
const MASK_SRC = URL_ROOT_COM_SSL + "square_svg.sjs";
|
||||
const STYLE_ATTRIBUTE = `mask-image: url("${MASK_SRC}"); width:10px; height: 10px; background: red;`;
|
||||
const TEST_URL = `https://example.org/document-builder.sjs?html=<div style='${STYLE_ATTRIBUTE}'>`;
|
||||
|
||||
// Used to assert screenshot colors.
|
||||
const RED = { r: 255, g: 0, b: 0 };
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(TEST_URL);
|
||||
const { inspector, toolbox, view } = await openRuleView();
|
||||
|
||||
info("Open the splitconsole to check for CORS messages");
|
||||
await toolbox.toggleSplitConsole();
|
||||
|
||||
await selectNode("div", inspector);
|
||||
|
||||
info("Take a node screenshot, mask is applied, should be red");
|
||||
const beforeScreenshot = await takeNodeScreenshot(inspector);
|
||||
await assertSingleColorScreenshotImage(beforeScreenshot, 10, 10, RED);
|
||||
|
||||
info("Update a property from the rule view");
|
||||
const heightProperty = getTextProperty(view, 0, { height: "10px" });
|
||||
await setProperty(view, heightProperty, "11px");
|
||||
|
||||
info("Wait until the style has been applied in the content page");
|
||||
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => {
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => content.document.querySelector("div").style.height == "11px"
|
||||
);
|
||||
});
|
||||
|
||||
// Wait for some time in case the image needs to be reloaded, and to allow
|
||||
// error messages (if any) to be rendered.
|
||||
await wait(1000);
|
||||
|
||||
info("Take another screenshot, mask should still apply, should be red");
|
||||
const afterScreenshot = await takeNodeScreenshot(inspector);
|
||||
await assertSingleColorScreenshotImage(afterScreenshot, 10, 11, RED);
|
||||
|
||||
const hud = toolbox.getPanel("webconsole").hud;
|
||||
ok(
|
||||
!findMessageByType(hud, "Cross-Origin Request Blocked", ".error"),
|
||||
"No message was logged about a CORS issue"
|
||||
);
|
||||
|
||||
info("Close split console");
|
||||
await toolbox.toggleSplitConsole();
|
||||
});
|
13
devtools/client/inspector/rules/test/square_svg.sjs
Normal file
13
devtools/client/inspector/rules/test/square_svg.sjs
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
response.setHeader("Access-Control-Allow-Headers", "content-type", false);
|
||||
response.setHeader("Content-Type", "image/svg+xml", false);
|
||||
response.write(
|
||||
`<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="16" /></svg>`
|
||||
);
|
||||
}
|
|
@ -62,6 +62,7 @@ const XUL_HIGHLIGHTER_STYLES_SHEET = `data:text/css;charset=utf-8,
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
color-scheme: light;
|
||||
}`;
|
||||
|
||||
const STYLESHEET_URI =
|
||||
|
@ -295,6 +296,11 @@ CanvasFrameAnonymousContentHelper.prototype = {
|
|||
|
||||
if (!this._iframe) {
|
||||
this._iframe = window.document.createElement("iframe");
|
||||
// We need the color-scheme shenanigans to ensure that the iframe is
|
||||
// transparent, see bug 1773155, bug 1738380, and
|
||||
// https://github.com/mozilla/wg-decisions/issues/774.
|
||||
this._iframe.srcdoc =
|
||||
"<!doctype html><meta name=color-scheme content=light>";
|
||||
this._iframe.classList.add("devtools-highlighter-renderer");
|
||||
// If iframe is used for the first time, add ref count of one to its
|
||||
// numberOfHighlighters data attribute.
|
||||
|
|
|
@ -5,18 +5,21 @@
|
|||
"use strict";
|
||||
|
||||
const ResourceCommand = require("devtools/shared/commands/resource/resource-command");
|
||||
|
||||
const stacktraces = new Set();
|
||||
module.exports = async function({ targetCommand, targetFront, onAvailable }) {
|
||||
function onNetworkEventStackTrace(packet) {
|
||||
const actor = packet.eventActor;
|
||||
onAvailable([
|
||||
{
|
||||
resourceType: ResourceCommand.TYPES.NETWORK_EVENT_STACKTRACE,
|
||||
resourceId: actor.channelId,
|
||||
stacktraceAvailable: actor.cause.stacktraceAvailable,
|
||||
lastFrame: actor.cause.lastFrame,
|
||||
},
|
||||
]);
|
||||
if (!stacktraces.has(actor.channelId)) {
|
||||
stacktraces.add(actor.channelId);
|
||||
onAvailable([
|
||||
{
|
||||
resourceType: ResourceCommand.TYPES.NETWORK_EVENT_STACKTRACE,
|
||||
resourceId: actor.channelId,
|
||||
stacktraceAvailable: actor.cause.stacktraceAvailable,
|
||||
lastFrame: actor.cause.lastFrame,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
const webConsoleFront = await targetFront.getFront("console");
|
||||
webConsoleFront.on("serverNetworkStackTrace", onNetworkEventStackTrace);
|
||||
|
|
|
@ -377,7 +377,12 @@ async function testNestedResourceUpdateFeature() {
|
|||
|
||||
info("Apply new media query");
|
||||
// In order to avoid applying the media query (min-height: 400px).
|
||||
tab.ownerGlobal.resizeTo(originalWindowWidth, 300);
|
||||
if (originalWindowHeight !== 300) {
|
||||
await new Promise(resolve => {
|
||||
tab.ownerGlobal.addEventListener("resize", resolve, { once: true });
|
||||
tab.ownerGlobal.resizeTo(originalWindowWidth, 300);
|
||||
});
|
||||
}
|
||||
|
||||
// Retrieve the stylesheet of the top-level target
|
||||
const resource = availableResources.find(
|
||||
|
|
|
@ -3557,6 +3557,32 @@ exports.CSS_PROPERTIES = {
|
|||
"unset"
|
||||
]
|
||||
},
|
||||
"backdrop-filter": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
"backdrop-filter"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"blur",
|
||||
"brightness",
|
||||
"contrast",
|
||||
"drop-shadow",
|
||||
"grayscale",
|
||||
"hue-rotate",
|
||||
"inherit",
|
||||
"initial",
|
||||
"invert",
|
||||
"none",
|
||||
"opacity",
|
||||
"revert",
|
||||
"revert-layer",
|
||||
"saturate",
|
||||
"sepia",
|
||||
"unset",
|
||||
"url"
|
||||
]
|
||||
},
|
||||
"backface-visibility": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
|
|
|
@ -13,6 +13,7 @@ You should consider requesting accessibility review if you aren't certain
|
|||
whether your change is accessible to people with disabilities. Accessibility
|
||||
review is optional, but it is strongly encouraged if you are introducing new
|
||||
user interface or are significantly redesigning existing user interface.
|
||||
Review should be requested both on the design side _and_ on the engineering side.
|
||||
|
||||
## When Should I Request Accessibility Review?
|
||||
Generally, it's best to request accessibility review as early as possible, even
|
||||
|
@ -27,12 +28,33 @@ what is needed to make user interfaces accessible. To make accessibility review
|
|||
faster, you may wish to try to verify and implement these guidelines prior to
|
||||
requesting accessibility review.
|
||||
|
||||
The deadline for accessibility review requests is Friday of the first week of
|
||||
nightly builds for the release in which the feature/change is expected to ship.
|
||||
For design reviews, please allow at least a week between review request and expected-engineering-handoff. The deadline for engineering review requests is Friday of the first week of nightly builds for the release in which the feature/change is expected to ship.
|
||||
This is the same date as the PI Request deadline.
|
||||
|
||||
## How Do I Request Accessibility Review?
|
||||
You request accessibility review by setting the a11y-review flag to "requested"
|
||||
## Requesting Design Review
|
||||
Design review should be requested via the #accessibility slack channel. Please post the following information to help us triage your review:
|
||||
|
||||
```
|
||||
Timeline? (ie. when is engineering handoff? product approval? etc.)
|
||||
Tracking/bug issue:
|
||||
Product spec:
|
||||
Figma file:
|
||||
Engineering lead:
|
||||
Product manager:
|
||||
Have you completed self-review (contrast audit, focus order/role annotations, HCM mockups)?
|
||||
```
|
||||
|
||||
In addition to posting this information, please complete the following self-review tasks **before requesting review**. Note: Some of the following links require SSO authentication.
|
||||
|
||||
- **Perform a contrast audit**: Using a [figma plugin that audits contrast](https://www.figma.com/community/plugin/748533339900865323/Contrast), check your designs for color contrast sufficiency. Your designs should be at least "AA" rated in order to pass accessibility review. "AAA" is even better! If there are particular components that are difficult to adjust to meet "AA" standards, make a note in the figma file and the a11y team will provide specific guidance during review.
|
||||
- **Add focus order and role annotations**: Focus order annotations describe the behaviour a keyboard user should expect when navigating your design. Generally this follows the reading order. Note that we only care about focusable elements here (ie. links, buttons, inputs, etc.).
|
||||
Role annotations help screen readers and other assistive technologies identify the "kind" of component they're navigating through. These mappings expose semantic information to the user. You can find a [list of common roles here](https://www.codeinwp.com/blog/wai-aria-roles/). You may want to use a [figma plugin that annotates focus and roles](https://www.figma.com/community/plugin/731310036968334777/A11y---Focus-Order) for this process. You do not need to annotate every view in your design, pick those with the largest amount of new content.
|
||||
- **Create Windows High-Contrast Mode (HCM) mockups**: Our designs should be accessible to users [running HCM](https://docs.google.com/document/d/1El3XJiAdA5gFcG7H9iI1dNmLbht0hXfi_oKBZPWx3t0/edit). You can read more about [how HCM affects color selection](https://firefox-source-docs.mozilla.org/accessible/ColorsAndHighContrastMode.html), and [how to design for HCM](https://wiki.mozilla.org/Accessibility/Design_Guide). Using the ["Night Sky" HCM palette](https://www.figma.com/file/XQrEePCCJebjlVBQwNggQ6/Pro-Client-Accessibility-Reviews?node-id=25%3A3848), translate your designs into High Contrast. Remember, it's important we use these colors **semantically**, not based on a desire for a particular aesthetic. Colors are labelled according to their uses -- `Background` for page background, `Button Text` for button or control text, `Selected Item Background` for backgrounds of selected or active items, etc.. You do not need to mock up every view in your design, pick those with the largest amount of new content. You can find [examples of previous HCM mock ups here](https://www.figma.com/file/XQrEePCCJebjlVBQwNggQ6/Accessibility).
|
||||
Where possible, we should rely on SVG's and PNG's for image content to increase adaptability.
|
||||
|
||||
|
||||
## Requesting Engineering Review
|
||||
For an engineering-focused review, you submit a review request by setting the a11y-review flag to "requested"
|
||||
on a bug in Bugzilla and filling in the template that appears in the comment
|
||||
field. For features spanning several bugs, you may wish to file a new, dedicated
|
||||
bug for the accessibility review. Otherwise, particularly for smaller changes,
|
||||
|
@ -45,5 +67,6 @@ team:
|
|||
|
||||
* \#accessibility on
|
||||
[Matrix](https://matrix.to/#/!jmuErVonajdNMbgdeY:mozilla.org?via=mozilla.org&via=matrix.org)
|
||||
or Slack
|
||||
or [Slack](https://mozilla.slack.com/archives/C4E0W8B8E)
|
||||
* Email: accessibility@mozilla.com
|
||||
* Please avoid reaching out to individual team members directly -- containing review requests and questions in these channels helps us balance our workload. Thank you!
|
||||
|
|
|
@ -2471,7 +2471,7 @@ void BrowsingContext::PostMessageMoz(JSContext* aCx,
|
|||
if (message.CloneScope() ==
|
||||
StructuredCloneHolder::StructuredCloneScope::DifferentProcess) {
|
||||
ClonedMessageData clonedMessageData;
|
||||
if (!message.BuildClonedMessageDataForChild(cc, clonedMessageData)) {
|
||||
if (!message.BuildClonedMessageData(clonedMessageData)) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
@ -2495,7 +2495,7 @@ void BrowsingContext::PostMessageMoz(JSContext* aCx,
|
|||
if (message.CloneScope() ==
|
||||
StructuredCloneHolder::StructuredCloneScope::DifferentProcess) {
|
||||
ClonedMessageData clonedMessageData;
|
||||
if (!message.BuildClonedMessageDataForParent(cp, clonedMessageData)) {
|
||||
if (!message.BuildClonedMessageData(clonedMessageData)) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -2743,29 +2743,9 @@ nsresult nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) {
|
|||
mContentListener->SetParentContentListener(parentURIListener);
|
||||
}
|
||||
|
||||
// Inform windows when they're being removed from their parent.
|
||||
if (!aParent) {
|
||||
MaybeClearStorageAccessFlag();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsDocShell::MaybeClearStorageAccessFlag() {
|
||||
if (mScriptGlobal) {
|
||||
// Tell our window that the parent has now changed.
|
||||
mScriptGlobal->ParentWindowChanged();
|
||||
|
||||
// Tell all of our children about the change recursively as well.
|
||||
for (auto* childDocLoader : mChildList.ForwardRange()) {
|
||||
nsCOMPtr<nsIDocShell> child = do_QueryObject(childDocLoader);
|
||||
if (child) {
|
||||
static_cast<nsDocShell*>(child.get())->MaybeClearStorageAccessFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsDocShell::MaybeRestoreWindowName() {
|
||||
if (!StaticPrefs::privacy_window_name_update_enabled()) {
|
||||
return;
|
||||
|
|
|
@ -401,9 +401,6 @@ class nsDocShell final : public nsDocLoader,
|
|||
nsDocShellLoadState* aLoadState,
|
||||
mozilla::Maybe<uint32_t> aCacheKey = mozilla::Nothing());
|
||||
|
||||
// Clear the document's storage access flag if needed.
|
||||
void MaybeClearStorageAccessFlag();
|
||||
|
||||
void MaybeRestoreWindowName();
|
||||
|
||||
void StoreWindowNameToSHEntries();
|
||||
|
|
|
@ -1501,25 +1501,12 @@ void IPDLParamTraits<dom::SessionHistoryInfo>::Write(
|
|||
Maybe<Tuple<uint32_t, dom::ClonedMessageData>> stateData;
|
||||
if (aParam.mStateData) {
|
||||
stateData.emplace();
|
||||
uint32_t version;
|
||||
NS_ENSURE_SUCCESS_VOID(aParam.mStateData->GetFormatVersion(&version));
|
||||
Get<0>(*stateData) = version;
|
||||
|
||||
IToplevelProtocol* topLevel = aActor->ToplevelProtocol();
|
||||
MOZ_RELEASE_ASSERT(topLevel->GetProtocolId() == PContentMsgStart);
|
||||
if (topLevel->GetSide() == ChildSide) {
|
||||
auto* contentChild = static_cast<dom::ContentChild*>(topLevel);
|
||||
if (NS_WARN_IF(!aParam.mStateData->BuildClonedMessageDataForChild(
|
||||
contentChild, Get<1>(*stateData)))) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
auto* contentParent = static_cast<dom::ContentParent*>(topLevel);
|
||||
if (NS_WARN_IF(!aParam.mStateData->BuildClonedMessageDataForParent(
|
||||
contentParent, Get<1>(*stateData)))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// FIXME: We should fail more aggressively if this fails, as currently we'll
|
||||
// just early return and the deserialization will break.
|
||||
NS_ENSURE_SUCCESS_VOID(
|
||||
aParam.mStateData->GetFormatVersion(&Get<0>(*stateData)));
|
||||
NS_ENSURE_TRUE_VOID(
|
||||
aParam.mStateData->BuildClonedMessageData(Get<1>(*stateData)));
|
||||
}
|
||||
|
||||
WriteIPDLParam(aWriter, aActor, aParam.mURI);
|
||||
|
@ -1669,13 +1656,7 @@ bool IPDLParamTraits<dom::SessionHistoryInfo>::Read(
|
|||
if (stateData.isSome()) {
|
||||
uint32_t version = Get<0>(*stateData);
|
||||
aResult->mStateData = new nsStructuredCloneContainer(version);
|
||||
if (aActor->GetSide() == ChildSide) {
|
||||
aResult->mStateData->StealFromClonedMessageDataForChild(
|
||||
Get<1>(*stateData));
|
||||
} else {
|
||||
aResult->mStateData->StealFromClonedMessageDataForParent(
|
||||
Get<1>(*stateData));
|
||||
}
|
||||
aResult->mStateData->StealFromClonedMessageData(Get<1>(*stateData));
|
||||
}
|
||||
MOZ_ASSERT_IF(stateData.isNothing(), !aResult->mStateData);
|
||||
return true;
|
||||
|
|
|
@ -16,60 +16,53 @@
|
|||
|
||||
namespace mozilla::dom {
|
||||
|
||||
ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning)
|
||||
: mParent(aParent),
|
||||
mChild(nullptr),
|
||||
mDefaultChild(nullptr),
|
||||
mIsFirst(aStartAtBeginning),
|
||||
mIndexInInserted(0) {
|
||||
mParentAsSlot = HTMLSlotElement::FromNode(mParent);
|
||||
FlattenedChildIterator::FlattenedChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning)
|
||||
: mParent(aParent), mOriginalParent(aParent), mIsFirst(aStartAtBeginning) {
|
||||
if (!mParent->IsElement()) {
|
||||
// TODO(emilio): I think it probably makes sense to only allow constructing
|
||||
// FlattenedChildIterators with Element.
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShadowRoot* shadow = mParent->AsElement()->GetShadowRoot()) {
|
||||
mParent = shadow;
|
||||
mShadowDOMInvolved = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto* slot = HTMLSlotElement::FromNode(mParent)) {
|
||||
if (!slot->AssignedNodes().IsEmpty()) {
|
||||
mParentAsSlot = slot;
|
||||
if (!aStartAtBeginning) {
|
||||
mIndexInInserted = slot->AssignedNodes().Length();
|
||||
}
|
||||
mShadowDOMInvolved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsIContent* ExplicitChildIterator::GetNextChild() {
|
||||
nsIContent* FlattenedChildIterator::GetNextChild() {
|
||||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
MOZ_ASSERT(mChild);
|
||||
MOZ_ASSERT(!mDefaultChild);
|
||||
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (mIndexInInserted < assignedNodes.Length())
|
||||
? assignedNodes[mIndexInInserted++]->AsContent()
|
||||
: nullptr;
|
||||
if (!mChild) {
|
||||
mIndexInInserted = 0;
|
||||
}
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (mIsFirst) {
|
||||
mIsFirst = false;
|
||||
MOZ_ASSERT(mIndexInInserted == 0);
|
||||
mChild = assignedNodes[0]->AsContent();
|
||||
return mChild;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("This needs to be revisited");
|
||||
} else if (mDefaultChild) {
|
||||
// If we're already in default content, check if there are more nodes there
|
||||
MOZ_ASSERT(mChild);
|
||||
|
||||
mDefaultChild = mDefaultChild->GetNextSibling();
|
||||
if (mDefaultChild) {
|
||||
return mDefaultChild;
|
||||
}
|
||||
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mIsFirst) { // at the beginning of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = 1;
|
||||
mChild = assignedNodes[0]->AsContent();
|
||||
mIsFirst = false;
|
||||
return mChild;
|
||||
}
|
||||
MOZ_ASSERT(mIndexInInserted <= assignedNodes.Length());
|
||||
if (mIndexInInserted + 1 >= assignedNodes.Length()) {
|
||||
mIndexInInserted = assignedNodes.Length();
|
||||
return nullptr;
|
||||
}
|
||||
mChild = assignedNodes[++mIndexInInserted]->AsContent();
|
||||
return mChild;
|
||||
}
|
||||
|
||||
if (mIsFirst) { // at the beginning of the child list
|
||||
mChild = mParent->GetFirstChild();
|
||||
mIsFirst = false;
|
||||
} else if (mChild) { // in the middle of the child list
|
||||
|
@ -79,103 +72,54 @@ nsIContent* ExplicitChildIterator::GetNextChild() {
|
|||
return mChild;
|
||||
}
|
||||
|
||||
void FlattenedChildIterator::Init() {
|
||||
if (!mParent->IsElement()) {
|
||||
// TODO(emilio): I think it probably makes sense to only allow constructing
|
||||
// FlattenedChildIterators with Element.
|
||||
return;
|
||||
}
|
||||
if (ShadowRoot* shadow = mParent->AsElement()->GetShadowRoot()) {
|
||||
mParent = shadow;
|
||||
mShadowDOMInvolved = true;
|
||||
return;
|
||||
}
|
||||
if (mParentAsSlot) {
|
||||
mShadowDOMInvolved = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExplicitChildIterator::Seek(const nsIContent* aChildToFind) {
|
||||
if (aChildToFind->GetParent() == mParent &&
|
||||
bool FlattenedChildIterator::Seek(const nsIContent* aChildToFind) {
|
||||
if (!mParentAsSlot && aChildToFind->GetParent() == mParent &&
|
||||
!aChildToFind->IsRootOfNativeAnonymousSubtree()) {
|
||||
// Fast path: just point ourselves to aChildToFind, which is a
|
||||
// normal DOM child of ours.
|
||||
mChild = const_cast<nsIContent*>(aChildToFind);
|
||||
mIndexInInserted = 0;
|
||||
mDefaultChild = nullptr;
|
||||
mIsFirst = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Can we add more fast paths here based on whether the parent of aChildToFind
|
||||
// is a shadow insertion point or content insertion point?
|
||||
// is a This version can take shortcuts that the two-argument version
|
||||
// can't, so can be faster (and in fact cshadow insertion point or content
|
||||
// insertion point?
|
||||
|
||||
// Slow path: just walk all our kids.
|
||||
return Seek(aChildToFind, nullptr);
|
||||
// It would be nice to assert that we find aChildToFind, but bz thinks that
|
||||
// we might not find aChildToFind when called from ContentInserted
|
||||
// if first-letter frames are about.
|
||||
while (nsIContent* child = GetNextChild()) {
|
||||
if (child == aChildToFind) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIContent* ExplicitChildIterator::Get() const {
|
||||
MOZ_ASSERT(!mIsFirst);
|
||||
|
||||
// When mParentAsSlot is set, mChild is always set to the current child. It
|
||||
// does not matter whether mChild is an assigned node or a fallback content.
|
||||
nsIContent* FlattenedChildIterator::GetPreviousChild() {
|
||||
if (mIsFirst) { // at the beginning of the child list
|
||||
return nullptr;
|
||||
}
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
MOZ_ASSERT(mIndexInInserted <= assignedNodes.Length());
|
||||
if (mIndexInInserted == 0) {
|
||||
mIsFirst = true;
|
||||
return nullptr;
|
||||
}
|
||||
mChild = assignedNodes[--mIndexInInserted]->AsContent();
|
||||
return mChild;
|
||||
}
|
||||
|
||||
if (mIndexInInserted) {
|
||||
MOZ_ASSERT_UNREACHABLE("This needs to be revisited");
|
||||
}
|
||||
|
||||
return mDefaultChild ? mDefaultChild : mChild;
|
||||
}
|
||||
|
||||
nsIContent* ExplicitChildIterator::GetPreviousChild() {
|
||||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (--mIndexInInserted)
|
||||
? assignedNodes[mIndexInInserted - 1]->AsContent()
|
||||
: nullptr;
|
||||
|
||||
if (!mChild) {
|
||||
mIsFirst = true;
|
||||
}
|
||||
return mChild;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("This needs to be revisited");
|
||||
} else if (mDefaultChild) {
|
||||
// If we're already in default content, check if there are more nodes there
|
||||
mDefaultChild = mDefaultChild->GetPreviousSibling();
|
||||
if (mDefaultChild) {
|
||||
return mDefaultChild;
|
||||
}
|
||||
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else if (mIsFirst) { // at the beginning of the child list
|
||||
return nullptr;
|
||||
} else if (mChild) { // in the middle of the child list
|
||||
if (mChild) { // in the middle of the child list
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else { // at the end of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = assignedNodes.Length();
|
||||
mChild = assignedNodes[mIndexInInserted - 1]->AsContent();
|
||||
return mChild;
|
||||
}
|
||||
}
|
||||
|
||||
mChild = mParent->GetLastChild();
|
||||
}
|
||||
|
||||
if (!mChild) {
|
||||
mIsFirst = true;
|
||||
}
|
||||
|
@ -186,25 +130,25 @@ nsIContent* ExplicitChildIterator::GetPreviousChild() {
|
|||
nsIContent* AllChildrenIterator::Get() const {
|
||||
switch (mPhase) {
|
||||
case eAtMarkerKid: {
|
||||
Element* marker = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
Element* marker = nsLayoutUtils::GetMarkerPseudo(Parent());
|
||||
MOZ_ASSERT(marker, "No content marker frame at eAtMarkerKid phase");
|
||||
return marker;
|
||||
}
|
||||
|
||||
case eAtBeforeKid: {
|
||||
Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
Element* before = nsLayoutUtils::GetBeforePseudo(Parent());
|
||||
MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
|
||||
return before;
|
||||
}
|
||||
|
||||
case eAtExplicitKids:
|
||||
return ExplicitChildIterator::Get();
|
||||
case eAtFlatTreeKids:
|
||||
return FlattenedChildIterator::Get();
|
||||
|
||||
case eAtAnonKids:
|
||||
return mAnonKids[mAnonKidsIdx];
|
||||
|
||||
case eAtAfterKid: {
|
||||
Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
Element* after = nsLayoutUtils::GetAfterPseudo(Parent());
|
||||
MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase");
|
||||
return after;
|
||||
}
|
||||
|
@ -216,24 +160,23 @@ nsIContent* AllChildrenIterator::Get() const {
|
|||
|
||||
bool AllChildrenIterator::Seek(const nsIContent* aChildToFind) {
|
||||
if (mPhase == eAtBegin || mPhase == eAtMarkerKid) {
|
||||
mPhase = eAtBeforeKid;
|
||||
Element* markerPseudo = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
Element* markerPseudo = nsLayoutUtils::GetMarkerPseudo(Parent());
|
||||
if (markerPseudo && markerPseudo == aChildToFind) {
|
||||
mPhase = eAtMarkerKid;
|
||||
return true;
|
||||
}
|
||||
mPhase = eAtBeforeKid;
|
||||
}
|
||||
if (mPhase == eAtBeforeKid) {
|
||||
mPhase = eAtExplicitKids;
|
||||
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(Parent());
|
||||
if (beforePseudo && beforePseudo == aChildToFind) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return true;
|
||||
}
|
||||
mPhase = eAtFlatTreeKids;
|
||||
}
|
||||
|
||||
if (mPhase == eAtExplicitKids) {
|
||||
if (ExplicitChildIterator::Seek(aChildToFind)) {
|
||||
if (mPhase == eAtFlatTreeKids) {
|
||||
if (FlattenedChildIterator::Seek(aChildToFind)) {
|
||||
return true;
|
||||
}
|
||||
mPhase = eAtAnonKids;
|
||||
|
@ -248,36 +191,31 @@ bool AllChildrenIterator::Seek(const nsIContent* aChildToFind) {
|
|||
}
|
||||
|
||||
void AllChildrenIterator::AppendNativeAnonymousChildren() {
|
||||
nsContentUtils::AppendNativeAnonymousChildren(mOriginalContent, mAnonKids,
|
||||
mFlags);
|
||||
nsContentUtils::AppendNativeAnonymousChildren(Parent(), mAnonKids, mFlags);
|
||||
}
|
||||
|
||||
nsIContent* AllChildrenIterator::GetNextChild() {
|
||||
if (mPhase == eAtBegin) {
|
||||
Element* markerContent = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
if (markerContent) {
|
||||
mPhase = eAtMarkerKid;
|
||||
mPhase = eAtMarkerKid;
|
||||
if (Element* markerContent = nsLayoutUtils::GetMarkerPseudo(Parent())) {
|
||||
return markerContent;
|
||||
}
|
||||
}
|
||||
|
||||
if (mPhase == eAtBegin || mPhase == eAtMarkerKid) {
|
||||
mPhase = eAtExplicitKids;
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforeContent) {
|
||||
mPhase = eAtBeforeKid;
|
||||
if (mPhase == eAtMarkerKid) {
|
||||
mPhase = eAtBeforeKid;
|
||||
if (Element* beforeContent = nsLayoutUtils::GetBeforePseudo(Parent())) {
|
||||
return beforeContent;
|
||||
}
|
||||
}
|
||||
|
||||
if (mPhase == eAtBeforeKid) {
|
||||
// Advance into our explicit kids.
|
||||
mPhase = eAtExplicitKids;
|
||||
mPhase = eAtFlatTreeKids;
|
||||
}
|
||||
|
||||
if (mPhase == eAtExplicitKids) {
|
||||
nsIContent* kid = ExplicitChildIterator::GetNextChild();
|
||||
if (kid) {
|
||||
if (mPhase == eAtFlatTreeKids) {
|
||||
if (nsIContent* kid = FlattenedChildIterator::GetNextChild()) {
|
||||
return kid;
|
||||
}
|
||||
mPhase = eAtAnonKids;
|
||||
|
@ -300,9 +238,8 @@ nsIContent* AllChildrenIterator::GetNextChild() {
|
|||
return mAnonKids[mAnonKidsIdx];
|
||||
}
|
||||
|
||||
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
if (afterContent) {
|
||||
mPhase = eAtAfterKid;
|
||||
mPhase = eAtAfterKid;
|
||||
if (Element* afterContent = nsLayoutUtils::GetAfterPseudo(Parent())) {
|
||||
return afterContent;
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +252,7 @@ nsIContent* AllChildrenIterator::GetPreviousChild() {
|
|||
if (mPhase == eAtEnd) {
|
||||
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
|
||||
mPhase = eAtAnonKids;
|
||||
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
Element* afterContent = nsLayoutUtils::GetAfterPseudo(Parent());
|
||||
if (afterContent) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterContent;
|
||||
|
@ -338,24 +275,23 @@ nsIContent* AllChildrenIterator::GetPreviousChild() {
|
|||
if (mAnonKidsIdx < mAnonKids.Length()) {
|
||||
return mAnonKids[mAnonKidsIdx];
|
||||
}
|
||||
mPhase = eAtExplicitKids;
|
||||
mPhase = eAtFlatTreeKids;
|
||||
}
|
||||
|
||||
if (mPhase == eAtExplicitKids) {
|
||||
nsIContent* kid = ExplicitChildIterator::GetPreviousChild();
|
||||
if (kid) {
|
||||
if (mPhase == eAtFlatTreeKids) {
|
||||
if (nsIContent* kid = FlattenedChildIterator::GetPreviousChild()) {
|
||||
return kid;
|
||||
}
|
||||
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(Parent());
|
||||
if (beforeContent) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeContent;
|
||||
}
|
||||
}
|
||||
|
||||
if (mPhase == eAtExplicitKids || mPhase == eAtBeforeKid) {
|
||||
Element* markerContent = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
if (mPhase == eAtFlatTreeKids || mPhase == eAtBeforeKid) {
|
||||
Element* markerContent = nsLayoutUtils::GetMarkerPseudo(Parent());
|
||||
if (markerContent) {
|
||||
mPhase = eAtMarkerKid;
|
||||
return markerContent;
|
||||
|
|
|
@ -11,121 +11,60 @@
|
|||
#include "nsIContentInlines.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Iterates over the children on a node. If a child is an insertion point,
|
||||
* iterates over the children inserted there instead, or the default content
|
||||
* if no children are inserted there.
|
||||
*
|
||||
* The FlattenedChildIterator expands any anonymous content bound from an XBL
|
||||
* binding's <xbl:content> element.
|
||||
*/
|
||||
|
||||
class nsIContent;
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
// This class iterates normal DOM child nodes of a given DOM node with
|
||||
// <xbl:children> nodes replaced by the elements that have been filtered into
|
||||
// that insertion point. Any bindings on the given element are ignored for
|
||||
// purposes of determining which insertion point children are filtered into. The
|
||||
// iterator can be initialized to start at the end by providing false for
|
||||
// Iterates over the flattened children of a node, that is, the regular DOM
|
||||
// child nodes of a given DOM node, with assigned nodes as slot children, and
|
||||
// shadow host children replaced by their shadow root.
|
||||
//
|
||||
// The iterator can be initialized to start at the end by providing false for
|
||||
// aStartAtBeginning in order to start iterating in reverse from the last child.
|
||||
class ExplicitChildIterator {
|
||||
class FlattenedChildIterator {
|
||||
public:
|
||||
explicit ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true);
|
||||
explicit FlattenedChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true);
|
||||
|
||||
nsIContent* GetNextChild();
|
||||
|
||||
// Looks for aChildToFind respecting insertion points until aChildToFind is
|
||||
// found. This version can take shortcuts that the two-argument version
|
||||
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
|
||||
// cases).
|
||||
// found. This can be O(1) instead of O(N) in many cases.
|
||||
bool Seek(const nsIContent* aChildToFind);
|
||||
|
||||
// Looks for aChildToFind respecting insertion points until aChildToFind is
|
||||
// found. or aBound is found. If aBound is nullptr then the seek is unbounded.
|
||||
// Returns whether aChildToFind was found as an explicit child prior to
|
||||
// encountering aBound.
|
||||
bool Seek(const nsIContent* aChildToFind, nsIContent* aBound) {
|
||||
// It would be nice to assert that we find aChildToFind, but bz thinks that
|
||||
// we might not find aChildToFind when called from ContentInserted
|
||||
// if first-letter frames are about.
|
||||
|
||||
// We can't easily take shortcuts here because we'd have to have a way to
|
||||
// compare aChildToFind to aBound.
|
||||
nsIContent* child;
|
||||
do {
|
||||
child = GetNextChild();
|
||||
} while (child && child != aChildToFind && child != aBound);
|
||||
|
||||
return child == aChildToFind;
|
||||
}
|
||||
|
||||
// Returns the current target of this iterator (which might be an explicit
|
||||
// child of the node, fallback content of an insertion point or
|
||||
// a node distributed to an insertion point.
|
||||
nsIContent* Get() const;
|
||||
// child of the node, or a node assigned to a slot.
|
||||
nsIContent* Get() const { return mChild; }
|
||||
|
||||
// Returns the original parent we were initialized with.
|
||||
const nsIContent* Parent() const { return mOriginalParent; }
|
||||
|
||||
// The inverse of GetNextChild. Properly steps in and out of insertion
|
||||
// points.
|
||||
nsIContent* GetPreviousChild();
|
||||
|
||||
bool ShadowDOMInvolved() const { return mShadowDOMInvolved; }
|
||||
|
||||
protected:
|
||||
// The parent of the children being iterated. For the FlattenedChildIterator,
|
||||
// if there is a binding attached to the original parent, mParent points to
|
||||
// the <xbl:content> element for the binding.
|
||||
// The parent of the children being iterated. For shadow hosts this will point
|
||||
// to its shadow root.
|
||||
const nsIContent* mParent;
|
||||
|
||||
// If parent is a slot element, this points to the parent as HTMLSlotElement,
|
||||
// otherwise, it's null.
|
||||
const HTMLSlotElement* mParentAsSlot;
|
||||
// If parent is a slot element with assigned slots, this points to the parent
|
||||
// as HTMLSlotElement, otherwise, it's null.
|
||||
const HTMLSlotElement* mParentAsSlot = nullptr;
|
||||
|
||||
// The current child. When we encounter an insertion point,
|
||||
// mChild remains as the insertion point whose content we're iterating (and
|
||||
// our state is controled by mDefaultChild or mIndexInInserted depending on
|
||||
// whether the insertion point expands to its default content or not).
|
||||
nsIContent* mChild;
|
||||
const nsIContent* mOriginalParent = nullptr;
|
||||
|
||||
// If non-null, this points to the current default content for the current
|
||||
// insertion point that we're iterating (i.e. mChild, which must be an
|
||||
// nsXBLChildrenElement or HTMLContentElement). Once this transitions back
|
||||
// to null, we continue iterating at mChild's next sibling.
|
||||
nsIContent* mDefaultChild;
|
||||
// The current child.
|
||||
nsIContent* mChild = nullptr;
|
||||
|
||||
// A flag to let us know that we haven't started iterating yet.
|
||||
bool mIsFirst;
|
||||
bool mIsFirst = false;
|
||||
|
||||
// If not zero, we're iterating inserted children for an insertion point. This
|
||||
// is an index into mChild's inserted children array (mChild must be an
|
||||
// nsXBLChildrenElement). The index is one past the "current" child (as
|
||||
// opposed to mChild which represents the "current" child).
|
||||
uint32_t mIndexInInserted;
|
||||
};
|
||||
|
||||
// Iterates over the flattened children of a node, which accounts for anonymous
|
||||
// children and nodes moved by insertion points. If a node has anonymous
|
||||
// children, those are iterated over. The iterator can be initialized to start
|
||||
// at the end by providing false for aStartAtBeginning in order to start
|
||||
// iterating in reverse from the last child.
|
||||
class FlattenedChildIterator : public ExplicitChildIterator {
|
||||
public:
|
||||
explicit FlattenedChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning),
|
||||
mOriginalContent(aParent) {
|
||||
Init();
|
||||
}
|
||||
|
||||
bool ShadowDOMInvolved() { return mShadowDOMInvolved; }
|
||||
|
||||
const nsIContent* Parent() const { return mOriginalContent; }
|
||||
|
||||
protected:
|
||||
const nsIContent* mOriginalContent;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
// The index of the current element in the slot assigned nodes. One-past the
|
||||
// end to represent the last position.
|
||||
uint32_t mIndexInInserted = 0u;
|
||||
|
||||
// For certain optimizations, nsCSSFrameConstructor needs to know if the child
|
||||
// list of the element that we're iterating matches its .childNodes.
|
||||
|
@ -180,7 +119,7 @@ class AllChildrenIterator : private FlattenedChildIterator {
|
|||
eAtBegin,
|
||||
eAtMarkerKid,
|
||||
eAtBeforeKid,
|
||||
eAtExplicitKids,
|
||||
eAtFlatTreeKids,
|
||||
eAtAnonKids,
|
||||
eAtAfterKid,
|
||||
eAtEnd
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/CSSEnabledState.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ContentBlockingAllowList.h"
|
||||
#include "mozilla/ContentBlockingNotifier.h"
|
||||
#include "mozilla/ContentBlockingUserInteraction.h"
|
||||
|
@ -96,6 +95,7 @@
|
|||
#include "mozilla/PresShellInlines.h"
|
||||
#include "mozilla/PseudoStyleType.h"
|
||||
#include "mozilla/RefCountType.h"
|
||||
#include "mozilla/RejectForeignAllowList.h"
|
||||
#include "mozilla/RelativeTo.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "mozilla/ReverseIterator.h"
|
||||
|
@ -11878,7 +11878,7 @@ void Document::OnPageHide(bool aPersisted, EventTarget* aDispatchStartTarget,
|
|||
NotifyActivityChanged();
|
||||
|
||||
ClearPendingFullscreenRequests(this);
|
||||
if (GetUnretargetedFullScreenElement()) {
|
||||
if (Fullscreen()) {
|
||||
// If this document was fullscreen, we should exit fullscreen in this
|
||||
// doctree branch. This ensures that if the user navigates while in
|
||||
// fullscreen mode we don't leave its still visible ancestor documents
|
||||
|
@ -14276,7 +14276,7 @@ static uint32_t CountFullscreenSubDocuments(Document& aDoc) {
|
|||
uint32_t count = 0;
|
||||
// FIXME(emilio): Should this be recursive and dig into our nested subdocs?
|
||||
auto subDoc = [&count](Document& aSubDoc) {
|
||||
if (aSubDoc.GetUnretargetedFullScreenElement()) {
|
||||
if (aSubDoc.Fullscreen()) {
|
||||
count++;
|
||||
}
|
||||
return CallState::Continue;
|
||||
|
@ -14288,17 +14288,17 @@ static uint32_t CountFullscreenSubDocuments(Document& aDoc) {
|
|||
bool Document::IsFullscreenLeaf() {
|
||||
// A fullscreen leaf document is fullscreen, and has no fullscreen
|
||||
// subdocuments.
|
||||
if (!GetUnretargetedFullScreenElement()) {
|
||||
return false;
|
||||
}
|
||||
return CountFullscreenSubDocuments(*this) == 0;
|
||||
//
|
||||
// FIXME(emilio): This doesn't seem to account for fission iframes, is that
|
||||
// ok?
|
||||
return Fullscreen() && CountFullscreenSubDocuments(*this) == 0;
|
||||
}
|
||||
|
||||
static Document* GetFullscreenLeaf(Document& aDoc) {
|
||||
if (aDoc.IsFullscreenLeaf()) {
|
||||
return &aDoc;
|
||||
}
|
||||
if (!aDoc.GetUnretargetedFullScreenElement()) {
|
||||
if (!aDoc.Fullscreen()) {
|
||||
return nullptr;
|
||||
}
|
||||
Document* leaf = nullptr;
|
||||
|
@ -14321,12 +14321,11 @@ static Document* GetFullscreenLeaf(Document* aDoc) {
|
|||
}
|
||||
|
||||
static CallState ResetFullscreen(Document& aDocument) {
|
||||
if (Element* fsElement = aDocument.GetUnretargetedFullScreenElement()) {
|
||||
if (Element* fsElement = aDocument.GetUnretargetedFullscreenElement()) {
|
||||
NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1,
|
||||
"Should have at most 1 fullscreen subdocument.");
|
||||
aDocument.CleanupFullscreenState();
|
||||
NS_ASSERTION(!aDocument.GetUnretargetedFullScreenElement(),
|
||||
"Should reset fullscreen");
|
||||
NS_ASSERTION(!aDocument.Fullscreen(), "Should reset fullscreen");
|
||||
DispatchFullscreenChange(aDocument, fsElement);
|
||||
aDocument.EnumerateSubDocuments(ResetFullscreen);
|
||||
}
|
||||
|
@ -14379,7 +14378,7 @@ void Document::ExitFullscreenInDocTree(Document* aMaybeNotARootDoc) {
|
|||
}
|
||||
|
||||
nsCOMPtr<Document> root = aMaybeNotARootDoc->GetFullscreenRoot();
|
||||
if (!root || !root->GetUnretargetedFullScreenElement()) {
|
||||
if (!root || !root->Fullscreen()) {
|
||||
// If a document was detached before exiting from fullscreen, it is
|
||||
// possible that the root had left fullscreen state. In this case,
|
||||
// we would not get anything from the ResetFullscreen() call. Root's
|
||||
|
@ -14400,7 +14399,7 @@ void Document::ExitFullscreenInDocTree(Document* aMaybeNotARootDoc) {
|
|||
// Walk the tree of fullscreen documents, and reset their fullscreen state.
|
||||
ResetFullscreen(*root);
|
||||
|
||||
NS_ASSERTION(!root->GetUnretargetedFullScreenElement(),
|
||||
NS_ASSERTION(!root->Fullscreen(),
|
||||
"Fullscreen root should no longer be a fullscreen doc...");
|
||||
|
||||
// Move the top-level window out of fullscreen mode.
|
||||
|
@ -14418,15 +14417,14 @@ static void DispatchFullscreenNewOriginEvent(Document* aDoc) {
|
|||
}
|
||||
|
||||
void Document::RestorePreviousFullscreenState(UniquePtr<FullscreenExit> aExit) {
|
||||
NS_ASSERTION(
|
||||
!GetUnretargetedFullScreenElement() || !FullscreenRoots::IsEmpty(),
|
||||
"Should have at least 1 fullscreen root when fullscreen!");
|
||||
NS_ASSERTION(!Fullscreen() || !FullscreenRoots::IsEmpty(),
|
||||
"Should have at least 1 fullscreen root when fullscreen!");
|
||||
|
||||
if (!GetWindow()) {
|
||||
aExit->MayRejectPromise("No active window");
|
||||
return;
|
||||
}
|
||||
if (!GetUnretargetedFullScreenElement() || FullscreenRoots::IsEmpty()) {
|
||||
if (!Fullscreen() || FullscreenRoots::IsEmpty()) {
|
||||
aExit->MayRejectPromise("Not in fullscreen mode");
|
||||
return;
|
||||
}
|
||||
|
@ -14437,7 +14435,7 @@ void Document::RestorePreviousFullscreenState(UniquePtr<FullscreenExit> aExit) {
|
|||
Document* doc = fullScreenDoc;
|
||||
// Collect all subdocuments.
|
||||
for (; doc != this; doc = doc->GetInProcessParentDocument()) {
|
||||
Element* fsElement = doc->GetUnretargetedFullScreenElement();
|
||||
Element* fsElement = doc->GetUnretargetedFullscreenElement();
|
||||
MOZ_ASSERT(fsElement,
|
||||
"Parent document of "
|
||||
"a fullscreen document without fullscreen element?");
|
||||
|
@ -14446,7 +14444,7 @@ void Document::RestorePreviousFullscreenState(UniquePtr<FullscreenExit> aExit) {
|
|||
MOZ_ASSERT(doc == this, "Must have reached this doc");
|
||||
// Collect all ancestor documents which we are going to change.
|
||||
for (; doc; doc = doc->GetInProcessParentDocument()) {
|
||||
Element* fsElement = doc->GetUnretargetedFullScreenElement();
|
||||
Element* fsElement = doc->GetUnretargetedFullscreenElement();
|
||||
MOZ_ASSERT(fsElement,
|
||||
"Ancestor of fullscreen document must also be in fullscreen");
|
||||
if (doc != this) {
|
||||
|
@ -14552,10 +14550,11 @@ static void NotifyFullScreenChangedForMediaElement(Element& aElement) {
|
|||
}
|
||||
|
||||
void Document::CleanupFullscreenState() {
|
||||
while (PopFullscreenElement()) {
|
||||
/* Remove the next one if appropriate */
|
||||
while (PopFullscreenElement(UpdateViewport::No)) {
|
||||
// Remove the next one if appropriate
|
||||
}
|
||||
|
||||
UpdateViewportScrollbarOverrideForFullscreen(this);
|
||||
mFullscreenRoot = nullptr;
|
||||
|
||||
// Restore the zoom level that was in place prior to entering fullscreen.
|
||||
|
@ -14567,7 +14566,7 @@ void Document::CleanupFullscreenState() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Document::PopFullscreenElement() {
|
||||
bool Document::PopFullscreenElement(UpdateViewport aUpdateViewport) {
|
||||
Element* removedElement = TopLayerPop([](Element* element) -> bool {
|
||||
return element->State().HasState(ElementState::FULLSCREEN);
|
||||
});
|
||||
|
@ -14583,7 +14582,9 @@ bool Document::PopFullscreenElement() {
|
|||
if (auto* iframe = HTMLIFrameElement::FromNode(removedElement)) {
|
||||
iframe->SetFullscreenFlag(false);
|
||||
}
|
||||
UpdateViewportScrollbarOverrideForFullscreen(this);
|
||||
if (aUpdateViewport == UpdateViewport::Yes) {
|
||||
UpdateViewportScrollbarOverrideForFullscreen(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -14838,7 +14839,7 @@ Element* Document::GetTopLayerTop() {
|
|||
return element;
|
||||
}
|
||||
|
||||
Element* Document::GetUnretargetedFullScreenElement() const {
|
||||
Element* Document::GetUnretargetedFullscreenElement() const {
|
||||
for (const nsWeakPtr& weakPtr : Reversed(mTopLayer)) {
|
||||
nsCOMPtr<Element> element(do_QueryReferent(weakPtr));
|
||||
// Per spec, the fullscreen element is the topmost element in the document’s
|
||||
|
@ -14964,7 +14965,7 @@ bool Document::FullscreenElementReadyCheck(FullscreenRequest& aRequest) {
|
|||
// is already the fullscreen element requests fullscreen, nothing
|
||||
// should change and no event should be dispatched, but we still need
|
||||
// to resolve the returned promise.
|
||||
Element* fullscreenElement = GetUnretargetedFullScreenElement();
|
||||
Element* fullscreenElement = GetUnretargetedFullscreenElement();
|
||||
if (elem == fullscreenElement) {
|
||||
aRequest.MayResolvePromise();
|
||||
return false;
|
||||
|
@ -15066,26 +15067,25 @@ static bool CheckFullscreenAllowedElementType(const Element* elem) {
|
|||
}
|
||||
|
||||
void Document::RequestFullscreen(UniquePtr<FullscreenRequest> aRequest,
|
||||
bool applyFullScreenDirectly) {
|
||||
bool aApplyFullscreenDirectly) {
|
||||
if (XRE_IsContentProcess()) {
|
||||
RequestFullscreenInContentProcess(std::move(aRequest),
|
||||
applyFullScreenDirectly);
|
||||
aApplyFullscreenDirectly);
|
||||
} else {
|
||||
RequestFullscreenInParentProcess(std::move(aRequest),
|
||||
applyFullScreenDirectly);
|
||||
aApplyFullscreenDirectly);
|
||||
}
|
||||
}
|
||||
|
||||
void Document::RequestFullscreenInContentProcess(
|
||||
UniquePtr<FullscreenRequest> aRequest, bool applyFullScreenDirectly) {
|
||||
UniquePtr<FullscreenRequest> aRequest, bool aApplyFullscreenDirectly) {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
// If we are in the content process, we can apply the fullscreen
|
||||
// state directly only if we have been in DOM fullscreen, because
|
||||
// otherwise we always need to notify the chrome.
|
||||
if (applyFullScreenDirectly ||
|
||||
!!nsContentUtils::GetInProcessSubtreeRootDocument(this)
|
||||
->GetUnretargetedFullScreenElement()) {
|
||||
if (aApplyFullscreenDirectly ||
|
||||
nsContentUtils::GetInProcessSubtreeRootDocument(this)->Fullscreen()) {
|
||||
ApplyFullscreen(std::move(aRequest));
|
||||
return;
|
||||
}
|
||||
|
@ -15110,7 +15110,7 @@ void Document::RequestFullscreenInContentProcess(
|
|||
}
|
||||
|
||||
void Document::RequestFullscreenInParentProcess(
|
||||
UniquePtr<FullscreenRequest> aRequest, bool applyFullScreenDirectly) {
|
||||
UniquePtr<FullscreenRequest> aRequest, bool aApplyFullscreenDirectly) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
nsCOMPtr<nsPIDOMWindowOuter> rootWin = GetRootWindow(this);
|
||||
if (!rootWin) {
|
||||
|
@ -15118,7 +15118,8 @@ void Document::RequestFullscreenInParentProcess(
|
|||
return;
|
||||
}
|
||||
|
||||
if (applyFullScreenDirectly || ShouldApplyFullscreenDirectly(this, rootWin)) {
|
||||
if (aApplyFullscreenDirectly ||
|
||||
ShouldApplyFullscreenDirectly(this, rootWin)) {
|
||||
ApplyFullscreen(std::move(aRequest));
|
||||
return;
|
||||
}
|
||||
|
@ -15274,7 +15275,7 @@ bool Document::ApplyFullscreen(UniquePtr<FullscreenRequest> aRequest) {
|
|||
// reversed so that events are dispatched in the tree order as
|
||||
// indicated in the spec.
|
||||
for (Document* d : Reversed(changed)) {
|
||||
DispatchFullscreenChange(*d, d->GetUnretargetedFullScreenElement());
|
||||
DispatchFullscreenChange(*d, d->GetUnretargetedFullscreenElement());
|
||||
}
|
||||
aRequest->MayResolvePromise();
|
||||
return true;
|
||||
|
@ -16424,7 +16425,7 @@ void Document::MaybeAllowStorageForOpenerAfterUserInteraction() {
|
|||
}
|
||||
|
||||
// We don't care when the asynchronous work finishes here.
|
||||
Unused << ContentBlocking::AllowAccessFor(
|
||||
Unused << StorageAccessAPIHelper::AllowAccessFor(
|
||||
NodePrincipal(), openerBC,
|
||||
ContentBlockingNotifier::eOpenerAfterUserInteraction);
|
||||
}
|
||||
|
@ -16833,7 +16834,7 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
|
|||
return NS_OK;
|
||||
}
|
||||
Maybe<bool> resultBecauseCookiesApproved =
|
||||
ContentBlocking::CheckCookiesPermittedDecidesStorageAccessAPI(
|
||||
StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), NodePrincipal());
|
||||
if (resultBecauseCookiesApproved.isSome()) {
|
||||
if (resultBecauseCookiesApproved.value()) {
|
||||
|
@ -16848,9 +16849,19 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
|
|||
// Step 2: Check if the browser settings determine whether or not this
|
||||
// document has access to its unpartitioned cookies.
|
||||
bool isThirdPartyDocument = AntiTrackingUtils::IsThirdPartyDocument(this);
|
||||
bool isOnRejectForeignAllowList = RejectForeignAllowList::Check(this);
|
||||
bool isOnThirdPartySkipList = false;
|
||||
if (mChannel) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
|
||||
isOnThirdPartySkipList = loadInfo->GetStoragePermission() ==
|
||||
nsILoadInfo::StoragePermissionAllowListed;
|
||||
}
|
||||
bool isThirdPartyTracker =
|
||||
nsContentUtils::IsThirdPartyTrackingResourceWindow(inner);
|
||||
Maybe<bool> resultBecauseBrowserSettings =
|
||||
ContentBlocking::CheckBrowserSettingsDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), isThirdPartyDocument);
|
||||
StorageAccessAPIHelper::CheckBrowserSettingsDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), isThirdPartyDocument, isOnRejectForeignAllowList,
|
||||
isOnThirdPartySkipList, isThirdPartyTracker);
|
||||
if (resultBecauseBrowserSettings.isSome()) {
|
||||
if (resultBecauseBrowserSettings.value()) {
|
||||
aHasStorageAccess = true;
|
||||
|
@ -16864,7 +16875,8 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
|
|||
// Step 3: Check if the location of this call (embedded, top level, same-site)
|
||||
// determines if cookies are permitted or not.
|
||||
Maybe<bool> resultBecauseCallContext =
|
||||
ContentBlocking::CheckCallingContextDecidesStorageAccessAPI(this, false);
|
||||
StorageAccessAPIHelper::CheckCallingContextDecidesStorageAccessAPI(this,
|
||||
false);
|
||||
if (resultBecauseCallContext.isSome()) {
|
||||
if (resultBecauseCallContext.value()) {
|
||||
aHasStorageAccess = true;
|
||||
|
@ -16878,7 +16890,8 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
|
|||
// Step 4: Check if the permissions for this document determine if if has
|
||||
// access or is denied cookies.
|
||||
Maybe<bool> resultBecausePreviousPermission =
|
||||
ContentBlocking::CheckExistingPermissionDecidesStorageAccessAPI(this);
|
||||
StorageAccessAPIHelper::CheckExistingPermissionDecidesStorageAccessAPI(
|
||||
this);
|
||||
if (resultBecausePreviousPermission.isSome()) {
|
||||
if (resultBecausePreviousPermission.value()) {
|
||||
aHasStorageAccess = true;
|
||||
|
@ -16888,7 +16901,6 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
|
|||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If you get here, we default to not giving you permission.
|
||||
aHasStorageAccess = false;
|
||||
return NS_OK;
|
||||
|
@ -16957,8 +16969,9 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
|
|||
// called later in CompleteAllowAccessFor inside of AllowAccessFor.
|
||||
auto performFinalChecks = [inner, self, principal, aHasUserInteraction]() {
|
||||
// Create the user prompt
|
||||
RefPtr<ContentBlocking::StorageAccessFinalCheckPromise::Private> p =
|
||||
new ContentBlocking::StorageAccessFinalCheckPromise::Private(__func__);
|
||||
RefPtr<StorageAccessAPIHelper::StorageAccessFinalCheckPromise::Private> p =
|
||||
new StorageAccessAPIHelper::StorageAccessFinalCheckPromise::Private(
|
||||
__func__);
|
||||
RefPtr<StorageAccessPermissionRequest> sapr =
|
||||
StorageAccessPermissionRequest::Create(
|
||||
inner, principal,
|
||||
|
@ -16966,7 +16979,7 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
|
|||
[p] {
|
||||
Telemetry::AccumulateCategorical(
|
||||
Telemetry::LABELS_STORAGE_ACCESS_API_UI::Allow);
|
||||
p->Resolve(ContentBlocking::eAllow, __func__);
|
||||
p->Resolve(StorageAccessAPIHelper::eAllow, __func__);
|
||||
},
|
||||
// Block
|
||||
[p] {
|
||||
|
@ -17016,10 +17029,10 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
|
|||
MOZ_ASSERT_IF(pr2 != PromptResult::Granted,
|
||||
pr2 == PromptResult::Denied);
|
||||
if (pr2 == PromptResult::Granted) {
|
||||
ContentBlocking::StorageAccessPromptChoices choice =
|
||||
ContentBlocking::eAllow;
|
||||
StorageAccessAPIHelper::StorageAccessPromptChoices choice =
|
||||
StorageAccessAPIHelper::eAllow;
|
||||
if (autoGrant) {
|
||||
choice = ContentBlocking::eAllowAutoGrant;
|
||||
choice = StorageAccessAPIHelper::eAllowAutoGrant;
|
||||
}
|
||||
if (!autoGrant) {
|
||||
p->Resolve(choice, __func__);
|
||||
|
@ -17046,8 +17059,8 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
|
|||
};
|
||||
|
||||
// Try to allow access for the given principal.
|
||||
return ContentBlocking::AllowAccessFor(principal, aBrowsingContext, aNotifier,
|
||||
performFinalChecks);
|
||||
return StorageAccessAPIHelper::AllowAccessFor(principal, aBrowsingContext,
|
||||
aNotifier, performFinalChecks);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
|
||||
|
@ -17063,12 +17076,33 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Step 0: Check that we have user activation before proceeding to prevent
|
||||
// rapid calls to the API to leak information.
|
||||
if (!HasValidTransientUserGestureActivation()) {
|
||||
// Report an error to the console for this case
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
nsLiteralCString("requestStorageAccess"),
|
||||
this, nsContentUtils::eDOM_PROPERTIES,
|
||||
"RequestStorageAccessUserGesture");
|
||||
this->ConsumeTransientUserGestureActivation();
|
||||
promise->MaybeRejectWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Get a pointer to the inner window- We need this for convenience sake
|
||||
RefPtr<nsPIDOMWindowInner> inner = this->GetInnerWindow();
|
||||
if (!inner) {
|
||||
this->ConsumeTransientUserGestureActivation();
|
||||
promise->MaybeRejectWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Step 1: Check if the principal calling this has a permission that lets
|
||||
// them use cookies or forbids them from using cookies.
|
||||
// This is outside of the spec of the StorageAccess API, but makes the return
|
||||
// values to have proper semantics.
|
||||
Maybe<bool> resultBecauseCookiesApproved =
|
||||
ContentBlocking::CheckCookiesPermittedDecidesStorageAccessAPI(
|
||||
StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), NodePrincipal());
|
||||
if (resultBecauseCookiesApproved.isSome()) {
|
||||
if (resultBecauseCookiesApproved.value()) {
|
||||
|
@ -17086,9 +17120,19 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
|
|||
// This is outside of the spec of the StorageAccess API, but makes the return
|
||||
// values to have proper semantics.
|
||||
bool isThirdPartyDocument = AntiTrackingUtils::IsThirdPartyDocument(this);
|
||||
bool isOnRejectForeignAllowList = RejectForeignAllowList::Check(this);
|
||||
bool isOnThirdPartySkipList = false;
|
||||
if (mChannel) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
|
||||
isOnThirdPartySkipList = loadInfo->GetStoragePermission() ==
|
||||
nsILoadInfo::StoragePermissionAllowListed;
|
||||
}
|
||||
bool isThirdPartyTracker =
|
||||
nsContentUtils::IsThirdPartyTrackingResourceWindow(inner);
|
||||
Maybe<bool> resultBecauseBrowserSettings =
|
||||
ContentBlocking::CheckBrowserSettingsDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), isThirdPartyDocument);
|
||||
StorageAccessAPIHelper::CheckBrowserSettingsDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), isThirdPartyDocument, isOnRejectForeignAllowList,
|
||||
isOnThirdPartySkipList, isThirdPartyTracker);
|
||||
if (resultBecauseBrowserSettings.isSome()) {
|
||||
if (resultBecauseBrowserSettings.value()) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
|
@ -17103,7 +17147,8 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
|
|||
// Step 3: Check if the Document calling requestStorageAccess has anything to
|
||||
// gain from storage access. It should be embedded, non-null, etc.
|
||||
Maybe<bool> resultBecauseCallContext =
|
||||
ContentBlocking::CheckCallingContextDecidesStorageAccessAPI(this, true);
|
||||
StorageAccessAPIHelper::CheckCallingContextDecidesStorageAccessAPI(this,
|
||||
true);
|
||||
if (resultBecauseCallContext.isSome()) {
|
||||
if (resultBecauseCallContext.value()) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
|
@ -17118,7 +17163,8 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
|
|||
// Step 4: Check if we already allowed or denied storage access for this
|
||||
// document's storage key.
|
||||
Maybe<bool> resultBecausePreviousPermission =
|
||||
ContentBlocking::CheckExistingPermissionDecidesStorageAccessAPI(this);
|
||||
StorageAccessAPIHelper::CheckExistingPermissionDecidesStorageAccessAPI(
|
||||
this);
|
||||
if (resultBecausePreviousPermission.isSome()) {
|
||||
if (resultBecausePreviousPermission.value()) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
|
@ -17132,12 +17178,6 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
|
|||
|
||||
// Get pointers to some objects that will be used in the async portion
|
||||
RefPtr<BrowsingContext> bc = this->GetBrowsingContext();
|
||||
nsPIDOMWindowInner* inner = this->GetInnerWindow();
|
||||
if (!inner) {
|
||||
this->ConsumeTransientUserGestureActivation();
|
||||
promise->MaybeRejectWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
RefPtr<nsGlobalWindowOuter> outer =
|
||||
nsGlobalWindowOuter::Cast(inner->GetOuterWindow());
|
||||
if (!outer) {
|
||||
|
@ -17159,19 +17199,12 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
|
|||
ContentBlockingNotifier::eStorageAccessAPI)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[self, outer, promise] {
|
||||
// Step 10. Grant the document access to cookies and store
|
||||
// that fact for
|
||||
// the purposes of future calls to
|
||||
// hasStorageAccess() and requestStorageAccess().
|
||||
outer->SetStorageAccessPermissionGranted(true);
|
||||
[self, inner, promise] {
|
||||
inner->SaveStorageAccessPermissionGranted();
|
||||
self->NotifyUserGestureActivation();
|
||||
promise->MaybeResolveWithUndefined();
|
||||
},
|
||||
[outer, promise] {
|
||||
outer->SetStorageAccessPermissionGranted(false);
|
||||
promise->MaybeRejectWithUndefined();
|
||||
});
|
||||
[promise] { promise->MaybeRejectWithUndefined(); });
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -17189,6 +17222,19 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Step 0: Check that we have user activation before proceeding to prevent
|
||||
// rapid calls to the API to leak information.
|
||||
if (aRequireUserActivation && !HasValidTransientUserGestureActivation()) {
|
||||
// Report an error to the console for this case
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
nsLiteralCString("requestStorageAccess"),
|
||||
this, nsContentUtils::eDOM_PROPERTIES,
|
||||
"RequestStorageAccessUserGesture");
|
||||
this->ConsumeTransientUserGestureActivation();
|
||||
promise->MaybeRejectWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Step 1: Check if the provided URI is different-site to this Document
|
||||
nsCOMPtr<nsIURI> thirdPartyURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(thirdPartyURI), aThirdPartyOrigin);
|
||||
|
@ -17202,9 +17248,12 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
|
|||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
bool isOnRejectForeignAllowList =
|
||||
RejectForeignAllowList::Check(thirdPartyURI);
|
||||
Maybe<bool> resultBecauseBrowserSettings =
|
||||
ContentBlocking::CheckBrowserSettingsDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), isThirdPartyDocument);
|
||||
StorageAccessAPIHelper::CheckBrowserSettingsDecidesStorageAccessAPI(
|
||||
CookieJarSettings(), isThirdPartyDocument, isOnRejectForeignAllowList,
|
||||
false, true);
|
||||
if (resultBecauseBrowserSettings.isSome()) {
|
||||
if (resultBecauseBrowserSettings.value()) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
|
@ -17217,8 +17266,8 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
|
|||
|
||||
// Step 2: Check that this Document is same-site to the top, and check that
|
||||
// we have user activation if we require it.
|
||||
Maybe<bool> resultBecauseCallContext =
|
||||
ContentBlocking::CheckSameSiteCallingContextDecidesStorageAccessAPI(
|
||||
Maybe<bool> resultBecauseCallContext = StorageAccessAPIHelper::
|
||||
CheckSameSiteCallingContextDecidesStorageAccessAPI(
|
||||
this, aRequireUserActivation);
|
||||
if (resultBecauseCallContext.isSome()) {
|
||||
if (resultBecauseCallContext.value()) {
|
||||
|
@ -17265,7 +17314,7 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
|
|||
// permission, but this can't be done in this process. We needs the cookie
|
||||
// permission of the URL as if it were embedded on this page, so we need to
|
||||
// make this check in the ContentParent.
|
||||
ContentBlocking::AsyncCheckCookiesPermittedDecidesStorageAccessAPI(
|
||||
StorageAccessAPIHelper::AsyncCheckCookiesPermittedDecidesStorageAccessAPI(
|
||||
GetBrowsingContext(), principal)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
|
@ -17314,7 +17363,8 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
|
|||
GetCurrentSerialEventTarget(), __func__,
|
||||
// If the previous handlers resolved, we should reinstate user
|
||||
// activation and resolve the promise we returned in Step 5.
|
||||
[self, promise] {
|
||||
[self, inner, promise] {
|
||||
inner->SaveStorageAccessPermissionGranted();
|
||||
self->NotifyUserGestureActivation();
|
||||
promise->MaybeResolveWithUndefined();
|
||||
},
|
||||
|
@ -17655,8 +17705,7 @@ nsIPrincipal* Document::EffectiveStoragePrincipal() const {
|
|||
// We use the lower-level ContentBlocking API here to ensure this
|
||||
// check doesn't send notifications.
|
||||
uint32_t rejectedReason = 0;
|
||||
if (ContentBlocking::ShouldAllowAccessFor(inner, GetDocumentURI(),
|
||||
&rejectedReason)) {
|
||||
if (ShouldAllowAccessFor(inner, GetDocumentURI(), &rejectedReason)) {
|
||||
return mActiveStoragePrincipal = NodePrincipal();
|
||||
}
|
||||
|
||||
|
|
|
@ -1891,13 +1891,13 @@ class Document : public nsINode,
|
|||
// This is called asynchronously by Document::AsyncRequestFullscreen()
|
||||
// to move this document into fullscreen mode if allowed.
|
||||
void RequestFullscreen(UniquePtr<FullscreenRequest> aRequest,
|
||||
bool applyFullScreenDirectly = false);
|
||||
bool aApplyFullscreenDirectly = false);
|
||||
|
||||
private:
|
||||
void RequestFullscreenInContentProcess(UniquePtr<FullscreenRequest> aRequest,
|
||||
bool applyFullScreenDirectly);
|
||||
bool aApplyFullscreenDirectly);
|
||||
void RequestFullscreenInParentProcess(UniquePtr<FullscreenRequest> aRequest,
|
||||
bool applyFullScreenDirectly);
|
||||
bool aApplyFullscreenDirectly);
|
||||
|
||||
// Pushes aElement onto the top layer
|
||||
void TopLayerPush(Element&);
|
||||
|
@ -1913,7 +1913,8 @@ class Document : public nsINode,
|
|||
|
||||
// Pops the fullscreen element from the top layer and clears its
|
||||
// fullscreen flag. Returns whether there was any fullscreen element.
|
||||
bool PopFullscreenElement();
|
||||
enum class UpdateViewport : bool { No, Yes };
|
||||
bool PopFullscreenElement(UpdateViewport = UpdateViewport::Yes);
|
||||
|
||||
// Pushes the given element into the top of top layer and set fullscreen
|
||||
// flag.
|
||||
|
@ -3394,8 +3395,8 @@ class Document : public nsINode,
|
|||
|
||||
Element* GetTopLayerTop();
|
||||
// Return the fullscreen element in the top layer
|
||||
Element* GetUnretargetedFullScreenElement() const;
|
||||
bool Fullscreen() const { return !!GetUnretargetedFullScreenElement(); }
|
||||
Element* GetUnretargetedFullscreenElement() const;
|
||||
bool Fullscreen() const { return !!GetUnretargetedFullscreenElement(); }
|
||||
already_AddRefed<Promise> ExitFullscreen(ErrorResult&);
|
||||
void ExitPointerLock() { PointerLockManager::Unlock(this); }
|
||||
void GetFgColor(nsAString& aFgColor);
|
||||
|
|
|
@ -313,7 +313,7 @@ Element* DocumentOrShadowRoot::GetFullscreenElement() const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Element* element = AsNode().OwnerDoc()->GetUnretargetedFullScreenElement();
|
||||
Element* element = AsNode().OwnerDoc()->GetUnretargetedFullscreenElement();
|
||||
NS_ASSERTION(!element || element->State().HasState(ElementState::FULLSCREEN),
|
||||
"Fullscreen element should have fullscreen styles applied");
|
||||
|
||||
|
|
|
@ -55,19 +55,12 @@ class MessageManagerCallback {
|
|||
ErrorResult& aError) const;
|
||||
|
||||
protected:
|
||||
bool BuildClonedMessageDataForParent(ContentParent* aParent,
|
||||
StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData);
|
||||
bool BuildClonedMessageDataForChild(ContentChild* aChild,
|
||||
StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData);
|
||||
bool BuildClonedMessageData(StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData);
|
||||
};
|
||||
|
||||
void UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData);
|
||||
|
||||
void UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData);
|
||||
void UnpackClonedMessageData(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData);
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace dom
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "nsPluginArray.h"
|
||||
#include "nsMimeTypeArray.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ContentBlockingNotifier.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/BodyExtractor.h"
|
||||
|
|
|
@ -366,8 +366,7 @@ PointerLockManager::PointerLockRequest::Run() {
|
|||
}
|
||||
// If it is neither user input initiated, nor requested in fullscreen,
|
||||
// it should be rejected.
|
||||
if (!error && !mUserInputOrChromeCaller &&
|
||||
!document->GetUnretargetedFullScreenElement()) {
|
||||
if (!error && !mUserInputOrChromeCaller && !document->Fullscreen()) {
|
||||
error = "PointerLockDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ class PostMessageEvent final : public Runnable {
|
|||
mHolder.construct<ipc::StructuredCloneData>();
|
||||
// FIXME Want to steal!
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1516349.
|
||||
mHolder.ref<ipc::StructuredCloneData>().CopyFromClonedMessageDataForChild(
|
||||
mHolder.ref<ipc::StructuredCloneData>().CopyFromClonedMessageData(
|
||||
aMessageData);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue