mediawiki-extensions-Visual.../modules/ve/dm/ve.dm.BranchNode.js
Catrope 49963c75fd Store the data model element in the DM tree
This is cleaner than passing around the attributes separately, and it
allows us to access the annotations in dm.LeafNode as well.

Change-Id: Ie5b90988114835831cbe5cdccf63c7cd45719e31
2012-11-27 14:36:29 -08:00

134 lines
3.3 KiB
JavaScript

/**
* VisualEditor data model BranchNode class.
*
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* DataModel node that can have branch or leaf children.
*
* @class
* @abstract
* @constructor
* @extends {ve.dm.Node}
* @param {String} type Symbolic name of node type
* @param {ve.dm.Node[]} [children] Child nodes to attach
* @param {Object} [element] Reference to element in linear model
*/
ve.dm.BranchNode = function VeDmBranchNode( type, children, element ) {
// Mixin constructor
ve.BranchNode.call( this );
// Parent constructor
ve.dm.Node.call( this, type, 0, element );
if ( ve.isArray( children ) && children.length ) {
this.splice.apply( this, [0, 0].concat( children ) );
}
};
/* Inheritance */
ve.inheritClass( ve.dm.BranchNode, ve.dm.Node );
ve.mixinClass( ve.dm.BranchNode, ve.BranchNode );
/* Methods */
/**
* Adds a node to the end of this node's children.
*
* @method
* @param {ve.dm.BranchNode} childModel Item to add
* @returns {Number} New number of children
* @emits splice (index, 0, [childModel])
* @emits update
*/
ve.dm.BranchNode.prototype.push = function ( childModel ) {
this.splice( this.children.length, 0, childModel );
return this.children.length;
};
/**
* Removes a node from the end of this node's children
*
* @method
* @returns {ve.dm.BranchNode} Removed childModel
* @emits splice (index, 1, [])
* @emits update
*/
ve.dm.BranchNode.prototype.pop = function () {
if ( this.children.length ) {
var childModel = this.children[this.children.length - 1];
this.splice( this.children.length - 1, 1 );
return childModel;
}
};
/**
* Adds a node to the beginning of this node's children.
*
* @method
* @param {ve.dm.BranchNode} childModel Item to add
* @returns {Number} New number of children
* @emits splice (0, 0, [childModel])
* @emits update
*/
ve.dm.BranchNode.prototype.unshift = function ( childModel ) {
this.splice( 0, 0, childModel );
return this.children.length;
};
/**
* Removes a node from the beginning of this node's children
*
* @method
* @returns {ve.dm.BranchNode} Removed childModel
* @emits splice (0, 1, [])
* @emits update
*/
ve.dm.BranchNode.prototype.shift = function () {
if ( this.children.length ) {
var childModel = this.children[0];
this.splice( 0, 1 );
return childModel;
}
};
/**
* Adds and removes nodes from this node's children.
*
* @method
* @param {Number} index Index to remove and or insert nodes at
* @param {Number} howmany Number of nodes to remove
* @param {ve.dm.BranchNode} [...] Variadic list of nodes to insert
* @returns {ve.dm.BranchNode[]} Removed nodes
* @emits splice (index, howmany, [...])
*/
ve.dm.BranchNode.prototype.splice = function () {
var i,
length,
removals,
args = Array.prototype.slice.call( arguments ),
diff = 0;
if ( args.length >= 3 ) {
length = args.length;
for ( i = 2; i < length; i++ ) {
args[i].attach( this );
diff += args[i].getOuterLength();
}
}
removals = this.children.splice.apply( this.children, args );
for ( i = 0, length = removals.length; i < length; i++ ) {
removals[i].detach();
diff -= removals[i].getOuterLength();
}
this.adjustLength( diff, true );
this.emit.apply( this, ['splice'].concat( args ) );
return removals;
};