Bug 820926 - Hide void-element's closing tag if the page is an HTML page. r=pbro
Though, if the element has pseudo-elements, and thus can be expanded, show
the closing tag when the void element is expanded.
MozReview-Commit-ID: 7UMMlVjYqLX
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -18,16 +18,21 @@ const NEW_SELECTION_HIGHLIGHTER_TIMER =
const DRAG_DROP_AUTOSCROLL_EDGE_DISTANCE = 50;
const DRAG_DROP_MIN_AUTOSCROLL_SPEED = 5;
const DRAG_DROP_MAX_AUTOSCROLL_SPEED = 15;
const DRAG_DROP_MIN_INITIAL_DISTANCE = 10;
const AUTOCOMPLETE_POPUP_PANEL_ID = "markupview_autoCompletePopup";
const ATTR_COLLAPSE_ENABLED_PREF = "devtools.markup.collapseAttributes";
const ATTR_COLLAPSE_LENGTH_PREF = "devtools.markup.collapseAttributeLength";
+// Contains only void (without end tag) HTML elements
+const HTML_VOID_ELEMENTS = [ "area", "base", "br", "col", "command", "embed",
+ "hr", "img", "input", "keygen", "link", "meta", "param", "source",
+ "track", "wbr" ];
+
const {UndoStack} = require("devtools/client/shared/undo");
const {editableField, InplaceEditor} =
require("devtools/client/shared/inplace-editor");
const {HTMLEditor} = require("devtools/client/inspector/markup/html-editor");
const promise = require("promise");
const Services = require("Services");
const {Tooltip} = require("devtools/client/shared/widgets/Tooltip");
const EventEmitter = require("devtools/shared/event-emitter");
@@ -2674,16 +2679,21 @@ function ElementEditor(container, node)
});
}
});
let tagName = this.getTagName(this.node);
this.tag.textContent = tagName;
this.closeTag.textContent = tagName;
+ let isVoidElement = HTML_VOID_ELEMENTS.includes(tagName);
+ if (node.isInHTMLDocument && isVoidElement) {
+ this.elt.classList.add("void-element");
+ }
+
this.update();
this.initialized = true;
}
ElementEditor.prototype = {
set selected(value) {
if (this.textEditor) {
this.textEditor.selected = value;
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -22,16 +22,18 @@ support-files =
doc_markup_navigation.html
doc_markup_not_displayed.html
doc_markup_pagesize_01.html
doc_markup_pagesize_02.html
doc_markup_search.html
doc_markup_svg_attributes.html
doc_markup_toggle.html
doc_markup_tooltip.png
+ doc_markup_void_elements.html
+ doc_markup_void_elements.xhtml
doc_markup_xul.xul
head.js
helper_attributes_test_runner.js
helper_events_test_runner.js
helper_outerhtml_test_runner.js
helper_style_attr_test_runner.js
lib_jquery_1.0.js
lib_jquery_1.1.js
@@ -123,8 +125,10 @@ skip-if = e10s # Bug 1036409 - The last
[browser_markup_tag_edit_12.js]
[browser_markup_tag_edit_13-other.js]
[browser_markup_textcontent_edit_01.js]
[browser_markup_textcontent_edit_02.js]
[browser_markup_toggle_01.js]
[browser_markup_toggle_02.js]
[browser_markup_toggle_03.js]
[browser_markup_update-on-navigtion.js]
+[browser_markup_void_elements_html.js]
+[browser_markup_void_elements_xhtml.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_void_elements_html.js
@@ -0,0 +1,44 @@
+/* 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 void element display in the markupview.
+const TEST_URL = URL_ROOT + "doc_markup_void_elements.html";
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+ let {win} = inspector.markup;
+
+ info("check non-void element closing tag is displayed");
+ let {editor} = yield getContainerForSelector("h1", inspector);
+ ok(!editor.elt.classList.contains("void-element"),
+ "h1 element does not have void-element class");
+ ok(!editor.elt.querySelector(".close").style.display !== "none",
+ "h1 element tag is not hidden");
+
+ info("check void element closing tag is hidden in HTML document");
+ let container = yield getContainerForSelector("img", inspector);
+ ok(container.editor.elt.classList.contains("void-element"),
+ "img element has the expected class");
+ let closeElement = container.editor.elt.querySelector(".close");
+ let computedStyle = win.getComputedStyle(closeElement, null);
+ ok(computedStyle.display === "none", "img closing tag is hidden");
+
+ info("check void element with pseudo element");
+ let hrNodeFront = yield getNodeFront("hr.before", inspector);
+ container = getContainerForNodeFront(hrNodeFront, inspector);
+ ok(container.editor.elt.classList.contains("void-element"),
+ "hr element has the expected class");
+ closeElement = container.editor.elt.querySelector(".close");
+ computedStyle = win.getComputedStyle(closeElement, null);
+ ok(computedStyle.display === "none", "hr closing tag is hidden");
+
+ info("check expanded void element closing tag is not hidden");
+ yield inspector.markup.expandNode(hrNodeFront);
+ yield waitForMultipleChildrenUpdates(inspector);
+ ok(container.expanded, "hr container is expanded");
+ computedStyle = win.getComputedStyle(closeElement, null);
+ ok(computedStyle.display === "none", "hr closing tag is not hidden anymore");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_void_elements_xhtml.js
@@ -0,0 +1,28 @@
+/* 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 void element display in the markupview.
+const TEST_URL = URL_ROOT + "doc_markup_void_elements.xhtml";
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+ let {win} = inspector.markup;
+
+ info("check non-void element closing tag is displayed");
+ let {editor} = yield getContainerForSelector("h1", inspector);
+ ok(!editor.elt.classList.contains("void-element"),
+ "h1 element does not have void-element class");
+ ok(!editor.elt.querySelector(".close").style.display !== "none",
+ "h1 element tag is not hidden");
+
+ info("check void element closing tag is not hidden in XHTML document");
+ let container = yield getContainerForSelector("br", inspector);
+ ok(!container.editor.elt.classList.contains("void-element"),
+ "br element does not have void-element class");
+ let closeElement = container.editor.elt.querySelector(".close");
+ let computedStyle = win.getComputedStyle(closeElement, null);
+ ok(computedStyle.display !== "none", "br closing tag is not hidden");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/doc_markup_void_elements.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="html">
+ <head class="head">
+ <meta charset=utf-8 />
+ <style>
+ .before:before {
+ content: "before";
+ }
+ </style>
+ </head>
+ <body class="body">
+ <h1>Test void elements in HTML document</h1>
+ <img>
+ <hr>
+ <hr class="before">
+ <br>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/doc_markup_void_elements.xhtml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head class="head">
+ <meta charset="utf-8" />
+ <style>
+ .before:before {
+ content: "before";
+ }
+ </style>
+ </head>
+ <body class="body">
+ <h1>Test void elements in XHTML document</h1>
+ <hr class="before" />
+ <img />
+ <hr />
+ <br />
+ </body>
+</html>
--- a/devtools/client/themes/markup.css
+++ b/devtools/client/themes/markup.css
@@ -188,16 +188,22 @@ ul.children + .tag-line::before {
.child.collapsed > .tag-line ~ .tag-line {
display: none;
}
.child.collapsed .close {
display: inline;
}
+/* Hide HTML void elements (img, hr, br, …) closing tag when the element is not
+ * expanded (it can be if it has pseudo-elements attached) */
+.child.collapsed > .tag-line .void-element .close {
+ display: none;
+}
+
.closing-bracket {
pointer-events: none;
}
.newattr {
display: inline-block;
width: 1em;
height: 1ex;
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -276,17 +276,18 @@ var NodeActor = exports.NodeActor = prot
isAfterPseudoElement: this.isAfterPseudoElement,
isAnonymous: isAnonymous(this.rawNode),
isNativeAnonymous: isNativeAnonymous(this.rawNode),
isXBLAnonymous: isXBLAnonymous(this.rawNode),
isShadowAnonymous: isShadowAnonymous(this.rawNode),
pseudoClassLocks: this.writePseudoClassLocks(),
isDisplayed: this.isDisplayed,
-
+ isInHTMLDocument: this.rawNode.ownerDocument &&
+ this.rawNode.ownerDocument.contentType === "text/html",
hasEventListeners: this._hasEventListeners,
};
if (this.isDocumentElement()) {
form.isDocumentElement = true;
}
if (this.rawNode.nodeValue) {
@@ -911,17 +912,19 @@ var NodeFront = protocol.FrontClass(Node
return this._form.isAfterPseudoElement;
},
get isPseudoElement() {
return this.isBeforePseudoElement || this.isAfterPseudoElement;
},
get isAnonymous() {
return this._form.isAnonymous;
},
-
+ get isInHTMLDocument() {
+ return this._form.isInHTMLDocument;
+ },
get tagName() {
return this.nodeType === Ci.nsIDOMNode.ELEMENT_NODE ? this.nodeName : null;
},
get shortValue() {
return this._form.shortValue;
},
get incompleteValue() {
return !!this._form.incompleteValue;