| 'use strict'; | 
|   | 
| const { DOCUMENT_MODE } = require('../common/html'); | 
|   | 
| //Node construction | 
| exports.createDocument = function() { | 
|     return { | 
|         nodeName: '#document', | 
|         mode: DOCUMENT_MODE.NO_QUIRKS, | 
|         childNodes: [] | 
|     }; | 
| }; | 
|   | 
| exports.createDocumentFragment = function() { | 
|     return { | 
|         nodeName: '#document-fragment', | 
|         childNodes: [] | 
|     }; | 
| }; | 
|   | 
| exports.createElement = function(tagName, namespaceURI, attrs) { | 
|     return { | 
|         nodeName: tagName, | 
|         tagName: tagName, | 
|         attrs: attrs, | 
|         namespaceURI: namespaceURI, | 
|         childNodes: [], | 
|         parentNode: null | 
|     }; | 
| }; | 
|   | 
| exports.createCommentNode = function(data) { | 
|     return { | 
|         nodeName: '#comment', | 
|         data: data, | 
|         parentNode: null | 
|     }; | 
| }; | 
|   | 
| const createTextNode = function(value) { | 
|     return { | 
|         nodeName: '#text', | 
|         value: value, | 
|         parentNode: null | 
|     }; | 
| }; | 
|   | 
| //Tree mutation | 
| const appendChild = (exports.appendChild = function(parentNode, newNode) { | 
|     parentNode.childNodes.push(newNode); | 
|     newNode.parentNode = parentNode; | 
| }); | 
|   | 
| const insertBefore = (exports.insertBefore = function(parentNode, newNode, referenceNode) { | 
|     const insertionIdx = parentNode.childNodes.indexOf(referenceNode); | 
|   | 
|     parentNode.childNodes.splice(insertionIdx, 0, newNode); | 
|     newNode.parentNode = parentNode; | 
| }); | 
|   | 
| exports.setTemplateContent = function(templateElement, contentElement) { | 
|     templateElement.content = contentElement; | 
| }; | 
|   | 
| exports.getTemplateContent = function(templateElement) { | 
|     return templateElement.content; | 
| }; | 
|   | 
| exports.setDocumentType = function(document, name, publicId, systemId) { | 
|     let doctypeNode = null; | 
|   | 
|     for (let i = 0; i < document.childNodes.length; i++) { | 
|         if (document.childNodes[i].nodeName === '#documentType') { | 
|             doctypeNode = document.childNodes[i]; | 
|             break; | 
|         } | 
|     } | 
|   | 
|     if (doctypeNode) { | 
|         doctypeNode.name = name; | 
|         doctypeNode.publicId = publicId; | 
|         doctypeNode.systemId = systemId; | 
|     } else { | 
|         appendChild(document, { | 
|             nodeName: '#documentType', | 
|             name: name, | 
|             publicId: publicId, | 
|             systemId: systemId | 
|         }); | 
|     } | 
| }; | 
|   | 
| exports.setDocumentMode = function(document, mode) { | 
|     document.mode = mode; | 
| }; | 
|   | 
| exports.getDocumentMode = function(document) { | 
|     return document.mode; | 
| }; | 
|   | 
| exports.detachNode = function(node) { | 
|     if (node.parentNode) { | 
|         const idx = node.parentNode.childNodes.indexOf(node); | 
|   | 
|         node.parentNode.childNodes.splice(idx, 1); | 
|         node.parentNode = null; | 
|     } | 
| }; | 
|   | 
| exports.insertText = function(parentNode, text) { | 
|     if (parentNode.childNodes.length) { | 
|         const prevNode = parentNode.childNodes[parentNode.childNodes.length - 1]; | 
|   | 
|         if (prevNode.nodeName === '#text') { | 
|             prevNode.value += text; | 
|             return; | 
|         } | 
|     } | 
|   | 
|     appendChild(parentNode, createTextNode(text)); | 
| }; | 
|   | 
| exports.insertTextBefore = function(parentNode, text, referenceNode) { | 
|     const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1]; | 
|   | 
|     if (prevNode && prevNode.nodeName === '#text') { | 
|         prevNode.value += text; | 
|     } else { | 
|         insertBefore(parentNode, createTextNode(text), referenceNode); | 
|     } | 
| }; | 
|   | 
| exports.adoptAttributes = function(recipient, attrs) { | 
|     const recipientAttrsMap = []; | 
|   | 
|     for (let i = 0; i < recipient.attrs.length; i++) { | 
|         recipientAttrsMap.push(recipient.attrs[i].name); | 
|     } | 
|   | 
|     for (let j = 0; j < attrs.length; j++) { | 
|         if (recipientAttrsMap.indexOf(attrs[j].name) === -1) { | 
|             recipient.attrs.push(attrs[j]); | 
|         } | 
|     } | 
| }; | 
|   | 
| //Tree traversing | 
| exports.getFirstChild = function(node) { | 
|     return node.childNodes[0]; | 
| }; | 
|   | 
| exports.getChildNodes = function(node) { | 
|     return node.childNodes; | 
| }; | 
|   | 
| exports.getParentNode = function(node) { | 
|     return node.parentNode; | 
| }; | 
|   | 
| exports.getAttrList = function(element) { | 
|     return element.attrs; | 
| }; | 
|   | 
| //Node data | 
| exports.getTagName = function(element) { | 
|     return element.tagName; | 
| }; | 
|   | 
| exports.getNamespaceURI = function(element) { | 
|     return element.namespaceURI; | 
| }; | 
|   | 
| exports.getTextNodeContent = function(textNode) { | 
|     return textNode.value; | 
| }; | 
|   | 
| exports.getCommentNodeContent = function(commentNode) { | 
|     return commentNode.data; | 
| }; | 
|   | 
| exports.getDocumentTypeNodeName = function(doctypeNode) { | 
|     return doctypeNode.name; | 
| }; | 
|   | 
| exports.getDocumentTypeNodePublicId = function(doctypeNode) { | 
|     return doctypeNode.publicId; | 
| }; | 
|   | 
| exports.getDocumentTypeNodeSystemId = function(doctypeNode) { | 
|     return doctypeNode.systemId; | 
| }; | 
|   | 
| //Node types | 
| exports.isTextNode = function(node) { | 
|     return node.nodeName === '#text'; | 
| }; | 
|   | 
| exports.isCommentNode = function(node) { | 
|     return node.nodeName === '#comment'; | 
| }; | 
|   | 
| exports.isDocumentTypeNode = function(node) { | 
|     return node.nodeName === '#documentType'; | 
| }; | 
|   | 
| exports.isElementNode = function(node) { | 
|     return !!node.tagName; | 
| }; | 
|   | 
| // Source code location | 
| exports.setNodeSourceCodeLocation = function(node, location) { | 
|     node.sourceCodeLocation = location; | 
| }; | 
|   | 
| exports.getNodeSourceCodeLocation = function(node) { | 
|     return node.sourceCodeLocation; | 
| }; |