diff --git a/devtools/client/dom/content/components/search-box.css b/devtools/client/dom/content/components/search-box.css index f857fe5db3a8..168b5bbd0a07 100644 --- a/devtools/client/dom/content/components/search-box.css +++ b/devtools/client/dom/content/components/search-box.css @@ -7,4 +7,8 @@ /* Search Box */ .dom-searchbox { float: right; -} \ No newline at end of file +} + +.dom-searchbox:dir(rtl) { + float: left; +} diff --git a/devtools/client/dom/content/dom-view.css b/devtools/client/dom/content/dom-view.css index c1293e934d7d..2d404325d6c2 100644 --- a/devtools/client/dom/content/dom-view.css +++ b/devtools/client/dom/content/dom-view.css @@ -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 */ diff --git a/devtools/client/dom/dom.html b/devtools/client/dom/dom.html index b1a654f28b2b..62172590d2a9 100644 --- a/devtools/client/dom/dom.html +++ b/devtools/client/dom/dom.html @@ -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/. --> - + diff --git a/devtools/client/inspector/markup/test/browser.ini b/devtools/client/inspector/markup/test/browser.ini index d7be4448331e..3116e4beb173 100644 --- a/devtools/client/inspector/markup/test/browser.ini +++ b/devtools/client/inspector/markup/test/browser.ini @@ -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] diff --git a/devtools/client/inspector/markup/test/browser_markup_navigation.js b/devtools/client/inspector/markup/test/browser_markup_navigation.js index a64a448566b2..5bfd9719fbee 100644 --- a/devtools/client/inspector/markup/test/browser_markup_navigation.js +++ b/devtools/client/inspector/markup/test/browser_markup_navigation.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"], diff --git a/devtools/client/inspector/markup/test/browser_markup_whitespace.js b/devtools/client/inspector/markup/test/browser_markup_whitespace.js new file mode 100644 index 000000000000..6de4e4dd5ac7 --- /dev/null +++ b/devtools/client/inspector/markup/test/browser_markup_whitespace.js @@ -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"); +}); diff --git a/devtools/client/inspector/markup/test/doc_markup_dragdrop.html b/devtools/client/inspector/markup/test/doc_markup_dragdrop.html index c6d9556df3ba..f45c26065348 100644 --- a/devtools/client/inspector/markup/test/doc_markup_dragdrop.html +++ b/devtools/client/inspector/markup/test/doc_markup_dragdrop.html @@ -16,16 +16,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=858038 Mozilla Bug 858038

