Source: DOM.js

  1. /**
  2. * @file
  3. *
  4. * Summary.
  5. *
  6. * <p>Print DOM tree.</p>
  7. *
  8. * @author F. Permadi and Paulo Roma
  9. * @since 2005
  10. * @copyright 2005-2022
  11. * @see <a href="/cwdc/10-html5css3/DOM.js">source</a>
  12. * @see https://www.permadi.com/tutorial/domTree/index.html
  13. */
  14. "use strict";
  15. /** Line feed character. */
  16. const linefeed = "<br>\n";
  17. /** White space character. */
  18. const space = "&nbsp;&nbsp;";
  19. /** White space plus a vertical bar. */
  20. const verticalbar = "&nbsp;&nbsp;&#124;";
  21. /** Dash. */
  22. const dash = "&#11153;";
  23. /**
  24. * Get all attribute names of a given element.
  25. *
  26. * @global
  27. * @function
  28. * @param {HTMLNode} el element.
  29. * @return {String} all atributes concatenated in a string: name="value" ...
  30. */
  31. const getAllAttributes = (el) =>
  32. el.getAttributeNames().reduce((str, name) => {
  33. str += ` ${name}=\"${el.getAttribute(name)}\"`;
  34. return str;
  35. }, "");
  36. /**
  37. * Traverses the DOM tree starting at an element and prints the tree.
  38. * This function is called recursively until the tree is fully traversed.
  39. *
  40. * @param {Window} targetDocument where the tree will be printed to.
  41. * @param {HTMLNode} currentElement root element.
  42. * @param {Number} depth the depth of the current element.
  43. */
  44. function traverseDOMTree(targetDocument, currentElement, depth = 1) {
  45. if (currentElement) {
  46. var j;
  47. var tagName = currentElement.tagName;
  48. // Prints the node tagName, such as <A>, <IMG>, etc
  49. if (tagName) {
  50. targetDocument.write(
  51. `&lt;${tagName}${getAllAttributes(currentElement.toLowerCase())}&gt`
  52. );
  53. } else {
  54. if (currentElement.nodeType === Node.TEXT_NODE)
  55. targetDocument.write(`"${currentElement.data}"`);
  56. else targetDocument.write("[unknown tag]");
  57. }
  58. // Traverse the tree
  59. var i = 0;
  60. var currentElementChild = currentElement.childNodes[i];
  61. while (currentElementChild) {
  62. // Formatting code (indent the tree so it looks nice on the screen)
  63. targetDocument.write(linefeed);
  64. for (j = 0; j < depth; j++) {
  65. targetDocument.write(verticalbar);
  66. }
  67. targetDocument.writeln(linefeed);
  68. for (j = 0; j < depth; j++) {
  69. targetDocument.write(verticalbar);
  70. }
  71. if (tagName) targetDocument.write(dash);
  72. // Recursively traverse the branches of the child node
  73. traverseDOMTree(targetDocument, currentElementChild, depth + 1);
  74. i++;
  75. currentElementChild = currentElement.childNodes[i];
  76. }
  77. // The remaining code is mostly for formatting the tree
  78. targetDocument.writeln(linefeed);
  79. for (j = 0; j < depth - 1; j++) {
  80. targetDocument.write(verticalbar);
  81. }
  82. targetDocument.write(space);
  83. if (tagName && tagName != "BR")
  84. targetDocument.write(`&lt;/${tagName.toLowerCase()}&gt;`);
  85. }
  86. }
  87. /**
  88. * Traverses the DOM tree starting at an element and returns the tree as a string.
  89. * This function is called recursively until the tree is fully traversed.
  90. *
  91. * @param {HTMLNode} currentElement root element.
  92. * @param {Number} depth the depth of the current element.
  93. * @return {String} DOM tree as a string.
  94. */
  95. function DOMTreeToString(currentElement, depth = 1) {
  96. if (currentElement) {
  97. var j;
  98. var tagName = currentElement.tagName;
  99. var domStr = "";
  100. // Prints the node tagName, such as <A>, <IMG>, etc
  101. if (tagName) {
  102. domStr += `&lt;${tagName.toLowerCase()}${getAllAttributes(
  103. currentElement
  104. )}&gt`;
  105. } else {
  106. if (currentElement.nodeType === Node.TEXT_NODE)
  107. domStr += `"${currentElement.data}"`;
  108. else domStr += "[unknown tag]";
  109. }
  110. // Traverse the tree
  111. var i = 0;
  112. var currentElementChild = currentElement.childNodes[i];
  113. while (currentElementChild) {
  114. // Formatting code (indent the tree so it looks nice on the screen)
  115. domStr += linefeed;
  116. for (j = 0; j < depth; j++) {
  117. domStr += verticalbar;
  118. }
  119. domStr += linefeed;
  120. for (j = 0; j < depth; j++) {
  121. domStr += verticalbar;
  122. }
  123. if (tagName) domStr += dash;
  124. // Recursively traverse the branches of the child node
  125. domStr += DOMTreeToString(currentElementChild, depth + 1);
  126. i++;
  127. currentElementChild = currentElement.childNodes[i];
  128. }
  129. // The remaining code is mostly for formatting the tree
  130. domStr += linefeed;
  131. for (j = 0; j < depth - 1; j++) {
  132. domStr += verticalbar;
  133. }
  134. domStr += space;
  135. if (tagName && tagName != "BR")
  136. domStr += `&lt;/${tagName.toLowerCase()}&gt;`;
  137. }
  138. return domStr;
  139. }
  140. /**
  141. * Acepts a DOM element as parameter and prints
  142. * out the DOM tree structure rooted at the element.
  143. *
  144. * @param {HTMLNode} domElement root element.
  145. * @param {Window} destinationWindow if not specified, the tree is printed in a new window.
  146. */
  147. function printDOMTree(domElement, destinationWindow) {
  148. // Use destination window to print the tree.
  149. var outputWindow = destinationWindow;
  150. if (!outputWindow)
  151. outputWindow = window.open(
  152. `${window.location.protocol}://${window.location.hostname}/`,
  153. "_blank"
  154. );
  155. // make a valid html page
  156. outputWindow.document.open("text/html", "replace");
  157. outputWindow.document.writeln(`<!DOCTYPE html>
  158. <html>
  159. <head>
  160. <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
  161. <title>DOM</title>
  162. </head>
  163. <body style="background-color:white;">
  164. <code>
  165. ${DOMTreeToString(domElement)}
  166. </code>
  167. </body>
  168. </html>
  169. `);
  170. // The document should be closed. Otherwise, Mozilla browsers might keep showing
  171. // "loading in progress".
  172. outputWindow.document.close();
  173. }