UNPKG

sub

Version:

A subset of the DOM environment for running Rule.js on the server

207 lines (192 loc) 6.36 kB
"use strict"; var DOMException = require('./DOMException').DOMException; var createDOMException = require('./DOMException').createDOMException; /* * Node */ var Node, initializeNode; Node = (function () { // Contants Node.ELEMENT_NODE = 1; Node.ATTRIBUTE_NODE = 2; Node.TEXT_NODE = 3; Node.CDATA_SECTION_NODE = 4; Node.ENTITY_REFERENCE_NODE = 5; Node.ENTITY_NODE = 6; Node.PROCESSING_INSTRUCTION_NODE = 7; Node.DOCUMENT_NODE = 9; Node.COMMENT_NODE = 8; Node.DOCUMENT_TYPE_NODE = 10; Node.DOCUMENT_FRAGMENT_NODE = 11; Node.NOTATION_NODE = 12; Node.DOCUMENT_POSITION_DISCONNECTED = 1; Node.DOCUMENT_POSITION_PRECEDING = 2; Node.DOCUMENT_POSITION_FOLLOWING = 4; Node.DOCUMENT_POSITION_CONTAINS = 8; Node.DOCUMENT_POSITION_CONTAINED_BY = 16; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 32; //Prototype // These properties within defineProperties should not be in the element // prototype, this is a speed optimization, as the call to defineProperties // is expensive when called on every element initialization. // On the actual DOM, these properties belong to the object itself, // not the prototype. Object.defineProperties(Node.prototype, { 'parentElement': { configurable: true, get: function () { return this.parentNode; } }, 'firstChild': { configurable: true, get: function () { return this.childNodes[0] || null; } }, 'lastChild': { configurable: true, get: function () { return this.childNodes[this.childNodes.length - 1] || null; } }, 'nextSibling': { configurable: true, get: function () { var index, sibling; if (this.parentNode) { index = this.parentNode.childNodes.indexOf(this); sibling = this.parentNode.childNodes[index + 1]; } return sibling || null; } }, 'previousSibling': { configurable: true, get: function () { var index, sibling; if (this.parentNode) { index = this.parentNode.childNodes.indexOf(this); sibling = this.parentNode.childNodes[index - 1]; } return sibling || null; } } }); // cloneNode is set up to load in dependencies once, and then replace itself // with the closure function. This is so the dependencies do not need to be // loaded repeatedly, they cannot be taken out of the function, or it will // cause a dependency loop. Node.prototype.cloneNode = function () { var createHTMLElement = require('./HTMLElement').createHTMLElement; var createText = require('./Text').createText; Node.prototype.cloneNode = function (deep) { var newNode; var index; if (deep === null || deep === undefined) { deep = true; } if (this.nodeType === 1 || this.nodeType === 10 || this.nodeType === 11) { newNode = createHTMLElement(this.tagName); for (index = 0; index < this.attributes.length; index++) { newNode.attributes[index] = { name: this.attributes[index].name, value: this.attributes[index].value }; } } if (this.nodeType === 3) { newNode = createText(this.data); } if (deep === true) { for (index = 0; index < this.childNodes.length; index++) { newNode.insertBefore(this.childNodes[index].cloneNode(true)); } } return newNode; }; return Node.prototype.cloneNode.apply(this, arguments); }; Node.prototype.contains = function (element) { var index, child; for (index = 0; index < this.childNodes.length; index++) { child = this.childNodes[index]; if (child === element || child.contains(element)) { return true; } } return false; }; Node.prototype.hasChildNodes = function () { return this.childNodes.length > 0; }; Node.prototype.normalize = function () { var index, child; for (index = 0; index < this.childNodes.length; index++) { child = this.childNodes[index]; child.normalize(); if (child.nodeType === Node.TEXT_NODE) { if (child.data === '') { child.parentNode.removeChild(child); } else if (child.nextSibling.nodeType === Node.TEXT_NODE) { child.appendData(child.nextSibling.data); this.removeChild(child.nextSibling); } } } }; Node.prototype.insertBefore = function (newElement, referenceElement) { var index; if (!(newElement instanceof Node)) { throw createDOMException(DOMException.NOT_FOUND_ERR); } if (referenceElement instanceof Node) { index = this.childNodes.indexOf(referenceElement); if (index === -1) { throw createDOMException(DOMException.NOT_FOUND_ERR); } } // If already inserted, remove from where it was if (newElement.parentNode) { newElement.parentNode.removeChild(newElement); } newElement.parentNode = this; // We need to reindex in case the parent element was this element // Index is by default the last node. index = this.childNodes.length; if (referenceElement !== null && referenceElement !== undefined) { index = this.childNodes.indexOf(referenceElement); } this.childNodes.splice(index, 0, newElement); return newElement; }; Node.prototype.appendChild = function (newElement) { return this.insertBefore(newElement); }; Node.prototype.removeChild = function (childElement) { var index = this.childNodes.indexOf(childElement); if (index === -1) { throw createDOMException(DOMException.NOT_FOUND_ERR); } this.childNodes.splice(index, 1); // We still have to set parent to null in case it's reused. childElement.parentNode = null; return childElement; }; Node.prototype.replaceChild = function (newElement, oldElement) { if (newElement instanceof Node || oldElement instanceof Node) { this.insertBefore(newElement, oldElement); this.removeChild(oldElement); } return oldElement; }; //Constructor function Node() { throw new TypeError('Illegal constructor'); } return Node; }()); initializeNode = function () { this.parentNode = null; this.childNodes = []; }; exports.Node = Node; exports.initializeNode = initializeNode;