merge fx-team to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-10-12 12:00:50 +02:00
Родитель 6b31140392 a38e6ca6d7
Коммит a93333bf09
25 изменённых файлов: 313 добавлений и 209 удалений

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

@ -8,3 +8,7 @@
.dom-searchbox {
float: right;
}
.dom-searchbox:dir(rtl) {
float: left;
}

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

@ -32,7 +32,12 @@ body {
/* Space for read only properties icon */
.treeTable td.treeValueCell {
padding-left: 16px;
padding-inline-start: 16px;
}
.treeTable .treeLabel,
.treeTable td.treeValueCell .objectBox {
direction: ltr; /* Don't change the direction of english labels */
}
/* Read only properties have a padlock icon */
@ -42,6 +47,10 @@ body {
background-size: 10px 10px;
}
.treeTable tr:not(.writable) td.treeValueCell:dir(rtl) {
background-position-x: right 1px;
}
/* Non-enumerable properties are grayed out */
.treeTable tr:not(.enumerable) td.treeValueCell {
opacity: 0.7;
@ -87,14 +96,6 @@ body {
font-weight: bold;
}
/******************************************************************************/
/* Selection */
.treeTable .treeRow:hover a,
.treeTable .treeRow:hover span {
color: var(--theme-selection-color) !important;
}
/******************************************************************************/
/* Theme Dark */

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

@ -3,7 +3,7 @@
- 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/. -->
<!DOCTYPE html>
<html>
<html dir="">
<head>
<meta charset="utf-8"/>

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

@ -30,6 +30,7 @@ support-files =
doc_markup_tooltip.png
doc_markup_void_elements.html
doc_markup_void_elements.xhtml
doc_markup_whitespace.html
doc_markup_xul.xul
head.js
helper_attributes_test_runner.js
@ -151,3 +152,4 @@ skip-if = e10s # Bug 1036409 - The last selected node isn't reselected
[browser_markup_update-on-navigtion.js]
[browser_markup_void_elements_html.js]
[browser_markup_void_elements_xhtml.js]
[browser_markup_whitespace.js]

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

@ -22,7 +22,9 @@ const TEST_DATA = [
["right", "node4"],
["down", "*text*"],
["down", "node5"],
["down", "*text*"],
["down", "node6"],
["down", "*text*"],
["down", "*comment*"],
["down", "node7"],
["right", "node7"],
@ -33,9 +35,13 @@ const TEST_DATA = [
["right", "node7"],
["right", "*text*"],
["down", "node8"],
["down", "*text*"],
["down", "node9"],
["down", "*text*"],
["down", "node10"],
["down", "*text*"],
["down", "node11"],
["down", "*text*"],
["down", "node12"],
["right", "node12"],
["down", "*text*"],
@ -53,13 +59,17 @@ const TEST_DATA = [
["home", "*doctype*"],
["pagedown", "*text*"],
["down", "node5"],
["down", "*text*"],
["down", "node6"],
["down", "*text*"],
["down", "*comment*"],
["down", "node7"],
["left", "node7"],
["down", "*text*"],
["down", "node9"],
["down", "*text*"],
["down", "node10"],
["pageup", "node2"],
["pageup", "*text*"],
["pageup", "*doctype*"],
["down", "html"],
["left", "html"],

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

@ -0,0 +1,66 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that whitespace text nodes do show up in the markup-view when needed.
const TEST_URL = URL_ROOT + "doc_markup_whitespace.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let {markup} = inspector;
yield markup.expandAll();
info("Verify the number of child nodes and child elements in body");
// Body has 5 element children, but there are 6 text nodes in there too, they come from
// the HTML file formatting (spaces and carriage returns).
let {numNodes, numChildren} = yield testActor.getNodeInfo("body");
is(numNodes, 11, "The body node has 11 child nodes (includes text nodes)");
is(numChildren, 5, "The body node has 5 child elements (only element nodes)");
// In body, there are only block-level elements, so whitespace text nodes do not have
// layout, so they should be skipped in the markup-view.
info("Check that the body's whitespace text node children aren't shown");
let bodyContainer = markup.getContainer(inspector.selection.nodeFront);
let childContainers = bodyContainer.getChildContainers();
is(childContainers.length, 5,
"Only the element nodes are shown in the markup view");
// div#inline has 3 element children, but there are 4 text nodes in there too, like in
// body, they come from spaces and carriage returns in the HTML file.
info("Verify the number of child nodes and child elements in div#inline");
({numNodes, numChildren} = yield testActor.getNodeInfo("#inline"));
is(numNodes, 7, "The div#inline node has 7 child nodes (includes text nodes)");
is(numChildren, 3, "The div#inline node has 3 child elements (only element nodes)");
// Within the inline formatting context in div#inline, the whitespace text nodes between
// the images have layout, so they should appear in the markup-view.
info("Check that the div#inline's whitespace text node children are shown");
yield selectNode("#inline", inspector);
let divContainer = markup.getContainer(inspector.selection.nodeFront);
childContainers = divContainer.getChildContainers();
is(childContainers.length, 5,
"Both the element nodes and some text nodes are shown in the markup view");
// div#pre has 2 element children, but there are 3 text nodes in there too, like in
// div#inline, they come from spaces and carriage returns in the HTML file.
info("Verify the number of child nodes and child elements in div#pre");
({numNodes, numChildren} = yield testActor.getNodeInfo("#pre"));
is(numNodes, 5, "The div#pre node has 5 child nodes (includes text nodes)");
is(numChildren, 2, "The div#pre node has 2 child elements (only element nodes)");
// Within the inline formatting context in div#pre, the whitespace text nodes between
// the images have layout, so they should appear in the markup-view, but since
// white-space is set to pre, then the whitespace text nodes before and after the first
// and last image should also appear.
info("Check that the div#pre's whitespace text node children are shown");
yield selectNode("#pre", inspector);
divContainer = markup.getContainer(inspector.selection.nodeFront);
childContainers = divContainer.getChildContainers();
is(childContainers.length, 5,
"Both the element nodes and all text nodes are shown in the markup view");
});

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

@ -16,16 +16,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=858038
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=858038">Mozilla Bug 858038</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<input id="anonymousParent" />
<span id="before">Before<!-- Force not-inline --></span>
<pre id="test">
<span id="firstChild">First</span>
<span id="middleChild">Middle</span>
<span id="lastChild">Last</span>
</pre>
<span id="after">After</span>
<input id="anonymousParent" /><span id="before">Before<!-- Force not-inline --></span>
<pre id="test"><span id="firstChild">First</span><span id="middleChild">Middle</span><span id="lastChild">Last</span></pre> <span id="after">After</span>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
#pre {
white-space: pre;
}
</style>
</head>
<body>
<div>div 1</div>
<div>div 2</div>
<div>div 3</div>
<div id="inline">
<img src="chrome://branding/content/about-logo.png" />
<img src="chrome://branding/content/about-logo.png" />
<img src="chrome://branding/content/about-logo.png" />
</div>
<div id="pre">
<img src="chrome://branding/content/about-logo.png" />
<img src="chrome://branding/content/about-logo.png" />
</div>
</body>
</html>

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

@ -259,7 +259,8 @@ MarkupContainer.prototype = {
return null;
}
return [...this.children.children].map(node => node.container);
return [...this.children.children].filter(node => node.container)
.map(node => node.container);
},
/**

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

@ -27,11 +27,12 @@ RootContainer.prototype = {
destroy: function () {},
/**
* If the node has children, return the list of containers for all these
* children.
* If the node has children, return the list of containers for all these children.
* @return {Array} An array of child containers or null.
*/
getChildContainers: function () {
return [...this.children.children].map(node => node.container);
return [...this.children.children].filter(node => node.container)
.map(node => node.container);
},
/**

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

@ -7,6 +7,9 @@
const {getAutocompleteMaxWidth} = require("devtools/client/inspector/markup/utils");
const {editableField} = require("devtools/client/shared/inplace-editor");
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
const {LocalizationHelper} = require("devtools/shared/l10n");
const INSPECTOR_L10N = new LocalizationHelper("devtools/locale/inspector.properties");
/**
* Creates a simple text editor node, used for TEXT and COMMENT
@ -79,6 +82,16 @@ TextEditor.prototype = {
}).then(str => {
longstr.release().then(null, console.error);
this.value.textContent = str;
let isWhitespace = !/[^\s]/.exec(str);
this.value.classList.toggle("whitespace", isWhitespace);
let chars = str.replace(/\n/g, "⏎")
.replace(/\t/g, "⇥")
.replace(/ /g, "◦");
this.value.setAttribute("title", isWhitespace
? INSPECTOR_L10N.getFormatStr("markupView.whitespaceOnly", chars)
: "");
}).then(null, console.error);
},

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

@ -33,6 +33,10 @@ markupView.more.showing=Some nodes were hidden.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
markupView.more.showAll2=Show one more node;Show all #1 nodes
# LOCALIZATION NOTE (markupView.whitespaceOnly)
# Used in a tooltip that appears when the user hovers over whitespace-only text nodes in
# the inspector.
markupView.whitespaceOnly=Whitespace-only text node: %S
#LOCALIZATION NOTE: Used in the image preview tooltip when the image could not be loaded
previewTooltip.image.brokenImage=Could not load the image

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

@ -44,7 +44,9 @@ define(function (require, exports, module) {
let grip = this.props.object;
return (
span({className: "objectBox objectBox-function"},
// Set dir="ltr" to prevent function parentheses from
// appearing in the wrong direction
span({dir: "ltr", className: "objectBox objectBox-function"},
this.getTitle(grip),
this.summarizeFunction(grip)
)

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

@ -33,15 +33,25 @@ define(function (require, exports, module) {
// Compute indentation dynamically. The deeper the item is
// inside the hierarchy, the bigger is the left padding.
let rowStyle = {
"paddingLeft": (level * 16) + "px",
"paddingInlineStart": (level * 16) + "px",
};
let iconClassList = ["treeIcon"];
if (member.hasChildren && member.loading) {
iconClassList.push("devtools-throbber");
} else if (member.hasChildren) {
iconClassList.push("theme-twisty");
}
if (member.open) {
iconClassList.push("open");
}
return (
td({
className: "treeLabelCell",
key: "default",
style: rowStyle},
span({ className: "treeIcon" }),
span({ className: iconClassList.join(" ") }),
span({
className: "treeLabel " + member.type + "Label",
"data-level": level

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

@ -18,7 +18,7 @@
/* TreeView Table*/
.treeTable .treeLabelCell {
padding: 2px 0 2px 0px;
padding: 2px 0;
vertical-align: top;
white-space: nowrap;
}
@ -29,20 +29,21 @@
}
.treeTable .treeValueCell {
padding: 2px 0 2px 5px;
padding: 2px 0;
padding-inline-start: 5px;
overflow: hidden;
}
.treeTable .treeLabel {
cursor: default;
overflow: hidden;
padding-left: 4px;
padding-inline-start: 4px;
white-space: nowrap;
}
/* No paddding if there is actually no label */
.treeTable .treeLabel:empty {
padding-left: 0;
padding-inline-start: 0;
}
.treeTable .treeRow.hasChildren > .treeLabelCell > .treeLabel:hover {
@ -60,11 +61,12 @@
/* Toggle Icon */
.treeTable .treeRow .treeIcon {
height: 12px;
height: 14px;
width: 14px;
font-size: 10px; /* Set the size of loading spinner */
display: inline-block;
vertical-align: bottom;
margin-left: 3px;
margin-inline-start: 3px;
padding-top: 1px;
}
@ -75,14 +77,6 @@
background-repeat: no-repeat;
}
/* Spinner (used for async fetch). Needs to have higher priority than
theme toggle icons */
.treeTable .treeRow.hasChildren.loading > .treeLabelCell > .treeIcon {
background-image: url(chrome://devtools/skin/images/firebug/spinner.png) !important;
background-position: 2px 1px !important;
background-size: 9px 9px !important;
}
/******************************************************************************/
/* Header */
@ -106,7 +100,9 @@
}
.treeTable .treeHeaderCellBox {
padding: 2px 14px 2px 10px;
padding: 2px 0;
padding-inline-start: 10px;
padding-inline-end: 14px;
}
.treeTable .treeHeaderRow > .treeHeaderCell:first-child > .treeHeaderCellBox {
@ -137,44 +133,9 @@
/******************************************************************************/
/* Themes */
/* Light, Firebug Theme: toggle icon */
.theme-light .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon,
.theme-firebug .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon {
background-image: url(chrome://devtools/skin/images/controls.png);
background-size: 56px 28px;
background-position: 0 -14px;
}
.theme-light .treeTable .treeRow.hasChildren.opened > .treeLabelCell > .treeIcon,
.theme-firebug .treeTable .treeRow.hasChildren.opened > .treeLabelCell > .treeIcon {
background-image: url(chrome://devtools/skin/images/controls.png);
background-size: 56px 28px;
background-position: -14px -14px;
}
/* Dark Theme: toggle icon */
.theme-dark .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon {
background-image: url(chrome://devtools/skin/images/controls.png);
background-size: 56px 28px;
background-position: -28px -14px;
}
.theme-dark .treeTable .treeRow.hasChildren.opened > .treeLabelCell > .treeIcon {
background-image: url(chrome://devtools/skin/images/controls.png);
background-size: 56px 28px;
background-position: -42px -14px;
}
/* Support for retina displays */
@media (min-resolution: 1.1dppx) {
.treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon {
background-image: url("chrome://devtools/skin/images/controls@2x.png") !important;
}
}
.theme-light .treeTable .treeRow:hover,
.theme-dark .treeTable .treeRow:hover {
background-color: var(--theme-selection-background) !important;
background-color: var(--theme-selection-background-semitransparent) !important;
}
.theme-firebug .treeTable .treeRow:hover {

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

@ -754,6 +754,7 @@ var TestActor = exports.TestActor = protocol.ActorClassWithSpec(testSpec, {
tagName: node.tagName,
namespaceURI: node.namespaceURI,
numChildren: node.children.length,
numNodes: node.childNodes.length,
attributes: [...node.attributes].map(({name, value, namespaceURI}) => {
return {name, value, namespaceURI};
}),

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

@ -699,6 +699,66 @@ checkbox:-moz-focusring {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
/* Twisty and checkbox controls */
.theme-twisty, .theme-checkbox {
width: 14px;
height: 14px;
background-repeat: no-repeat;
background-image: url("chrome://devtools/skin/images/controls.png");
background-size: 56px 28px;
}
.theme-twisty {
cursor: pointer;
background-position: 0 -14px;
}
.theme-selected ~ .theme-twisty,
.theme-dark .theme-twisty {
background-position: -28px -14px;
}
.theme-twisty:-moz-focusring {
outline-style: none;
}
.theme-twisty[open], .theme-twisty.open {
background-position: -14px -14px;
}
.theme-selected ~ .theme-twisty[open],
.theme-dark .theme-twisty[open], .theme-dark .theme-twisty.open {
background-position: -42px -14px;
}
.theme-twisty[invisible] {
visibility: hidden;
}
/* Mirror the twisty for rtl direction */
.theme-twisty:dir(rtl),
.theme-twisty:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.theme-checkbox {
display: inline-block;
border: 0;
padding: 0;
outline: none;
background-position: -28px 0;
}
.theme-checkbox[checked] {
background-position: -42px 0;
}
@media (min-resolution: 1.1dppx) {
.theme-twisty, .theme-checkbox {
background-image: url("chrome://devtools/skin/images/controls@2x.png");
}
}
/* Throbbers */
.devtools-throbber::before {
content: "";

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

@ -256,56 +256,6 @@ div.CodeMirror span.eval-text {
min-height: 1.4em;
}
/* Twisty and checkbox controls */
.theme-twisty, .theme-checkbox {
width: 14px;
height: 14px;
background-repeat: no-repeat;
background-image: url("chrome://devtools/skin/images/controls.png");
background-size: 56px 28px;
}
.theme-twisty {
cursor: pointer;
background-position: -28px -14px;
}
.theme-twisty:-moz-focusring {
outline-style: none;
}
.theme-twisty[open], .theme-twisty.open {
background-position: -42px -14px;
}
.theme-twisty[invisible] {
visibility: hidden;
}
/* Mirror the twisty for rtl direction */
.theme-twisty:dir(rtl),
.theme-twisty:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.theme-checkbox {
display: inline-block;
border: 0;
padding: 0;
outline: none;
background-position: -28px 0;
}
.theme-checkbox[checked] {
background-position: -42px 0;
}
@media (min-resolution: 1.1dppx) {
.theme-twisty, .theme-checkbox {
background-image: url("chrome://devtools/skin/images/controls@2x.png");
}
}
/* XUL panel styling (see devtools/client/shared/widgets/tooltip/Tooltip.js) */
.theme-tooltip-panel .panel-arrowcontent {

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

@ -258,66 +258,6 @@ div.CodeMirror span.eval-text {
min-height: 1.4em;
}
/* Twisty and checkbox controls */
.theme-twisty, .theme-checkbox {
width: 14px;
height: 14px;
background-repeat: no-repeat;
background-image: url("chrome://devtools/skin/images/controls.png");
background-size: 56px 28px;
}
.theme-twisty {
cursor: pointer;
background-position: 0 -14px;
}
.theme-twisty:-moz-focusring {
outline-style: none;
}
.theme-twisty[open], .theme-twisty.open {
background-position: -14px -14px;
}
.theme-twisty[invisible] {
visibility: hidden;
}
/* Use white twisty when next to a selected item in markup view */
.theme-selected ~ .theme-twisty {
background-position: -28px -14px;
}
.theme-selected ~ .theme-twisty[open] {
background-position: -42px -14px;
}
/* Mirror the twisty for rtl direction */
.theme-twisty:dir(rtl),
.theme-twisty:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.theme-checkbox {
display: inline-block;
border: 0;
padding: 0;
outline: none;
background-position: 0 0;
}
.theme-checkbox[checked] {
background-position: -14px 0;
}
@media (min-resolution: 1.1dppx) {
.theme-twisty, .theme-checkbox {
background-image: url("chrome://devtools/skin/images/controls@2x.png");
}
}
/* XUL panel styling (see devtools/client/shared/widgets/tooltip/Tooltip.js) */
.theme-tooltip-panel .panel-arrowcontent {

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

@ -247,6 +247,25 @@ ul.children + .tag-line::before {
font: inherit;
}
/* Whitespace only text nodes are sometimes shown in the markup-view, and when they do
they get a greyed-out whitespace symbol so users know what they are */
.editor.text .whitespace {
padding: 0 .5em;
}
.editor.text .whitespace::before {
content: "";
display: inline-block;
height: 4px;
width: 4px;
border: 1px solid var(--theme-body-color-inactive);
border-radius: 50%;
}
.tag-line[selected] .editor.text .whitespace::before {
border-color: white;
}
.more-nodes {
padding-left: 16px;
}

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

@ -40,8 +40,11 @@
let packagedAppLocation = getTestFilePath("build_app" + testSuffix + "1");
let onValidated = waitForUpdate(win, "project-validated");
let onDetails = waitForUpdate(win, "details");
yield winProject.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "details");
yield onValidated;
yield onDetails;
let project = win.AppManager.selectedProject;
@ -77,8 +80,11 @@
// # Now test a full featured package.json
packagedAppLocation = getTestFilePath("build_app" + testSuffix + "2");
onValidated = waitForUpdate(win, "project-validated");
onDetails = waitForUpdate(win, "details");
yield winProject.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
yield onValidated;
yield onDetails;
project = win.AppManager.selectedProject;
@ -96,8 +102,11 @@
is(loggedMessages[3], "succeed", "log messages are correct");
// Switch to the package dir in order to verify the generated webapp.manifest
onValidated = waitForUpdate(win, "project-validated");
onDetails = waitForUpdate(win, "details");
yield winProject.projectList.importPackagedApp(packageDir);
yield waitForUpdate(win, "project-validated");
yield onValidated;
yield onDetails;
project = win.AppManager.selectedProject;

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

@ -27,19 +27,21 @@
yield win.AppProjects.load();
is(win.AppProjects.projects.length, 0, "IDB is empty");
info("to call importPackagedApp(" + packagedAppLocation + ")");
let onValidated = waitForUpdate(win, "project-validated");
let onDetails = waitForUpdate(win, "details");
yield winProject.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
yield nextTick();
yield onValidated;
yield onDetails;
info("to call importHostedApp(" + hostedAppManifest + ")");
yield winProject.projectList.importHostedApp(hostedAppManifest);
yield waitForUpdate(win, "project-validated");
yield nextTick();
info("to call importPackagedApp(" + packagedAppLocation + ") again");
onValidated = waitForUpdate(win, "project-validated");
onDetails = waitForUpdate(win, "details");
yield winProject.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
yield onValidated;
yield onDetails;
let project = win.AppManager.selectedProject;
is(project.location, packagedAppLocation, "Correctly reselected existing packaged app.");

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

@ -90,8 +90,11 @@
let packagedAppLocation = getTestFilePath("app");
let onValidated = waitForUpdate(win, "project-validated");
let onDetails = waitForUpdate(win, "details");
yield winProject.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
yield onValidated;
yield onDetails;
let panelNode = docRuntime.querySelector("#runtime-panel");
let items = panelNode.querySelectorAll(".runtime-panel-item-usb");

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

@ -120,8 +120,11 @@
return Task.spawn(function*() {
let packagedAppLocation = getTestFilePath("../app");
let winProject = getProjectWindow(win);
let onValidated = waitForUpdate(win, "project-validated");
let onDetails = waitForUpdate(win, "details");
yield winProject.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
yield onValidated;
yield onDetails;
});
}

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

@ -2958,10 +2958,11 @@ function standardTreeWalkerFilter(node) {
return nodeFilterConstants.FILTER_ACCEPT;
}
// Ignore empty whitespace text nodes.
if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
!/[^\s]/.exec(node.nodeValue)) {
return nodeFilterConstants.FILTER_SKIP;
// Ignore empty whitespace text nodes that do not impact the layout.
if (isWhitespaceTextNode(node)) {
return nodeHasSize(node)
? nodeFilterConstants.FILTER_ACCEPT
: nodeFilterConstants.FILTER_SKIP;
}
// Ignore all native and XBL anonymous content inside a non-XUL document
@ -2982,14 +2983,38 @@ function standardTreeWalkerFilter(node) {
* it also includes all anonymous content (like internal form controls).
*/
function allAnonymousContentTreeWalkerFilter(node) {
// Ignore empty whitespace text nodes.
if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
!/[^\s]/.exec(node.nodeValue)) {
return nodeFilterConstants.FILTER_SKIP;
// Ignore empty whitespace text nodes that do not impact the layout.
if (isWhitespaceTextNode(node)) {
return nodeHasSize(node)
? nodeFilterConstants.FILTER_ACCEPT
: nodeFilterConstants.FILTER_SKIP;
}
return nodeFilterConstants.FILTER_ACCEPT;
}
/**
* Is the given node a text node composed of whitespace only?
* @param {DOMNode} node
* @return {Boolean}
*/
function isWhitespaceTextNode(node) {
return node.nodeType == Ci.nsIDOMNode.TEXT_NODE && !/[^\s]/.exec(node.nodeValue);
}
/**
* Does the given node have non-0 width and height?
* @param {DOMNode} node
* @return {Boolean}
*/
function nodeHasSize(node) {
if (!node.getBoxQuads) {
return false;
}
let quads = node.getBoxQuads();
return quads.length && quads.some(quad => quad.bounds.width && quad.bounds.height);
}
/**
* Returns a promise that is settled once the given HTMLImageElement has
* finished loading.