2012-03-07 20:21:32 +00:00
|
|
|
/**
|
|
|
|
* Creates an ve.dm.DocumentSynchronizer object.
|
|
|
|
*
|
2012-03-14 21:02:24 +00:00
|
|
|
* This object is a utility for collecting actions to be performed on the model tree
|
2012-03-07 20:21:32 +00:00
|
|
|
* in multiple steps and then processing those actions in a single step.
|
|
|
|
*
|
|
|
|
* @class
|
|
|
|
* @constructor
|
|
|
|
*/
|
2012-03-07 23:48:58 +00:00
|
|
|
ve.dm.DocumentSynchronizer = function( model ) {
|
2012-03-07 20:21:32 +00:00
|
|
|
// Properties
|
|
|
|
this.model = model;
|
|
|
|
this.actions = [];
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Methods */
|
|
|
|
|
2012-03-08 19:35:51 +00:00
|
|
|
ve.dm.DocumentSynchronizer.prototype.getModel = function() {
|
|
|
|
return this.model;
|
|
|
|
};
|
|
|
|
|
2012-03-07 20:21:32 +00:00
|
|
|
/**
|
2012-03-14 21:02:29 +00:00
|
|
|
* Add an insert action to the queue
|
|
|
|
* @param {ve.dm.BranchNode} node Node to insert
|
|
|
|
* @param {Integer} [offset] Offset of the inserted node, if known
|
|
|
|
*/
|
|
|
|
ve.dm.DocumentSynchronizer.prototype.pushInsert = function( node, offset ) {
|
|
|
|
this.actions.push( {
|
|
|
|
'type': 'insert',
|
|
|
|
'node': node,
|
|
|
|
'offset': offset || null
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a delete action to the queue
|
|
|
|
* @param {ve.dm.BranchNode} node Node to delete
|
|
|
|
*/
|
|
|
|
ve.dm.DocumentSynchronizer.prototype.pushDelete = function( node ) {
|
|
|
|
this.actions.push( {
|
|
|
|
'type': 'delete',
|
|
|
|
'node': node
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a rebuild action to the queue. This rebuilds a node from data
|
|
|
|
* found in the linear model.
|
|
|
|
* @param {ve.dm.BranchNode} node Node to rebuild
|
|
|
|
* @param {Integer} adjustment Length adjustment to apply to the node
|
|
|
|
* @param {Integer} offset Offset of the node, if known
|
|
|
|
*/
|
|
|
|
ve.dm.DocumentSynchronizer.prototype.pushRebuild = function( node, adjustment, offset ) {
|
|
|
|
this.actions.push( {
|
|
|
|
'type': 'rebuild',
|
|
|
|
'node': node,
|
|
|
|
'adjustment': adjustment,
|
|
|
|
'offset': offset || null
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a resize action to the queue. This changes the content length of a leaf node.
|
|
|
|
* @param {ve.dm.BranchNode} node Node to resize
|
|
|
|
* @param {Integer} adjustment Length adjustment to apply to the node
|
2012-03-07 20:21:32 +00:00
|
|
|
*/
|
2012-03-14 21:02:29 +00:00
|
|
|
ve.dm.DocumentSynchronizer.prototype.pushResize = function( node, adjustment ) {
|
2012-03-07 20:21:32 +00:00
|
|
|
this.actions.push( {
|
2012-03-14 21:02:29 +00:00
|
|
|
'type': 'resize',
|
2012-03-07 20:21:32 +00:00
|
|
|
'node': node,
|
2012-03-14 21:02:29 +00:00
|
|
|
'adjustment': adjustment
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add an update action to the queue
|
|
|
|
* @param {ve.dm.BranchNode} node Node to update
|
|
|
|
*/
|
|
|
|
ve.dm.DocumentSynchronizer.prototype.pushUpdate = function( node ) {
|
|
|
|
this.actions.push( {
|
|
|
|
'type': 'update',
|
|
|
|
'node': node
|
2012-03-07 20:21:32 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2012-03-14 21:02:29 +00:00
|
|
|
* Apply queued actions to the model tree. This assumes that the linear model
|
|
|
|
* has already been updated, but the model tree has not yet been.
|
2012-03-07 20:21:32 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
|
|
|
ve.dm.DocumentSynchronizer.prototype.synchronize = function() {
|
|
|
|
// TODO: Normalize the actions list to clean up nested actions
|
|
|
|
// Perform all actions
|
2012-03-14 21:02:27 +00:00
|
|
|
var action,
|
2012-03-07 20:21:32 +00:00
|
|
|
offset,
|
|
|
|
parent;
|
|
|
|
for ( var i = 0, len = this.actions.length; i < len; i++ ) {
|
|
|
|
action = this.actions[i];
|
2012-03-14 21:02:29 +00:00
|
|
|
offset = action.offset || null;
|
2012-03-07 20:21:32 +00:00
|
|
|
switch ( action.type ) {
|
|
|
|
case 'insert':
|
2012-03-14 21:02:26 +00:00
|
|
|
// Compute the offset if it wasn't provided
|
|
|
|
if ( offset === null ) {
|
|
|
|
offset = this.model.getOffsetFromNode( action.node );
|
|
|
|
}
|
2012-03-07 20:21:32 +00:00
|
|
|
// Insert the new node at the given offset
|
2012-03-08 00:52:30 +00:00
|
|
|
var target = this.model.getNodeFromOffset( offset + 1 );
|
2012-03-07 20:21:32 +00:00
|
|
|
if ( target === this.model ) {
|
|
|
|
// Insert at the beginning of the document
|
2012-03-08 00:52:30 +00:00
|
|
|
this.model.splice( 0, 0, action.node );
|
|
|
|
} else if ( target === null ) {
|
|
|
|
// Insert at the end of the document
|
|
|
|
this.model.splice( this.model.getElementLength(), 0, action.node );
|
2012-03-07 20:21:32 +00:00
|
|
|
} else {
|
|
|
|
// Insert before the element currently at the offset
|
|
|
|
parent = target.getParent();
|
|
|
|
parent.splice( parent.indexOf( target ), 0, action.node );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'delete':
|
|
|
|
// Replace original node with new node
|
|
|
|
parent = action.node.getParent();
|
2012-03-08 19:35:51 +00:00
|
|
|
parent.splice( parent.indexOf( action.node ), 1 );
|
2012-03-07 20:21:32 +00:00
|
|
|
break;
|
|
|
|
case 'rebuild':
|
2012-03-14 21:02:26 +00:00
|
|
|
// Compute the offset if it wasn't provided
|
|
|
|
if ( offset === null ) {
|
|
|
|
offset = this.model.getOffsetFromNode( action.node );
|
|
|
|
}
|
2012-03-07 20:21:32 +00:00
|
|
|
// Replace original node with new node
|
2012-03-08 19:35:51 +00:00
|
|
|
var newNodes = ve.dm.DocumentNode.createNodesFromData( this.model.getData(
|
2012-03-07 20:21:32 +00:00
|
|
|
new ve.Range( offset, action.node.getElementLength() + action.adjustment )
|
|
|
|
) );
|
|
|
|
parent = action.node.getParent();
|
2012-03-10 00:31:28 +00:00
|
|
|
ve.batchedSplice( parent, parent.indexOf( action.node ), 1, newNodes );
|
2012-03-07 20:21:32 +00:00
|
|
|
break;
|
|
|
|
case 'resize':
|
|
|
|
// Adjust node length - causes update events to be emitted
|
2012-03-08 00:52:30 +00:00
|
|
|
action.node.adjustContentLength( action.adjustment );
|
2012-03-07 20:21:32 +00:00
|
|
|
break;
|
|
|
|
case 'update':
|
|
|
|
// Emit update events
|
2012-03-08 00:52:30 +00:00
|
|
|
action.node.emit( 'update' );
|
2012-03-07 20:21:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-03-14 21:02:24 +00:00
|
|
|
|
|
|
|
// We've processed the queue, clear it
|
|
|
|
this.actions = [];
|
2012-03-07 20:21:32 +00:00
|
|
|
};
|