Transactions: Add trailing retainMetadata when there is trailing metadata.

Ensure that all transactions move the cursor past the trailing
metadata, if present.

Change-Id: I869c75f8cfabe1e14bb66d8e627d0b750bde46af
This commit is contained in:
C. Scott Ananian 2013-09-10 11:49:31 -07:00
parent 71df5562e4
commit 3928ca16fd
2 changed files with 43 additions and 23 deletions

View file

@ -30,8 +30,7 @@ ve.dm.Transaction = function VeDmTransaction() {
* @returns {ve.dm.Transaction} Transaction that inserts data
*/
ve.dm.Transaction.newFromInsertion = function ( doc, offset, insertion ) {
var tx = new ve.dm.Transaction(),
data = doc.data;
var tx = new ve.dm.Transaction();
// Fix up the insertion
insertion = doc.fixupInsertion( insertion, offset );
// Retain up to insertion point, if needed
@ -39,7 +38,7 @@ ve.dm.Transaction.newFromInsertion = function ( doc, offset, insertion ) {
// Insert data
tx.pushReplace( doc, insertion.offset, insertion.remove, insertion.data );
// Retain to end of document, if needed (for completeness)
tx.pushRetain( data.getLength() - ( insertion.offset + insertion.remove ) );
tx.pushFinalRetain( doc, insertion.offset + insertion.remove );
return tx;
};
@ -72,12 +71,11 @@ ve.dm.Transaction.newFromRemoval = function ( doc, range ) {
offset = 0,
removeStart = null,
removeEnd = null,
tx = new ve.dm.Transaction(),
data = doc.data;
tx = new ve.dm.Transaction();
// Validate range
if ( range.isCollapsed() ) {
// Empty range, nothing to remove, retain up to the end of the document (for completeness)
tx.pushRetain( data.getLength() );
tx.pushFinalRetain( doc, 0 );
return tx;
}
// Select nodes and validate selection
@ -102,7 +100,7 @@ ve.dm.Transaction.newFromRemoval = function ( doc, range ) {
}
tx.pushRetain( removeStart );
tx.addSafeRemoveOps( doc, removeStart, removeEnd );
tx.pushRetain( data.getLength() - removeEnd );
tx.pushFinalRetain( doc, removeEnd );
// All done
return tx;
}
@ -149,7 +147,7 @@ ve.dm.Transaction.newFromRemoval = function ( doc, range ) {
offset = removeEnd;
}
// Retain up to the end of the document
tx.pushRetain( data.getLength() - offset );
tx.pushFinalRetain( doc, offset );
return tx;
};
@ -174,7 +172,7 @@ ve.dm.Transaction.newFromNodeReplacement = function ( doc, nodeOrRange, newData
}
tx.pushRetain( range.start );
tx.pushReplace( doc, range.start, range.end - range.start, newData );
tx.pushRetain( doc.data.getLength() - range.end );
tx.pushFinalRetain( doc, range.end );
return tx;
};
@ -212,7 +210,7 @@ ve.dm.Transaction.newFromAttributeChanges = function ( doc, offset, attr ) {
);
}
// Retain to end of document
tx.pushRetain( data.length - offset );
tx.pushFinalRetain( doc, offset );
return tx;
};
@ -288,7 +286,7 @@ ve.dm.Transaction.newFromAnnotation = function ( doc, range, method, annotation
if ( on ) {
tx.pushStopAnnotating( method, annotation );
}
tx.pushRetain( data.getLength() - range.end );
tx.pushFinalRetain( doc, range.end );
return tx;
};
@ -320,7 +318,7 @@ ve.dm.Transaction.newFromMetadataInsertion = function ( doc, offset, index, newE
// Retain up to end of metadata elements (second dimension)
tx.pushRetainMetadata( elements.length - index );
// Retain to end of document
tx.pushRetain( doc.data.getLength() - offset );
tx.pushFinalRetain( doc, offset, elements.length );
return tx;
};
@ -363,8 +361,8 @@ ve.dm.Transaction.newFromMetadataRemoval = function ( doc, offset, range ) {
);
// Retain up to end of metadata elements (second dimension)
tx.pushRetainMetadata( elements.length - range.end );
// Retain to end of document
tx.pushRetain( doc.data.getLength() - offset );
// Retain to end of document (unless we're already off the end )
tx.pushFinalRetain( doc, offset, elements.length );
return tx;
};
@ -402,8 +400,8 @@ ve.dm.Transaction.newFromMetadataElementReplacement = function ( doc, offset, in
);
// Retain up to end of metadata elements (second dimension)
tx.pushRetainMetadata( elements.length - index - 1 );
// Retain to end of document
tx.pushRetain( doc.data.getLength() - offset );
// Retain to end of document (unless we're already off the end )
tx.pushFinalRetain( doc, offset, elements.length );
return tx;
};
@ -421,7 +419,6 @@ ve.dm.Transaction.newFromMetadataElementReplacement = function ( doc, offset, in
ve.dm.Transaction.newFromContentBranchConversion = function ( doc, range, type, attr ) {
var i, selected, branch, branchOuterRange,
tx = new ve.dm.Transaction(),
data = doc.getData(),
selection = doc.selectNodes( range, 'leaves' ),
opening = { 'type': type },
closing = { 'type': '/' + type },
@ -463,9 +460,7 @@ ve.dm.Transaction.newFromContentBranchConversion = function ( doc, range, type,
}
}
// Retain until the end
tx.pushRetain(
data.length - ( previousBranch ? previousBranchOuterRange.end : 0 )
);
tx.pushFinalRetain( doc, previousBranch ? previousBranchOuterRange.end : 0 );
return tx;
};
@ -598,7 +593,7 @@ ve.dm.Transaction.newFromWrap = function ( doc, range, unwrapOuter, wrapOuter, u
tx.pushReplace( doc, range.end, unwrapOuter.length, closingArray( wrapOuter ) );
// Retain up to the end of the document
tx.pushRetain( doc.data.getLength() - range.end - unwrapOuter.length );
tx.pushFinalRetain( doc, range.end + unwrapOuter.length );
return tx;
};
@ -787,6 +782,29 @@ ve.dm.Transaction.prototype.translateRange = function ( range, reversed ) {
return range.isBackwards() ? new ve.Range( end, start ) : new ve.Range( start, end );
};
/**
* Add a final retain operation to finish off a transaction (internal helper).
*
* @private
* @method
* @param {ve.dm.Document} doc Document to finish off.
* @param {number} Final offset edited by the transaction up to this point.
* @param {number} [metaOffset=0] Final metadata offset edited, if nonzero.
*/
ve.dm.Transaction.prototype.pushFinalRetain = function ( doc, offset, metaOffset ) {
var data = doc.data,
metadata = doc.metadata,
finalMetadata = metadata.getData( data.getLength() );
if ( offset < doc.data.getLength() ) {
this.pushRetain( doc.data.getLength() - offset );
metaOffset = 0;
}
// if there is trailing metadata, push a final retainMetadata
if ( finalMetadata !== undefined && finalMetadata.length > 0 ) {
this.pushRetainMetadata( finalMetadata.length - ( metaOffset || 0 ) );
}
};
/**
* Add a retain operation.
*

View file

@ -319,7 +319,8 @@ QUnit.test( 'newFromInsertion', function ( assert ) {
'remove': [],
'insert': [ 'b' ]
},
{ 'type': 'retain', 'length': 8 }
{ 'type': 'retain', 'length': 8 },
{ 'type': 'retainMetadata', 'length': 1 }
]
}
// TODO test cases for unclosed openings
@ -1177,7 +1178,8 @@ QUnit.test( 'newFromWrap', function ( assert ) {
{ 'type': 'replaceMetadata',
'insert': ve.dm.MetaLinearData.static.merge( listMetaDoc.getMetadata().slice(10, 12) )[0],
'remove': []
}
},
{ 'type': 'retainMetadata', 'length': 1 }
]
},
'checks integrity of unwrapOuter parameter': {