%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/ |
| Current File : //www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/ve.BranchNode.js |
/*!
* VisualEditor BranchNode class.
*
* @copyright 2011-2016 VisualEditor Team and others; see http://ve.mit-license.org
*/
/**
* Branch node mixin.
*
* Extenders are expected to inherit from ve.Node.
*
* Branch nodes are immutable, which is why there are no methods for adding or removing children.
* DataModel classes will add this functionality, and other subclasses will implement behavior that
* mimics changes made to DataModel nodes.
*
* @class
* @abstract
* @constructor
* @param {ve.Node[]} children Array of children to add
*/
ve.BranchNode = function VeBranchNode( children ) {
this.children = Array.isArray( children ) ? children : [];
};
/* Setup */
OO.initClass( ve.BranchNode );
/* Methods */
/**
* Traverse a branch node depth-first.
*
* @param {Function} callback Callback to execute for each traversed node
* @param {ve.Node} callback.node Node being traversed
*/
ve.BranchNode.prototype.traverse = function ( callback ) {
var i, len,
children = this.getChildren();
for ( i = 0, len = children.length; i < len; i++ ) {
callback.call( this, children[ i ] );
if ( children[ i ].hasChildren() ) {
children[ i ].traverse( callback );
}
}
};
/**
* Check if the node has children.
*
* @method
* @return {boolean} Whether the node has children
*/
ve.BranchNode.prototype.hasChildren = function () {
return true;
};
/**
* Get child nodes.
*
* @method
* @return {ve.Node[]} List of child nodes
*/
ve.BranchNode.prototype.getChildren = function () {
return this.children;
};
/**
* Get the index of a child node.
*
* @method
* @param {ve.dm.Node} node Child node to find index of
* @return {number} Index of child node or -1 if node was not found
*/
ve.BranchNode.prototype.indexOf = function ( node ) {
return this.children.indexOf( node );
};
/**
* Set the root node.
*
* @method
* @see ve.Node#setRoot
* @param {ve.Node} root Node to use as root
*/
ve.BranchNode.prototype.setRoot = function ( root ) {
var i;
if ( root === this.root ) {
// Nothing to do, don't recurse into all descendants
return;
}
this.root = root;
for ( i = 0; i < this.children.length; i++ ) {
this.children[ i ].setRoot( root );
}
};
/**
* Set the document the node is a part of.
*
* @method
* @see ve.Node#setDocument
* @param {ve.Document} doc Document this node is a part of
*/
ve.BranchNode.prototype.setDocument = function ( doc ) {
var i;
if ( doc === this.doc ) {
// Nothing to do, don't recurse into all descendants
return;
}
this.doc = doc;
for ( i = 0; i < this.children.length; i++ ) {
this.children[ i ].setDocument( doc );
}
};
/**
* Get a node from an offset.
*
* This method is pretty expensive. If you need to get different slices of the same content, get
* the content first, then slice it up locally.
*
* @method
* @param {number} offset Offset get node for
* @param {boolean} [shallow] Do not iterate into child nodes of child nodes
* @return {ve.Node|null} Node at offset, or null if none was found
*/
ve.BranchNode.prototype.getNodeFromOffset = function ( offset, shallow ) {
var i, length, nodeLength, childNode,
currentNode = this,
nodeOffset = 0;
if ( offset === 0 ) {
return currentNode;
}
// TODO a lot of logic is duplicated in selectNodes(), abstract that into a traverser or something
SIBLINGS:
while ( currentNode.children.length ) {
for ( i = 0, length = currentNode.children.length; i < length; i++ ) {
childNode = currentNode.children[ i ];
if ( childNode instanceof ve.ce.InternalListNode ) {
break;
}
if ( offset === nodeOffset ) {
// The requested offset is right before childNode, so it's not
// inside any of currentNode's children, but is inside currentNode
return currentNode;
}
nodeLength = childNode.getOuterLength();
if ( offset >= nodeOffset && offset < nodeOffset + nodeLength ) {
if ( !shallow && childNode.hasChildren() && childNode.getChildren().length ) {
// One of the children contains the node; increment to
// enter the node, then iterate through children
nodeOffset += 1;
currentNode = childNode;
continue SIBLINGS;
} else {
return childNode;
}
}
nodeOffset += nodeLength;
}
if ( offset === nodeOffset ) {
// The requested offset is right before currentNode.children[i], so it's
// not inside any of currentNode's children, but is inside currentNode
return currentNode;
}
}
return null;
};