You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
5.1 KiB

  1. 'use strict';
  2. const { DOCUMENT_MODE } = require('../common/html');
  3. //Node construction
  4. exports.createDocument = function() {
  5. return {
  6. nodeName: '#document',
  7. mode: DOCUMENT_MODE.NO_QUIRKS,
  8. childNodes: []
  9. };
  10. };
  11. exports.createDocumentFragment = function() {
  12. return {
  13. nodeName: '#document-fragment',
  14. childNodes: []
  15. };
  16. };
  17. exports.createElement = function(tagName, namespaceURI, attrs) {
  18. return {
  19. nodeName: tagName,
  20. tagName: tagName,
  21. attrs: attrs,
  22. namespaceURI: namespaceURI,
  23. childNodes: [],
  24. parentNode: null
  25. };
  26. };
  27. exports.createCommentNode = function(data) {
  28. return {
  29. nodeName: '#comment',
  30. data: data,
  31. parentNode: null
  32. };
  33. };
  34. const createTextNode = function(value) {
  35. return {
  36. nodeName: '#text',
  37. value: value,
  38. parentNode: null
  39. };
  40. };
  41. //Tree mutation
  42. const appendChild = (exports.appendChild = function(parentNode, newNode) {
  43. parentNode.childNodes.push(newNode);
  44. newNode.parentNode = parentNode;
  45. });
  46. const insertBefore = (exports.insertBefore = function(parentNode, newNode, referenceNode) {
  47. const insertionIdx = parentNode.childNodes.indexOf(referenceNode);
  48. parentNode.childNodes.splice(insertionIdx, 0, newNode);
  49. newNode.parentNode = parentNode;
  50. });
  51. exports.setTemplateContent = function(templateElement, contentElement) {
  52. templateElement.content = contentElement;
  53. };
  54. exports.getTemplateContent = function(templateElement) {
  55. return templateElement.content;
  56. };
  57. exports.setDocumentType = function(document, name, publicId, systemId) {
  58. let doctypeNode = null;
  59. for (let i = 0; i < document.childNodes.length; i++) {
  60. if (document.childNodes[i].nodeName === '#documentType') {
  61. doctypeNode = document.childNodes[i];
  62. break;
  63. }
  64. }
  65. if (doctypeNode) {
  66. doctypeNode.name = name;
  67. doctypeNode.publicId = publicId;
  68. doctypeNode.systemId = systemId;
  69. } else {
  70. appendChild(document, {
  71. nodeName: '#documentType',
  72. name: name,
  73. publicId: publicId,
  74. systemId: systemId
  75. });
  76. }
  77. };
  78. exports.setDocumentMode = function(document, mode) {
  79. document.mode = mode;
  80. };
  81. exports.getDocumentMode = function(document) {
  82. return document.mode;
  83. };
  84. exports.detachNode = function(node) {
  85. if (node.parentNode) {
  86. const idx = node.parentNode.childNodes.indexOf(node);
  87. node.parentNode.childNodes.splice(idx, 1);
  88. node.parentNode = null;
  89. }
  90. };
  91. exports.insertText = function(parentNode, text) {
  92. if (parentNode.childNodes.length) {
  93. const prevNode = parentNode.childNodes[parentNode.childNodes.length - 1];
  94. if (prevNode.nodeName === '#text') {
  95. prevNode.value += text;
  96. return;
  97. }
  98. }
  99. appendChild(parentNode, createTextNode(text));
  100. };
  101. exports.insertTextBefore = function(parentNode, text, referenceNode) {
  102. const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1];
  103. if (prevNode && prevNode.nodeName === '#text') {
  104. prevNode.value += text;
  105. } else {
  106. insertBefore(parentNode, createTextNode(text), referenceNode);
  107. }
  108. };
  109. exports.adoptAttributes = function(recipient, attrs) {
  110. const recipientAttrsMap = [];
  111. for (let i = 0; i < recipient.attrs.length; i++) {
  112. recipientAttrsMap.push(recipient.attrs[i].name);
  113. }
  114. for (let j = 0; j < attrs.length; j++) {
  115. if (recipientAttrsMap.indexOf(attrs[j].name) === -1) {
  116. recipient.attrs.push(attrs[j]);
  117. }
  118. }
  119. };
  120. //Tree traversing
  121. exports.getFirstChild = function(node) {
  122. return node.childNodes[0];
  123. };
  124. exports.getChildNodes = function(node) {
  125. return node.childNodes;
  126. };
  127. exports.getParentNode = function(node) {
  128. return node.parentNode;
  129. };
  130. exports.getAttrList = function(element) {
  131. return element.attrs;
  132. };
  133. //Node data
  134. exports.getTagName = function(element) {
  135. return element.tagName;
  136. };
  137. exports.getNamespaceURI = function(element) {
  138. return element.namespaceURI;
  139. };
  140. exports.getTextNodeContent = function(textNode) {
  141. return textNode.value;
  142. };
  143. exports.getCommentNodeContent = function(commentNode) {
  144. return commentNode.data;
  145. };
  146. exports.getDocumentTypeNodeName = function(doctypeNode) {
  147. return doctypeNode.name;
  148. };
  149. exports.getDocumentTypeNodePublicId = function(doctypeNode) {
  150. return doctypeNode.publicId;
  151. };
  152. exports.getDocumentTypeNodeSystemId = function(doctypeNode) {
  153. return doctypeNode.systemId;
  154. };
  155. //Node types
  156. exports.isTextNode = function(node) {
  157. return node.nodeName === '#text';
  158. };
  159. exports.isCommentNode = function(node) {
  160. return node.nodeName === '#comment';
  161. };
  162. exports.isDocumentTypeNode = function(node) {
  163. return node.nodeName === '#documentType';
  164. };
  165. exports.isElementNode = function(node) {
  166. return !!node.tagName;
  167. };
  168. // Source code location
  169. exports.setNodeSourceCodeLocation = function(node, location) {
  170. node.sourceCodeLocation = location;
  171. };
  172. exports.getNodeSourceCodeLocation = function(node) {
  173. return node.sourceCodeLocation;
  174. };