- - - Before -
-    First
-    Middle
-    Last
-  
- After + Before +
FirstMiddleLast
After diff --git a/devtools/client/inspector/markup/test/doc_markup_whitespace.html b/devtools/client/inspector/markup/test/doc_markup_whitespace.html new file mode 100644 index 000000000000..9071c802d0a8 --- /dev/null +++ b/devtools/client/inspector/markup/test/doc_markup_whitespace.html @@ -0,0 +1,25 @@ + + + + + + + +
div 1
+
div 2
+
div 3
+
+ + + +
+
+ + +
+ + diff --git a/devtools/client/inspector/markup/views/markup-container.js b/devtools/client/inspector/markup/views/markup-container.js index e96e4a3eda86..22962e1d2a8d 100644 --- a/devtools/client/inspector/markup/views/markup-container.js +++ b/devtools/client/inspector/markup/views/markup-container.js @@ -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); }, /** diff --git a/devtools/client/inspector/markup/views/root-container.js b/devtools/client/inspector/markup/views/root-container.js index 0dceb803c9da..ccc918fca620 100644 --- a/devtools/client/inspector/markup/views/root-container.js +++ b/devtools/client/inspector/markup/views/root-container.js @@ -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); }, /** diff --git a/devtools/client/inspector/markup/views/text-editor.js b/devtools/client/inspector/markup/views/text-editor.js index 76a7dd8f5633..d0466fcf0e56 100644 --- a/devtools/client/inspector/markup/views/text-editor.js +++ b/devtools/client/inspector/markup/views/text-editor.js @@ -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); }, diff --git a/devtools/client/locales/en-US/inspector.properties b/devtools/client/locales/en-US/inspector.properties index 0bb985e2b5a9..c9dde23f9f5e 100644 --- a/devtools/client/locales/en-US/inspector.properties +++ b/devtools/client/locales/en-US/inspector.properties @@ -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 diff --git a/devtools/client/shared/components/reps/function.js b/devtools/client/shared/components/reps/function.js index 095d8e360d76..fd20dc3189c5 100644 --- a/devtools/client/shared/components/reps/function.js +++ b/devtools/client/shared/components/reps/function.js @@ -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) ) diff --git a/devtools/client/shared/components/tree/label-cell.js b/devtools/client/shared/components/tree/label-cell.js index 7963e915fa6b..e14875b4d28a 100644 --- a/devtools/client/shared/components/tree/label-cell.js +++ b/devtools/client/shared/components/tree/label-cell.js @@ -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 diff --git a/devtools/client/shared/components/tree/tree-view.css b/devtools/client/shared/components/tree/tree-view.css index f0bc7284389a..850533872ef1 100644 --- a/devtools/client/shared/components/tree/tree-view.css +++ b/devtools/client/shared/components/tree/tree-view.css @@ -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 { diff --git a/devtools/client/shared/test/test-actor.js b/devtools/client/shared/test/test-actor.js index 6b57622f0beb..d8e2cf65eb0d 100644 --- a/devtools/client/shared/test/test-actor.js +++ b/devtools/client/shared/test/test-actor.js @@ -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}; }), diff --git a/devtools/client/themes/common.css b/devtools/client/themes/common.css index 6a570ea2d4a3..4c0a5653d734 100644 --- a/devtools/client/themes/common.css +++ b/devtools/client/themes/common.css @@ -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: ""; diff --git a/devtools/client/themes/dark-theme.css b/devtools/client/themes/dark-theme.css index f9bdc05d1c9f..096b5694f056 100644 --- a/devtools/client/themes/dark-theme.css +++ b/devtools/client/themes/dark-theme.css @@ -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 { diff --git a/devtools/client/themes/light-theme.css b/devtools/client/themes/light-theme.css index a5f19edd1965..4d32b6ca0f52 100644 --- a/devtools/client/themes/light-theme.css +++ b/devtools/client/themes/light-theme.css @@ -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 { diff --git a/devtools/client/themes/markup.css b/devtools/client/themes/markup.css index c8a00ed73717..4b4cfd031f33 100644 --- a/devtools/client/themes/markup.css +++ b/devtools/client/themes/markup.css @@ -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; } diff --git a/devtools/client/webide/test/test_build.html b/devtools/client/webide/test/test_build.html index b5acb58c67bc..ffb01998c6d0 100644 --- a/devtools/client/webide/test/test_build.html +++ b/devtools/client/webide/test/test_build.html @@ -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; diff --git a/devtools/client/webide/test/test_duplicate_import.html b/devtools/client/webide/test/test_duplicate_import.html index 456778aa78cc..ef01e23e448d 100644 --- a/devtools/client/webide/test/test_duplicate_import.html +++ b/devtools/client/webide/test/test_duplicate_import.html @@ -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."); diff --git a/devtools/client/webide/test/test_runtime.html b/devtools/client/webide/test/test_runtime.html index ccde517be3fe..496e8c8b5b96 100644 --- a/devtools/client/webide/test/test_runtime.html +++ b/devtools/client/webide/test/test_runtime.html @@ -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"); diff --git a/devtools/client/webide/test/test_telemetry.html b/devtools/client/webide/test/test_telemetry.html index 89a9761e6965..225ddb89b370 100644 --- a/devtools/client/webide/test/test_telemetry.html +++ b/devtools/client/webide/test/test_telemetry.html @@ -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; }); } diff --git a/devtools/server/actors/inspector.js b/devtools/server/actors/inspector.js index bf953134c02f..8e3631cd1a09 100644 --- a/devtools/server/actors/inspector.js +++ b/devtools/server/actors/inspector.js @@ -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.