120 lines
4.4 KiB
JavaScript
120 lines
4.4 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
var Node = require('./Node');
|
||
|
var LinkedList = require('./LinkedList');
|
||
|
|
||
|
var createDocumentFragmentFromArguments = function(document, args) {
|
||
|
var docFrag = document.createDocumentFragment();
|
||
|
|
||
|
for (var i=0; i<args.length; i++) {
|
||
|
var argItem = args[i];
|
||
|
var isNode = argItem instanceof Node;
|
||
|
docFrag.appendChild(isNode ? argItem :
|
||
|
document.createTextNode(String(argItem)));
|
||
|
}
|
||
|
|
||
|
return docFrag;
|
||
|
};
|
||
|
|
||
|
// The ChildNode interface contains methods that are particular to `Node`
|
||
|
// objects that can have a parent. It is implemented by `Element`,
|
||
|
// `DocumentType`, and `CharacterData` objects.
|
||
|
var ChildNode = {
|
||
|
|
||
|
// Inserts a set of Node or String objects in the children list of this
|
||
|
// ChildNode's parent, just after this ChildNode. String objects are
|
||
|
// inserted as the equivalent Text nodes.
|
||
|
after: { value: function after() {
|
||
|
var argArr = Array.prototype.slice.call(arguments);
|
||
|
var parentNode = this.parentNode, nextSibling = this.nextSibling;
|
||
|
if (parentNode === null) { return; }
|
||
|
// Find "viable next sibling"; that is, next one not in argArr
|
||
|
while (nextSibling && argArr.some(function(v) { return v===nextSibling; }))
|
||
|
nextSibling = nextSibling.nextSibling;
|
||
|
// ok, parent and sibling are saved away since this node could itself
|
||
|
// appear in argArr and we're about to move argArr to a document fragment.
|
||
|
var docFrag = createDocumentFragmentFromArguments(this.doc, argArr);
|
||
|
|
||
|
parentNode.insertBefore(docFrag, nextSibling);
|
||
|
}},
|
||
|
|
||
|
// Inserts a set of Node or String objects in the children list of this
|
||
|
// ChildNode's parent, just before this ChildNode. String objects are
|
||
|
// inserted as the equivalent Text nodes.
|
||
|
before: { value: function before() {
|
||
|
var argArr = Array.prototype.slice.call(arguments);
|
||
|
var parentNode = this.parentNode, prevSibling = this.previousSibling;
|
||
|
if (parentNode === null) { return; }
|
||
|
// Find "viable prev sibling"; that is, prev one not in argArr
|
||
|
while (prevSibling && argArr.some(function(v) { return v===prevSibling; }))
|
||
|
prevSibling = prevSibling.previousSibling;
|
||
|
// ok, parent and sibling are saved away since this node could itself
|
||
|
// appear in argArr and we're about to move argArr to a document fragment.
|
||
|
var docFrag = createDocumentFragmentFromArguments(this.doc, argArr);
|
||
|
|
||
|
var nextSibling =
|
||
|
prevSibling ? prevSibling.nextSibling : parentNode.firstChild;
|
||
|
parentNode.insertBefore(docFrag, nextSibling);
|
||
|
}},
|
||
|
|
||
|
// Remove this node from its parent
|
||
|
remove: { value: function remove() {
|
||
|
if (this.parentNode === null) return;
|
||
|
|
||
|
// Send mutation events if necessary
|
||
|
if (this.doc) {
|
||
|
this.doc._preremoveNodeIterators(this);
|
||
|
if (this.rooted) {
|
||
|
this.doc.mutateRemove(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove this node from its parents array of children
|
||
|
// and update the structure id for all ancestors
|
||
|
this._remove();
|
||
|
|
||
|
// Forget this node's parent
|
||
|
this.parentNode = null;
|
||
|
}},
|
||
|
|
||
|
// Remove this node w/o uprooting or sending mutation events
|
||
|
// (But do update the structure id for all ancestors)
|
||
|
_remove: { value: function _remove() {
|
||
|
var parent = this.parentNode;
|
||
|
if (parent === null) return;
|
||
|
if (parent._childNodes) {
|
||
|
parent._childNodes.splice(this.index, 1);
|
||
|
} else if (parent._firstChild === this) {
|
||
|
if (this._nextSibling === this) {
|
||
|
parent._firstChild = null;
|
||
|
} else {
|
||
|
parent._firstChild = this._nextSibling;
|
||
|
}
|
||
|
}
|
||
|
LinkedList.remove(this);
|
||
|
parent.modify();
|
||
|
}},
|
||
|
|
||
|
// Replace this node with the nodes or strings provided as arguments.
|
||
|
replaceWith: { value: function replaceWith() {
|
||
|
var argArr = Array.prototype.slice.call(arguments);
|
||
|
var parentNode = this.parentNode, nextSibling = this.nextSibling;
|
||
|
if (parentNode === null) { return; }
|
||
|
// Find "viable next sibling"; that is, next one not in argArr
|
||
|
while (nextSibling && argArr.some(function(v) { return v===nextSibling; }))
|
||
|
nextSibling = nextSibling.nextSibling;
|
||
|
// ok, parent and sibling are saved away since this node could itself
|
||
|
// appear in argArr and we're about to move argArr to a document fragment.
|
||
|
var docFrag = createDocumentFragmentFromArguments(this.doc, argArr);
|
||
|
if (this.parentNode === parentNode) {
|
||
|
parentNode.replaceChild(docFrag, this);
|
||
|
} else {
|
||
|
// `this` was inserted into docFrag
|
||
|
parentNode.insertBefore(docFrag, nextSibling);
|
||
|
}
|
||
|
}},
|
||
|
|
||
|
};
|
||
|
|
||
|
module.exports = ChildNode;
|