Support splitting nodes in replace tree sync

This means inserting things like </p><p> are now synced correctly and
split the paragraph in the model tree. Merges (removing e.g. </p><p>)
aren't supported yet.

Also, this needs tests, Trevor tells me he's working on porting replace
tests from the old ve/ directory

Change-Id: Ic5050849d7d007a1696dc36548654979aedb53a8
This commit is contained in:
Catrope 2012-05-14 21:46:39 -07:00
parent 59f74de3b8
commit 7e1aa2336e
2 changed files with 29 additions and 6 deletions

View file

@ -197,6 +197,9 @@ ve.dm.Document.containsElementData = function( data ) {
* @returns {ve.Node} Lowest level parent node being affected * @returns {ve.Node} Lowest level parent node being affected
*/ */
ve.dm.Document.getScope = function( node, data ) { ve.dm.Document.getScope = function( node, data ) {
// TODO improve this to return a set of siblings, rather than a common ancestor, that'll
// make for much more efficient rebuilds
// TODO also make it track offsets
var i, var i,
length, length,
level = 0, level = 0,

View file

@ -254,7 +254,7 @@ ve.dm.TransactionProcessor.prototype.replace = function( op ) {
insert = this.reversed ? op.remove : op.insert, insert = this.reversed ? op.remove : op.insert,
removeHasStructure = ve.dm.Document.containsElementData( remove ), removeHasStructure = ve.dm.Document.containsElementData( remove ),
insertHasStructure = ve.dm.Document.containsElementData( insert ), insertHasStructure = ve.dm.Document.containsElementData( insert ),
node, selection; node, scope, selection;
// Figure out if this is a structural insert or a content insert // Figure out if this is a structural insert or a content insert
if ( !removeHasStructure && !insertHasStructure ) { if ( !removeHasStructure && !insertHasStructure ) {
// Content replacement // Content replacement
@ -272,8 +272,7 @@ ve.dm.TransactionProcessor.prototype.replace = function( op ) {
// Advance the cursor // Advance the cursor
this.cursor += insert.length; this.cursor += insert.length;
} else { } else {
// Structural insert // Structural replacement
// TODO generalize for insert/remove
// It's possible that multiple replace operations are needed before the // It's possible that multiple replace operations are needed before the
// model is back in a consistent state. This loop applies the current // model is back in a consistent state. This loop applies the current
@ -342,8 +341,29 @@ ve.dm.TransactionProcessor.prototype.replace = function( op ) {
throw 'Unbalanced set of replace operations found'; throw 'Unbalanced set of replace operations found';
} }
} }
// Queue a rebuild for the replaced node
this.synchronizer.pushRebuild( new ve.Range( startOffset, this.cursor - adjustment ), // TODO this handles splitting nodes but not merging nodes
new ve.Range( startOffset, this.cursor ) ); // Figure out in which node the start was
selection = this.document.selectNodes( new ve.Range( startOffset, startOffset ) );
node = selection[0].node;
// Figure out what the scope of the insertion is
scope = ve.dm.Document.getScope( node, op.insert );
if ( scope === node ) {
// Simple case: no splits occurred, we can just rebuild the affected range
this.synchronizer.pushRebuild(
new ve.Range( startOffset, this.cursor - adjustment ),
new ve.Range( startOffset, this.cursor )
);
} else {
// A split occurred. Rebuild the entirety of scope
// TODO do something better to get the offset, possibly via getScope()
// or through whatever we have to do for deletion painting
var scopeStart = this.document.getDocumentNode().getOffsetFromNode( scope );
var scopeEnd = scopeStart + scope.getOuterLength();
this.synchronizer.pushRebuild(
new ve.Range( scopeStart, scopeEnd ),
new ve.Range( scopeStart, scopeEnd + adjustment )
);
}
} }
}; };