Bug 1078374 - Show content of template tags in markup view;r=bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Fri, 08 Jun 2018 18:17:15 +0200
changeset 810772 af386c52748c55d518445c0175ac129c101a63da
parent 810086 03766e229910776476910a90ba4cebe97648c767
child 810773 be16034feeac2868938bc9a88ec30162f4d99433
push id114098
push userjdescottes@mozilla.com
push dateTue, 26 Jun 2018 13:21:46 +0000
reviewersbgrins
bugs1078374
milestone62.0a1
Bug 1078374 - Show content of template tags in markup view;r=bgrins MozReview-Commit-ID: pbctIItlC9
devtools/client/inspector/markup/views/markup-container.js
devtools/server/actors/inspector/node.js
devtools/server/actors/inspector/walker.js
devtools/server/tests/mochitest/chrome.ini
devtools/server/tests/mochitest/inspector-template.html
devtools/server/tests/mochitest/test_inspector-template.html
--- a/devtools/client/inspector/markup/views/markup-container.js
+++ b/devtools/client/inspector/markup/views/markup-container.js
@@ -433,16 +433,17 @@ MarkupContainer.prototype = {
     const tagName = this.node.tagName && this.node.tagName.toLowerCase();
 
     return !this.node.isPseudoElement &&
            !this.node.isAnonymous &&
            !this.node.isDocumentElement &&
            tagName !== "body" &&
            tagName !== "head" &&
            this.win.getSelection().isCollapsed &&
+           this.node.parentNode() &&
            this.node.parentNode().tagName !== null;
   },
 
   isSlotted: function() {
     return false;
   },
 
   /**
--- a/devtools/server/actors/inspector/node.js
+++ b/devtools/server/actors/inspector/node.js
@@ -193,16 +193,20 @@ const NodeActor = protocol.ActorClassWit
     if (this.isBeforePseudoElement || this.isAfterPseudoElement) {
       return false;
     }
 
     const parentNode = this.rawNode.parentNode;
     return parentNode && !!parentNode.openOrClosedShadowRoot;
   },
 
+  get isTemplateElement() {
+    return this.rawNode instanceof this.rawNode.ownerGlobal.HTMLTemplateElement;
+  },
+
   // Estimate the number of children that the walker will return without making
   // a call to children() if possible.
   get numChildren() {
     // For pseudo elements, childNodes.length returns 1, but the walker
     // will return 0.
     if (this.isBeforePseudoElement || this.isAfterPseudoElement) {
       return 0;
     }
--- a/devtools/server/actors/inspector/walker.js
+++ b/devtools/server/actors/inspector/walker.js
@@ -600,17 +600,30 @@ var WalkerActor = protocol.ActorClassWit
     if (options.center && options.start) {
       throw Error("Can't specify both 'center' and 'start' options.");
     }
     let maxNodes = options.maxNodes || -1;
     if (maxNodes == -1) {
       maxNodes = Number.MAX_VALUE;
     }
 
-    const { isShadowHost, isShadowRoot, isDirectShadowHostChild } = node;
+    const {
+      isDirectShadowHostChild,
+      isShadowHost,
+      isShadowRoot,
+      isTemplateElement,
+    } = node;
+
+    if (isTemplateElement) {
+      // <template> tags should have a single child pointing to the element's template
+      // content.
+      const documentFragment = node.rawNode.content;
+      const nodes = [this._ref(documentFragment)];
+      return { hasFirst: true, hasLast: true, nodes };
+    }
 
     // Detect special case of unslotted shadow host children that cannot rely on a
     // regular anonymous walker.
     let isUnslottedHostChild = false;
     if (isDirectShadowHostChild) {
       try {
         this.getDocumentWalker(node.rawNode, options.whatToShow, SKIP_TO_SIBLING);
       } catch (e) {
--- a/devtools/server/tests/mochitest/chrome.ini
+++ b/devtools/server/tests/mochitest/chrome.ini
@@ -15,16 +15,17 @@ support-files =
   inspector_getImageData.html
   inspector_getOffsetParent.html
   inspector-delay-image-response.sjs
   inspector-eyedropper.html
   inspector-helpers.js
   inspector-search-data.html
   inspector-styles-data.css
   inspector-styles-data.html
+  inspector-template.html
   inspector-traversal-data.html
   large-image.jpg
   memory-helpers.js
   nonchrome_unsafeDereference.html
   small-image.gif
   setup-in-child.js
   setup-in-parent.js
   webconsole-helpers.js
@@ -76,16 +77,17 @@ skip-if = (verify && debug && (os == 'wi
 [test_inspector-reload.html]
 [test_inspector-remove.html]
 [test_inspector-resize.html]
 [test_inspector-resolve-url.html]
 [test_inspector-retain.html]
 [test_inspector-search.html]
 [test_inspector-search-front.html]
 [test_inspector-scroll-into-view.html]
+[test_inspector-template.html]
 [test_inspector-traversal.html]
 [test_makeGlobalObjectReference.html]
 [test_memory.html]
 [test_memory_allocations_01.html]
 [test_memory_allocations_02.html]
 [test_memory_allocations_03.html]
 [test_memory_allocations_04.html]
 [test_memory_allocations_05.html]
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/mochitest/inspector-template.html
@@ -0,0 +1,18 @@
+<html>
+<body>
+  <template>
+    <p>template content</p>
+  </template>
+  <div></div>
+  <script>
+    "use strict";
+
+    const template = document.querySelector("template");
+    const clone = document.importNode(template.content, true);
+    document.querySelector("div").appendChild(clone);
+
+    window.opener.postMessage("ready", "*");
+  </script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/mochitest/test_inspector-template.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1078374
+Display template tag content in inspector.
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug </title>
+
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  <script type="application/javascript" src="inspector-helpers.js"></script>
+  <script type="application/javascript">
+"use strict";
+
+window.onload = function() {
+  SimpleTest.waitForExplicitFinish();
+
+  let gWalker = null;
+
+  addAsyncTest(async function setup() {
+    const url = document.getElementById("inspectorContent").href;
+
+    const {client, tab} = await new Promise(resolve => {
+      attachURL(url, function(err, _client, _tab, doc) {
+        resolve({ client: _client, tab: _tab });
+      });
+    });
+
+    const {InspectorFront} = require("devtools/shared/fronts/inspector");
+    const inspector = InspectorFront(client, tab);
+    gWalker = await inspector.getWalker();
+
+    runNextTest();
+  });
+
+  addAsyncTest(async function testWalker() {
+    const nodeFront = await gWalker.querySelector(gWalker.rootNode, "template");
+
+    let children = await gWalker.children(nodeFront);
+    is(children.nodes.length, 1, "Found one child under the template element");
+
+    const docFragment = children.nodes[0];
+    is(docFragment.nodeName, "#document-fragment",
+      "First child under <template> is a document-fragment");
+
+    children = await gWalker.children(docFragment);
+    is(children.nodes.length, 1, "Found one child under the template element");
+
+    const p = children.nodes[0];
+    is(p.nodeName, "P",
+      "First child under the document-fragment is a p element");
+
+    runNextTest();
+  });
+
+  runNextTest();
+};
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<a id="inspectorContent" target="_blank" href="inspector-template.html">Test Document</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>