mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-29 00:30:44 +00:00
aa2836aa6e
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
134 lines
3.3 KiB
JavaScript
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;
|
|
};
|