mediawiki-extensions-Visual.../modules/ve/dm/ve.dm.BranchNode.js
Catrope aa2836aa6e Remove 'internal' property from DM nodes
There's no use case for keeping a deep copy of the 'internal' property
in the node tree, and it was breaking some of my new tests concerning
change markers. We could keep internal data in the node tree if we
wanted to, but to be correct we'd have to synchronize every time we
changed it, which is a pain.

Change-Id: I024de1ff8b6b6154da82c103c4bb21db8ff2ec14
2012-10-24 16:47:14 -07: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} [attributes] Reference to map of attribute key/value pairs
*/
ve.dm.BranchNode = function VeDmBranchNode( type, children, attributes ) {
// Mixin constructor
ve.BranchNode.call( this );
// Parent constructor
ve.dm.Node.call( this, type, 0, attributes );
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;
};