Merge "The resurrection"

This commit is contained in:
jenkins-bot 2013-04-22 18:38:12 +00:00 committed by Gerrit Code Review
commit b3850a65e3
16 changed files with 296 additions and 227 deletions

View file

@ -42,7 +42,7 @@ ve.AnnotationAction.static.methods = ['set', 'clear', 'toggle', 'clearAll'];
* @param {Object} [data] Additional annotation data
*/
ve.AnnotationAction.prototype.set = function ( name, data ) {
this.surface.getModel().getFragment().annotateContent( 'set', name, data ).destroy();
this.surface.getModel().getFragment().annotateContent( 'set', name, data );
};
/**
@ -53,7 +53,7 @@ ve.AnnotationAction.prototype.set = function ( name, data ) {
* @param {Object} [data] Additional annotation data
*/
ve.AnnotationAction.prototype.clear = function ( name, data ) {
this.surface.getModel().getFragment().annotateContent( 'clear', name, data ).destroy();
this.surface.getModel().getFragment().annotateContent( 'clear', name, data );
};
/**
@ -68,11 +68,9 @@ ve.AnnotationAction.prototype.clear = function ( name, data ) {
*/
ve.AnnotationAction.prototype.toggle = function ( name, data ) {
var fragment = this.surface.getModel().getFragment();
fragment
.annotateContent(
fragment.getAnnotations().hasAnnotationWithName( name ) ? 'clear' : 'set', name, data
)
.destroy();
fragment.annotateContent(
fragment.getAnnotations().hasAnnotationWithName( name ) ? 'clear' : 'set', name, data
);
};
/**
@ -91,7 +89,6 @@ ve.AnnotationAction.prototype.clearAll = function () {
for ( i = 0, len = arr.length; i < len; i++ ) {
fragment.annotateContent( 'clear', arr[i].name, arr[i].data );
}
fragment.destroy();
};
/* Registration */

View file

@ -42,7 +42,7 @@ ve.ContentAction.static.methods = ['insert', 'remove', 'select'];
* @param {boolean} annotate Content should be automatically annotated to match surrounding content
*/
ve.ContentAction.prototype.insert = function ( content, annotate ) {
this.surface.getModel().getFragment().insertContent( content, annotate ).destroy();
this.surface.getModel().getFragment().insertContent( content, annotate );
};
/**
@ -51,7 +51,7 @@ ve.ContentAction.prototype.insert = function ( content, annotate ) {
* @method
*/
ve.ContentAction.prototype.remove = function () {
this.surface.getModel().getFragment().removeContent().destroy();
this.surface.getModel().getFragment().removeContent();
};
/**

View file

@ -65,10 +65,9 @@ ve.FormatAction.prototype.convert = function ( type, attributes ) {
}
for ( i = 0, length = fragments.length; i < length; i++ ) {
fragments[i].isolateAndUnwrap( type ).destroy();
fragments[i].isolateAndUnwrap( type );
}
selection = fragmentForSelection.getRange();
fragmentForSelection.destroy();
txs = ve.dm.Transaction.newFromContentBranchConversion( doc, selection, type, attributes );
surfaceModel.change( txs, selection );

View file

@ -65,10 +65,9 @@ ve.IndentationAction.prototype.increase = function () {
this.indentListItem(
documentModel.getNodeFromOffset( fragments[i].getRange().start + 1 )
);
fragments[i].destroy();
}
selected.select().destroy();
selected.select();
return increased;
};
@ -104,10 +103,9 @@ ve.IndentationAction.prototype.decrease = function () {
this.unindentListItem(
documentModel.getNodeFromOffset( fragments[i].getRange().start + 1 )
);
fragments[i].destroy();
}
selected.select().destroy();
selected.select();
return decreased;
};
@ -301,7 +299,6 @@ ve.IndentationAction.prototype.unindentListItem = function ( listItem ) {
);
surfaceModel.change( tx );
}
fragment.destroy();
};
/* Registration */

View file

@ -94,7 +94,7 @@ ve.ce.ImageNode.prototype.onClick = function ( e ) {
[ selectionRange, nodeRange ], selectionRange.from > nodeRange.from
) :
nodeRange
).select().destroy();
).select();
};
/* Registration */

View file

@ -324,12 +324,11 @@ ve.ce.Surface.prototype.onDocumentDrop = function ( e ) {
nodeData = originFragment.getData();
// Remove node from old location (auto-updates targetFragment's range)
originFragment.removeContent().destroy();
originFragment.removeContent();
// Re-insert node at new location and re-select it
targetFragment.insertContent( nodeData );
targetFragment.adjustRange( -nodeData.length, 0 ).select().destroy();
targetFragment.destroy();
targetFragment.adjustRange( -nodeData.length, 0 ).select();
}, this ) );
}

View file

@ -24,6 +24,7 @@ ve.dm.Surface = function VeDmSurface( doc ) {
this.selectedNodes = {};
this.smallStack = [];
this.bigStack = [];
this.completeHistory = [];
this.undoIndex = 0;
this.historyTrackingInterval = null;
this.insertionAnnotations = new ve.dm.AnnotationSet( this.documentModel.getStore() );
@ -286,6 +287,10 @@ ve.dm.Surface.prototype.change = function ( transactions, selection ) {
this.bigStack = this.bigStack.slice( 0, this.bigStack.length - this.undoIndex );
this.undoIndex = 0;
this.smallStack.push( transactions[i] );
this.completeHistory.push( {
'undo': false,
'transaction': transactions[i]
} );
this.documentModel.commit( transactions[i] );
}
}
@ -411,7 +416,11 @@ ve.dm.Surface.prototype.undo = function () {
for ( i = item.stack.length - 1; i >= 0; i-- ) {
transaction = item.stack[i];
selection = transaction.translateRange( selection, true );
this.documentModel.rollback( item.stack[i] );
this.completeHistory.push( {
'undo': true,
'transaction': transaction
} );
this.documentModel.rollback( transaction );
}
this.emit( 'unlock' );
this.emit( 'history' );
@ -420,6 +429,23 @@ ve.dm.Surface.prototype.undo = function () {
return null;
};
/**
* Get the length of the complete history stack. This is also the current pointer.
* @returns {number} Length of the complete history stack
*/
ve.dm.Surface.prototype.getCompleteHistoryLength = function () {
return this.completeHistory.length;
};
/**
* Get all the items in the complete history stack since a specified pointer.
* @param {number} pointer Pointer from where to start the slice
* @returns {Array} Array of transaction objects with undo flag
*/
ve.dm.Surface.prototype.getCompleteHistorySince = function ( pointer ) {
return this.completeHistory.slice( pointer );
};
/**
* Step forwards in history.
*
@ -434,7 +460,7 @@ ve.dm.Surface.prototype.redo = function () {
if ( !this.enabled ) {
return;
}
var selection, item, i;
var item, i, transaction, selection;
this.breakpoint();
if ( this.undoIndex > 0 && this.bigStack[this.bigStack.length - this.undoIndex] ) {
@ -442,7 +468,12 @@ ve.dm.Surface.prototype.redo = function () {
item = this.bigStack[this.bigStack.length - this.undoIndex];
selection = item.selection;
for ( i = 0; i < item.stack.length; i++ ) {
this.documentModel.commit( item.stack[i] );
transaction = item.stack[i];
this.completeHistory.push( {
'undo': false,
'transaction': transaction
} );
this.documentModel.commit( transaction );
}
this.undoIndex--;
this.emit( 'unlock' );

View file

@ -21,26 +21,23 @@ ve.dm.SurfaceFragment = function VeDmSurfaceFragment( surface, range, noAutoSele
}
// Properties
this.range = range && range instanceof ve.Range ? range : surface.getSelection();
this.surface = surface;
this.setRange( range && range instanceof ve.Range ? range : surface.getSelection() );
// Short-circuit for invalid range null fragment
if ( !this.range ) {
return this;
}
this.surface = surface;
this.document = surface.getDocument();
this.noAutoSelect = !!noAutoSelect;
this.onTransactHandler = ve.bind( this.onTransact, this );
// Events
surface.on( 'transact', this.onTransactHandler );
// Initialization
var length = this.document.data.getLength();
this.range = new ve.Range(
this.setRange( new ve.Range(
// Clamp range to valid document offsets
Math.min( Math.max( this.range.from, 0 ), length ),
Math.min( Math.max( this.range.to, 0 ), length )
);
) );
};
/* Static Properties */
@ -55,16 +52,19 @@ ve.dm.SurfaceFragment.static = {};
/* Methods */
/**
* Handle transactions being processed on the document.
*
* This keeps the range of the fragment valid, even while other transactions are being processed
* Update range based on un-applied transactions in the surface.
*
* @method
* @param {ve.dm.Transaction[]} txs Transactions that have just been processed
*/
ve.dm.SurfaceFragment.prototype.onTransact = function ( txs ) {
for ( var i = 0; i < txs.length; i++ ) {
this.range = txs[i].translateRange( this.range );
ve.dm.SurfaceFragment.prototype.update = function () {
var i, length, txs;
// Small optimisation: check history pointer is in the past
if ( this.historyPointer < this.getSurface().getCompleteHistoryLength() ) {
txs = this.getSurface().getCompleteHistorySince( this.historyPointer );
for ( i = 0, length = txs.length; i < length; i++ ) {
this.range = txs[i].transaction.translateRange( this.range, txs[i].undo );
this.historyPointer++;
}
}
};
@ -91,11 +91,26 @@ ve.dm.SurfaceFragment.prototype.getDocument = function () {
/**
* Get the range of the fragment within the surface.
*
* This method also calls update to make sure the range returned is current.
*
* @method
* @param {boolean} noCopy Return the range by reference, not a copy
* @returns {ve.Range} Surface range
*/
ve.dm.SurfaceFragment.prototype.getRange = function () {
return this.range.clone();
ve.dm.SurfaceFragment.prototype.getRange = function ( noCopy ) {
this.update();
return noCopy ? this.range : this.range.clone();
};
/**
* Update the range of the transaction and reset the history pointer.
*
* @method
* @param {ve.Range} range New range
*/
ve.dm.SurfaceFragment.prototype.setRange = function ( range ) {
this.historyPointer = this.getSurface().getCompleteHistoryLength();
this.range = range;
};
/**
@ -108,21 +123,6 @@ ve.dm.SurfaceFragment.prototype.isNull = function () {
return this.surface === undefined;
};
/**
* Destroys fragment, removing event handlers and object references, leaving the fragment null.
*
* Call this whenever you are done using a fragment.
*
* @method
*/
ve.dm.SurfaceFragment.prototype.destroy = function () {
if ( this.surface ) {
this.surface.removeListener( 'transact', this.onTransactHandler );
this.surface = null;
this.document = null;
}
};
/**
* Get a new fragment with an adjusted position
*
@ -138,7 +138,7 @@ ve.dm.SurfaceFragment.prototype.adjustRange = function ( start, end ) {
}
return new ve.dm.SurfaceFragment(
this.surface,
new ve.Range( this.range.start + ( start || 0 ), this.range.end + ( end || 0 ) ),
new ve.Range( this.getRange( true ).start + ( start || 0 ), this.getRange( true ).end + ( end || 0 ) ),
this.noAutoSelect
);
};
@ -157,7 +157,7 @@ ve.dm.SurfaceFragment.prototype.truncateRange = function ( limit ) {
}
return new ve.dm.SurfaceFragment(
this.surface,
this.range.truncate( limit ),
this.getRange().truncate( limit ),
this.noAutoSelect
);
};
@ -174,7 +174,7 @@ ve.dm.SurfaceFragment.prototype.collapseRange = function () {
return this;
}
return new ve.dm.SurfaceFragment(
this.surface, new ve.Range( this.range.start ), this.noAutoSelect
this.surface, new ve.Range( this.getRange( true ).start ), this.noAutoSelect
);
};
@ -190,14 +190,14 @@ ve.dm.SurfaceFragment.prototype.trimRange = function () {
return this;
}
// If range is only whitespace
if ( this.document.getText( this.range ).trim().length === 0 ) {
if ( this.document.getText( this.getRange() ).trim().length === 0 ) {
// Collapse range
return new ve.dm.SurfaceFragment(
this.surface, new ve.Range( this.range.start ), this.noAutoSelect
this.surface, new ve.Range( this.getRange( true ).start ), this.noAutoSelect
);
}
return new ve.dm.SurfaceFragment(
this.surface, this.document.data.trimOuterSpaceFromRange( this.range ), this.noAutoSelect
this.surface, this.document.data.trimOuterSpaceFromRange( this.getRange() ), this.noAutoSelect
);
};
@ -223,30 +223,30 @@ ve.dm.SurfaceFragment.prototype.expandRange = function ( scope, type ) {
var range, node, nodes, parent;
switch ( scope || 'parent' ) {
case 'word':
if ( this.range.getLength() > 0 ) {
if ( this.getRange( true ).getLength() > 0 ) {
range = ve.Range.newCoveringRange( [
this.document.data.getNearestWordRange( this.range.start ),
this.document.data.getNearestWordRange( this.range.end )
this.document.data.getNearestWordRange( this.getRange( true ).start ),
this.document.data.getNearestWordRange( this.getRange( true ).end )
] );
if ( this.range.isBackwards() ) {
if ( this.getRange( true ).isBackwards() ) {
range = range.flip();
}
} else {
// optimisation for zero-length ranges
range = this.document.data.getNearestWordRange( this.range.start );
range = this.document.data.getNearestWordRange( this.getRange( true ).start );
}
break;
case 'annotation':
range = this.document.data.getAnnotatedRangeFromSelection( this.range, type );
range = this.document.data.getAnnotatedRangeFromSelection( this.getRange(), type );
// Adjust selection if it does not contain the annotated range
if ( this.range.start > range.start || this.range.end < range.end ) {
if ( this.getRange( true ).start > range.start || this.getRange( true ).end < range.end ) {
// Maintain range direction
if ( this.range.from > this.range.to ) {
if ( this.getRange( true ).from > this.getRange( true ).to ) {
range = range.flip();
}
} else {
// Otherwise just keep the range as is
range = this.range.clone();
range = this.getRange();
}
break;
case 'root':
@ -254,7 +254,7 @@ ve.dm.SurfaceFragment.prototype.expandRange = function ( scope, type ) {
break;
case 'siblings':
// Grow range to cover all siblings
nodes = this.document.selectNodes( this.range, 'siblings' );
nodes = this.document.selectNodes( this.getRange(), 'siblings' );
if ( nodes.length === 1 ) {
range = nodes[0].node.getOuterRange();
} else {
@ -266,7 +266,7 @@ ve.dm.SurfaceFragment.prototype.expandRange = function ( scope, type ) {
break;
case 'closest':
// Grow range to cover closest common ancestor node of given type
node = this.document.selectNodes( this.range, 'siblings' )[0].node;
node = this.document.selectNodes( this.getRange(), 'siblings' )[0].node;
parent = node.getParent();
while ( parent && parent.getType() !== type ) {
node = parent;
@ -279,7 +279,7 @@ ve.dm.SurfaceFragment.prototype.expandRange = function ( scope, type ) {
break;
case 'parent':
// Grow range to cover the closest common parent node
node = this.document.selectNodes( this.range, 'siblings' )[0].node;
node = this.document.selectNodes( this.getRange(), 'siblings' )[0].node;
parent = node.getParent();
if ( !parent ) {
return new ve.dm.SurfaceFragment( null );
@ -314,7 +314,7 @@ ve.dm.SurfaceFragment.prototype.getData = function ( deep ) {
if ( !this.surface ) {
return [];
}
return this.document.getData( this.range, deep );
return this.document.getData( this.getRange(), deep );
};
/**
@ -330,7 +330,7 @@ ve.dm.SurfaceFragment.prototype.getText = function () {
}
var i, length,
text = '',
data = this.document.getData( this.range );
data = this.document.getData( this.getRange() );
for ( i = 0, length = data.length; i < length; i++ ) {
if ( data[i].type === undefined ) {
// Annotated characters have a string at index 0, plain characters are 1-char strings
@ -355,8 +355,8 @@ ve.dm.SurfaceFragment.prototype.getAnnotations = function ( all ) {
if ( !this.surface ) {
return new ve.dm.AnnotationSet( this.getDocument().getStore() );
}
if ( this.range.getLength() ) {
return this.getDocument().data.getAnnotationsFromRange( this.range, all );
if ( this.getRange( true ).getLength() ) {
return this.getDocument().data.getAnnotationsFromRange( this.getRange(), all );
} else {
return this.surface.getInsertionAnnotations();
}
@ -375,7 +375,7 @@ ve.dm.SurfaceFragment.prototype.getLeafNodes = function () {
if ( !this.surface ) {
return [];
}
return this.document.selectNodes( this.range, 'leaves' );
return this.document.selectNodes( this.getRange(), 'leaves' );
};
/**
@ -395,7 +395,7 @@ ve.dm.SurfaceFragment.prototype.getCoveredNodes = function () {
if ( !this.surface ) {
return [];
}
return this.document.selectNodes( this.range, 'coveredNodes' );
return this.document.selectNodes( this.getRange(), 'coveredNodes' );
};
/**
@ -413,7 +413,7 @@ ve.dm.SurfaceFragment.prototype.getSiblingNodes = function () {
if ( !this.surface ) {
return [];
}
return this.document.selectNodes( this.range, 'siblings' );
return this.document.selectNodes( this.getRange(), 'siblings' );
};
/**
@ -439,7 +439,7 @@ ve.dm.SurfaceFragment.prototype.select = function () {
if ( !this.surface ) {
return this;
}
this.surface.change( null, this.range );
this.surface.change( null, this.getRange() );
return this;
};
@ -469,10 +469,10 @@ ve.dm.SurfaceFragment.prototype.annotateContent = function ( method, nameOrAnnot
} else {
annotation = ve.dm.annotationFactory.create( nameOrAnnotation, data );
}
if ( this.range.getLength() ) {
if ( this.getRange( true ).getLength() ) {
// Apply to selection
tx = ve.dm.Transaction.newFromAnnotation( this.document, this.range, method, annotation );
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.range ) );
tx = ve.dm.Transaction.newFromAnnotation( this.document, this.getRange(), method, annotation );
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.getRange() ) );
} else {
// Apply annotation to stack
if ( method === 'set' ) {
@ -500,7 +500,7 @@ ve.dm.SurfaceFragment.prototype.insertContent = function ( content, annotate ) {
return this;
}
var tx, annotations;
if ( this.range.getLength() ) {
if ( this.getRange( true ).getLength() ) {
this.removeContent();
}
// Auto-convert content to array of plain text characters
@ -509,13 +509,13 @@ ve.dm.SurfaceFragment.prototype.insertContent = function ( content, annotate ) {
}
if ( content.length ) {
if ( annotate ) {
annotations = this.document.data.getAnnotationsFromOffset( this.range.start - 1 );
annotations = this.document.data.getAnnotationsFromOffset( this.getRange( true ).start - 1 );
if ( annotations.getLength() > 0 ) {
ve.dm.Document.addAnnotationsToData( content, annotations );
}
}
tx = ve.dm.Transaction.newFromInsertion( this.document, this.range.start, content );
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.range ) );
tx = ve.dm.Transaction.newFromInsertion( this.document, this.getRange( true ).start, content );
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.getRange() ) );
}
return this;
};
@ -532,19 +532,18 @@ ve.dm.SurfaceFragment.prototype.removeContent = function () {
return this;
}
var tx;
if ( this.range.getLength() ) {
tx = ve.dm.Transaction.newFromRemoval( this.document, this.range );
// this.range will be translated via the onTransact event handler
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.range ) );
if ( this.getRange( true ).getLength() ) {
tx = ve.dm.Transaction.newFromRemoval( this.document, this.getRange() );
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.getRange() ) );
// Check if the range didn't get collapsed automatically - this will occur when removing
// content across un-mergable nodes because the delete only strips out content leaving
// structure at the beginning and end of the range in place
if ( this.range.getLength() ) {
if ( this.getRange( true ).getLength() ) {
// Collapse the range manually
this.range = new ve.Range( this.range.start );
this.range = new ve.Range( this.getRange( true ).start );
if ( !this.noAutoSelect ) {
// Update the surface selection
this.surface.change( null, this.range );
this.surface.change( null, this.getRange() );
}
}
}
@ -565,8 +564,8 @@ ve.dm.SurfaceFragment.prototype.convertNodes = function ( type, attr ) {
return this;
}
var tx =
ve.dm.Transaction.newFromContentBranchConversion( this.document, this.range, type, attr );
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.range ) );
ve.dm.Transaction.newFromContentBranchConversion( this.document, this.getRange(), type, attr );
this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.getRange() ) );
return this;
};
@ -597,10 +596,10 @@ ve.dm.SurfaceFragment.prototype.wrapNodes = function ( wrapper ) {
if ( !ve.isArray( wrapper ) ) {
wrapper = [wrapper];
}
var tx = ve.dm.Transaction.newFromWrap( this.document, this.range, [], [], [], wrapper ),
newRange = new ve.Range( this.range.start, this.range.end + tx.getLengthDifference() );
var tx = ve.dm.Transaction.newFromWrap( this.document, this.getRange(), [], [], [], wrapper ),
newRange = new ve.Range( this.getRange( true ).start, this.getRange( true ).end + tx.getLengthDifference() );
this.surface.change( tx, !this.noAutoSelect && newRange );
this.range = newRange;
this.setRange( newRange );
return this;
};
@ -624,22 +623,22 @@ ve.dm.SurfaceFragment.prototype.unwrapNodes = function ( outerDepth, innerDepth
}
var i, tx, newRange, innerUnwrapper = [], outerUnwrapper = [];
if ( this.range.end - this.range.start < innerDepth * 2 ) {
if ( this.getRange( true ).end - this.getRange( true ).start < innerDepth * 2 ) {
throw new Error( 'cannot unwrap by greater depth than maximum theoretical depth of selection' );
}
for ( i = 0; i < innerDepth; i++ ) {
innerUnwrapper.push( this.surface.getDocument().data.getData( this.range.start + i ) );
innerUnwrapper.push( this.surface.getDocument().data.getData( this.getRange( true ).start + i ) );
}
for ( i = outerDepth; i > 0; i-- ) {
outerUnwrapper.push( this.surface.getDocument().data.getData( this.range.start - i ) );
outerUnwrapper.push( this.surface.getDocument().data.getData( this.getRange( true ).start - i ) );
}
tx = ve.dm.Transaction.newFromWrap( this.document, this.range, outerUnwrapper, [], innerUnwrapper, [] );
newRange = new ve.Range( this.range.start - outerDepth, this.range.end + outerDepth + tx.getLengthDifference() );
tx = ve.dm.Transaction.newFromWrap( this.document, this.getRange(), outerUnwrapper, [], innerUnwrapper, [] );
newRange = new ve.Range( this.getRange( true ).start - outerDepth, this.getRange( true ).end + outerDepth + tx.getLengthDifference() );
this.surface.change( tx, !this.noAutoSelect && newRange );
this.range = newRange;
this.setRange( newRange );
return this;
};
@ -676,19 +675,19 @@ ve.dm.SurfaceFragment.prototype.rewrapNodes = function ( depth, wrapper ) {
wrapper = [wrapper];
}
if ( this.range.end - this.range.start < depth * 2 ) {
if ( this.getRange( true ).end - this.getRange( true ).start < depth * 2 ) {
throw new Error( 'cannot unwrap by greater depth than maximum theoretical depth of selection' );
}
for ( i = 0; i < depth; i++ ) {
unwrapper.push( this.surface.getDocument().data.getData( this.range.start + i ) );
unwrapper.push( this.surface.getDocument().data.getData( this.getRange( true ).start + i ) );
}
tx = ve.dm.Transaction.newFromWrap( this.document, this.range, [], [], unwrapper, wrapper );
newRange = new ve.Range( this.range.start, this.range.end + tx.getLengthDifference() );
tx = ve.dm.Transaction.newFromWrap( this.document, this.getRange(), [], [], unwrapper, wrapper );
newRange = new ve.Range( this.getRange( true ).start, this.getRange( true ).end + tx.getLengthDifference() );
this.surface.change( tx, !this.noAutoSelect && newRange );
this.range = newRange;
this.setRange( newRange );
return this;
};
@ -724,11 +723,11 @@ ve.dm.SurfaceFragment.prototype.wrapAllNodes = function ( wrapper ) {
wrapper = [wrapper];
}
tx = ve.dm.Transaction.newFromWrap( this.document, this.range, [], wrapper, [], [] );
newRange = new ve.Range( this.range.start, this.range.end + tx.getLengthDifference() );
tx = ve.dm.Transaction.newFromWrap( this.document, this.getRange(), [], wrapper, [], [] );
newRange = new ve.Range( this.getRange( true ).start, this.getRange( true ).end + tx.getLengthDifference() );
this.surface.change( tx, !this.noAutoSelect && newRange );
this.range = newRange;
this.setRange( newRange );
return this;
};
@ -757,25 +756,25 @@ ve.dm.SurfaceFragment.prototype.rewrapAllNodes = function ( depth, wrapper ) {
return this;
}
var i, tx, newRange, unwrapper = [],
innerRange = new ve.Range( this.range.start + depth, this.range.end - depth );
innerRange = new ve.Range( this.getRange( true ).start + depth, this.getRange( true ).end - depth );
if ( !ve.isArray( wrapper ) ) {
wrapper = [wrapper];
}
if ( this.range.end - this.range.start < depth * 2 ) {
if ( this.getRange( true ).end - this.getRange( true ).start < depth * 2 ) {
throw new Error( 'cannot unwrap by greater depth than maximum theoretical depth of selection' );
}
for ( i = 0; i < depth; i++ ) {
unwrapper.push( this.surface.getDocument().data.getData( this.range.start + i ) );
unwrapper.push( this.surface.getDocument().data.getData( this.getRange( true ).start + i ) );
}
tx = ve.dm.Transaction.newFromWrap( this.document, innerRange, unwrapper, wrapper, [], [] );
newRange = new ve.Range( this.range.start, this.range.end + tx.getLengthDifference() );
newRange = new ve.Range( this.getRange( true ).start, this.getRange( true ).end + tx.getLengthDifference() );
this.surface.change( tx, !this.noAutoSelect && newRange );
this.range = newRange;
this.setRange( newRange );
return this;
};
@ -807,7 +806,7 @@ ve.dm.SurfaceFragment.prototype.isolateAndUnwrap = function ( isolateForType ) {
startSplitNodes = [],
endSplitNodes = [],
fragment = this,
newRange = new ve.Range( this.range.start, this.range.end );
newRange = new ve.Range( this.getRange( true ).start, this.getRange( true ).end );
function createSplits( splitNodes, insertBefore ) {
var i, length,
@ -830,7 +829,7 @@ ve.dm.SurfaceFragment.prototype.isolateAndUnwrap = function ( isolateForType ) {
endOffset += endOffsetChange;
}
nodes = this.getDocument().selectNodes( this.range, 'siblings' );
nodes = this.getDocument().selectNodes( this.getRange(), 'siblings' );
// Find start split point, if required
startSplitNode = nodes[0].node;

View file

@ -9,67 +9,117 @@ QUnit.module( 've.FormatAction' );
/* Tests */
function runConverterTest( assert, range, type, attributes, expectedSelection, expectedData, label ) {
var dom = ve.createDocumentFromHTML( ve.dm.example.isolationHTML ),
function runFormatConverterTest( assert, range, type, attributes, expectedSelection, expectedData, msg ) {
var selection,
dom = ve.createDocumentFromHTML( ve.dm.example.isolationHTML ),
surface = new ve.Surface( new ve.init.Target( $( '<div>' ) ), dom ),
formatAction = new ve.FormatAction( surface ),
data = ve.copyArray( surface.getModel().getDocument().getFullData() );
data = ve.copyArray( surface.getModel().getDocument().getFullData() ),
originalData = ve.copyArray( data );
expectedData( data );
surface.getModel().change( null, range );
formatAction.convert( type, attributes );
expectedData( data );
assert.deepEqual( surface.getModel().getDocument().getFullData(), data, msg + ': data models match' );
assert.deepEqual( surface.getModel().getSelection(), expectedSelection, msg + ': selections match' );
assert.deepEqual( surface.getModel().getDocument().getFullData(), data, label + ': data models match' );
assert.deepEqual( surface.getModel().getSelection(), expectedSelection, label + ': selections match' );
selection = surface.getModel().undo();
assert.deepEqual( surface.getModel().getDocument().getFullData(), originalData, msg + ' (undo): data models match' );
assert.deepEqual( selection, range, msg + ' (undo): selections match' );
surface.destroy();
}
QUnit.test( 'convert', 12, function ( assert ) {
var rebuilt = { 'changed': { 'rebuilt': 1 } },
QUnit.test( 'convert', function ( assert ) {
var i,
rebuilt = { 'changed': { 'rebuilt': 1 } },
created = { 'changed': { 'created': 1 } },
createdAndRebuilt = { 'changed': { 'created': 1, 'rebuilt': 1 } };
runConverterTest( assert, new ve.Range( 14, 16 ), 'MWheading', { level: 2 }, new ve.Range( 14, 16 ), function( data ) {
data[0].internal = rebuilt;
data.splice( 11, 2, { 'type': '/list' }, { 'type': 'MWheading', 'attributes': { 'level': 2 }, 'internal': created } );
data.splice( 19, 2, { 'type': '/MWheading' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt } );
}, 'converting partial selection of list item "Item 2" to level 2 MWheading' );
runConverterTest( assert, new ve.Range( 15, 50 ), 'MWheading', { level: 3 }, new ve.Range( 15, 44 ), function( data ) {
data[0].internal = rebuilt;
data.splice( 11, 2, { 'type': '/list' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 19, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 27, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 38, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 46, 2, { 'type': '/MWheading' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': created } );
}, 'converting partial selection across two lists surrounding a paragraph' );
runConverterTest( assert, new ve.Range( 4, 28 ), 'MWheading', { level: 1 }, new ve.Range( 2, 22 ), function( data ) {
data[0].internal = rebuilt;
data.splice( 0, 3, { 'type': 'MWheading', 'attributes': { 'level': 1 }, 'internal': created } );
data.splice( 7, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 1 }, 'internal': created } );
data.splice( 15, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 1 }, 'internal': created } );
data.splice( 23, 3, { 'type': '/MWheading' } );
}, 'converting partial selection of all list items to level 1 MWheadings' );
runConverterTest( assert, new ve.Range( 5, 26 ), 'MWpreformatted', undefined, new ve.Range( 3, 20 ), function( data ) {
data[0].internal = rebuilt;
data.splice( 0, 3, { 'type': 'MWpreformatted', 'internal': created } );
data.splice( 7, 4, { 'type': '/MWpreformatted' }, { 'type': 'MWpreformatted', 'internal': created } );
data.splice( 15, 4, { 'type': '/MWpreformatted' }, { 'type': 'MWpreformatted', 'internal': created } );
data.splice( 23, 3, { 'type': '/MWpreformatted' } );
}, 'converting partial selection of some list items to MWpreformatted text' );
runConverterTest( assert, new ve.Range( 146, 159 ), 'paragraph', undefined, new ve.Range( 146, 159 ), function( data ) {
data.splice( 145, 1, { 'type': 'paragraph', 'internal': created } );
data.splice( 159, 1, { 'type': '/paragraph' } );
}, 'converting heading in list item to paragraph' );
runConverterTest( assert, new ve.Range( 165, 180 ), 'paragraph', undefined, new ve.Range( 165, 180 ), function( data ) {
data.splice( 162, 1, { 'type': 'paragraph', 'internal': created } );
data.splice( 183, 1, { 'type': '/paragraph' } );
}, 'converting MWpreformatted in list item to paragraph' );
createdAndRebuilt = { 'changed': { 'created': 1, 'rebuilt': 1 } },
cases = [
{
'range': new ve.Range( 14, 16 ),
'type': 'MWheading',
'attributes': { level: 2 },
'expectedSelection': new ve.Range( 14, 16 ),
'expectedData': function( data ) {
data[0].internal = rebuilt;
data.splice( 11, 2, { 'type': '/list' }, { 'type': 'MWheading', 'attributes': { 'level': 2 }, 'internal': created } );
data.splice( 19, 2, { 'type': '/MWheading' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt } );
},
'msg': 'converting partial selection of list item "Item 2" to level 2 MWheading'
},
{
'range': new ve.Range( 15, 50 ),
'type': 'MWheading',
'attributes': { level: 3 },
'expectedSelection': new ve.Range( 15, 44 ),
'expectedData': function( data ) {
data[0].internal = rebuilt;
data.splice( 11, 2, { 'type': '/list' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 19, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 27, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 38, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 3 }, 'internal': created } );
data.splice( 46, 2, { 'type': '/MWheading' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': created } );
},
'msg': 'converting partial selection across two lists surrounding a paragraph'
},
{
'range': new ve.Range( 4, 28 ),
'type': 'MWheading',
'attributes': { level: 1 },
'expectedSelection': new ve.Range( 2, 22 ),
'expectedData': function( data ) {
data[0].internal = rebuilt;
data.splice( 0, 3, { 'type': 'MWheading', 'attributes': { 'level': 1 }, 'internal': created } );
data.splice( 7, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 1 }, 'internal': created } );
data.splice( 15, 4, { 'type': '/MWheading' }, { 'type': 'MWheading', 'attributes': { 'level': 1 }, 'internal': created } );
data.splice( 23, 3, { 'type': '/MWheading' } );
},
'msg': 'converting partial selection of all list items to level 1 MWheadings'
},
{
'range': new ve.Range( 5, 26 ),
'type': 'MWpreformatted',
'attributes': undefined,
'expectedSelection': new ve.Range( 3, 20 ),
'expectedData': function( data ) {
data[0].internal = rebuilt;
data.splice( 0, 3, { 'type': 'MWpreformatted', 'internal': created } );
data.splice( 7, 4, { 'type': '/MWpreformatted' }, { 'type': 'MWpreformatted', 'internal': created } );
data.splice( 15, 4, { 'type': '/MWpreformatted' }, { 'type': 'MWpreformatted', 'internal': created } );
data.splice( 23, 3, { 'type': '/MWpreformatted' } );
},
'msg': 'converting partial selection of some list items to MWpreformatted text'
},
{
'range': new ve.Range( 146, 159 ),
'type': 'paragraph',
'attributes': undefined,
'expectedSelection': new ve.Range( 146, 159 ),
'expectedData': function( data ) {
data.splice( 145, 1, { 'type': 'paragraph', 'internal': created } );
data.splice( 159, 1, { 'type': '/paragraph' } );
},
'msg': 'converting heading in list item to paragraph'
},
{
'range': new ve.Range( 165, 180 ),
'type': 'paragraph',
'attributes': undefined,
'expectedSelection': new ve.Range( 165, 180 ),
'expectedData': function( data ) {
data.splice( 162, 1, { 'type': 'paragraph', 'internal': created } );
data.splice( 183, 1, { 'type': '/paragraph' } );
},
'msg': 'converting MWpreformatted in list item to paragraph'
}
];
QUnit.expect( cases.length * 4 );
for ( i = 0; i < cases.length; i++ ) {
runFormatConverterTest( assert, cases[i].range, cases[i].type, cases[i].attributes, cases[i].expectedSelection, cases[i].expectedData, cases[i].msg );
}
} );

View file

@ -9,30 +9,57 @@ QUnit.module( 've.IndentationAction' );
/* Tests */
function runIndentationTest( assert, range, method, expectedSelection, expectedData, label ) {
var dom = ve.createDocumentFromHTML( ve.dm.example.isolationHTML ),
function runIndentationChangeTest( assert, range, method, expectedSelection, expectedData, expectedOriginalData, msg ) {
var selection,
dom = ve.createDocumentFromHTML( ve.dm.example.isolationHTML ),
surface = new ve.Surface( new ve.init.Target( $( '<div>' ) ), dom ),
indentationAction = new ve.IndentationAction( surface ),
data = ve.copyArray( surface.getModel().getDocument().getFullData() );
data = ve.copyArray( surface.getModel().getDocument().getFullData() ),
originalData = ve.copyArray( data );
expectedData( data );
if ( expectedOriginalData ) {
expectedOriginalData( originalData );
}
surface.getModel().change( null, range );
indentationAction[method]();
expectedData( data );
assert.deepEqual( surface.getModel().getDocument().getFullData(), data, msg + ': data models match' );
assert.deepEqual( surface.getModel().getSelection(), expectedSelection, msg + ': selections match' );
assert.deepEqual( surface.getModel().getDocument().getFullData(), data, label + ': data models match' );
assert.deepEqual( surface.getModel().getSelection(), expectedSelection, label + ': selections match' );
selection = surface.getModel().undo();
assert.deepEqual( surface.getModel().getDocument().getFullData(), originalData, msg + ' (undo): data models match' );
assert.deepEqual( selection, range, msg + ' (undo): selections match' );
surface.destroy();
}
QUnit.test( 'decrease', 2, function ( assert ) {
var rebuilt = { 'changed': { 'rebuilt': 1 } },
createdAndRebuilt = { 'changed': { 'created': 2, 'rebuilt': 1 } };
var i,
rebuilt = { 'changed': { 'rebuilt': 1 } },
createdAndRebuilt = { 'changed': { 'created': 2, 'rebuilt': 1 } },
cases = [
{
'range': new ve.Range( 14, 16 ),
'method': 'decrease',
'expectedSelection': new ve.Range( 14, 16 ),
'expectedData': function( data ) {
data[0].internal = rebuilt;
data.splice( 11, 2, { 'type': '/list' }, { 'type': 'paragraph' } );
data.splice( 19, 2, { 'type': '/paragraph' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt } );
},
'expectedOriginalData': function( data ) {
// generated: 'wrapper' is removed by the action and not restored by undo
delete data[12].internal;
},
'msg': 'decrease indentation on partial selection of list item "Item 2"'
}
];
runIndentationTest( assert, new ve.Range( 14, 16 ), 'decrease', new ve.Range( 14, 16 ), function( data ) {
data[0].internal = rebuilt;
data.splice( 11, 2, { 'type': '/list' }, { 'type': 'paragraph' } );
data.splice( 19, 2, { 'type': '/paragraph' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt } );
}, 'decrease indentation on partial selection of list item "Item 2"' );
QUnit.expect( cases.length * 4 );
for ( i = 0; i < cases.length; i++ ) {
runIndentationChangeTest( assert, cases[i].range, cases[i].method, cases[i].expectedSelection, cases[i].expectedData, cases[i].expectedOriginalData, cases[i].msg );
}
} );

View file

@ -24,23 +24,26 @@ QUnit.test( 'constructor', 8, function ( assert ) {
assert.equal( fragment.getRange().from, 0, 'range is clamped between 0 and document length' );
assert.equal( fragment.getRange().to, 61, 'range is clamped between 0 and document length' );
assert.strictEqual( fragment.willAutoSelect(), false, 'noAutoSelect values are boolean' );
fragment.destroy();
} );
QUnit.test( 'onTransact', 1, function ( assert ) {
QUnit.test( 'update', 2, function ( assert ) {
var doc = ve.dm.example.createExampleDocument(),
surface = new ve.dm.Surface( doc ),
fragment1 = new ve.dm.SurfaceFragment( surface, new ve.Range( 1, 56 ) ),
fragment2 = new ve.dm.SurfaceFragment( surface, new ve.Range( 2, 4 ) );
fragment2 = new ve.dm.SurfaceFragment( surface, new ve.Range( 2, 4 ) ),
fragment3 = new ve.dm.SurfaceFragment( surface, new ve.Range( 2, 4 ) );
fragment1.removeContent();
assert.deepEqual(
fragment2.getRange(),
new ve.Range( 1, 1 ),
'fragment ranges are auto-translated when transactions are processed'
'fragment range collapses after removeContent'
);
surface.undo();
assert.deepEqual(
fragment3.getRange(),
new ve.Range( 4, 4 ),
'fragment range moved after undo'
);
fragment1.destroy();
fragment2.destroy();
} );
QUnit.test( 'adjustRange', 3, function ( assert ) {
@ -51,7 +54,6 @@ QUnit.test( 'adjustRange', 3, function ( assert ) {
assert.ok( fragment !== adjustedFragment, 'adjustRange produces a new fragment' );
assert.deepEqual( fragment.getRange(), new ve.Range( 20, 21 ), 'old fragment is not changed' );
assert.deepEqual( adjustedFragment.getRange(), new ve.Range( 1, 56 ), 'new range is used' );
fragment.destroy();
} );
QUnit.test( 'collapseRange', 3, function ( assert ) {
@ -62,8 +64,6 @@ QUnit.test( 'collapseRange', 3, function ( assert ) {
assert.ok( fragment !== collapsedFragment, 'collapseRange produces a new fragment' );
assert.deepEqual( fragment.getRange(), new ve.Range( 20, 21 ), 'old fragment is not changed' );
assert.deepEqual( collapsedFragment.getRange(), new ve.Range( 20, 20 ), 'new range is used' );
collapsedFragment.destroy();
fragment.destroy();
} );
QUnit.test( 'expandRange (closest)', 1, function ( assert ) {
@ -76,8 +76,6 @@ QUnit.test( 'expandRange (closest)', 1, function ( assert ) {
true,
'closest with invalid type results in null fragment'
);
exapandedFragment.destroy();
fragment.destroy();
} );
QUnit.test( 'expandRange (word)', 1, function ( assert ) {
@ -111,8 +109,6 @@ QUnit.test( 'expandRange (word)', 1, function ( assert ) {
word = cases[i].phrase.substring( range.start, range.end );
assert.strictEqual( word, cases[i].expected, cases[i].msg + ': text' );
assert.strictEqual( cases[i].range.isBackwards(), range.isBackwards(), cases[i].msg + ': range direction' );
fragment.destroy();
newFragment.destroy();
}
} );
@ -135,7 +131,6 @@ QUnit.test( 'removeContent', 2, function ( assert ) {
new ve.Range( 1, 1 ),
'removing content results in a zero-length fragment'
);
fragment.destroy();
} );
QUnit.test( 'insertContent', 3, function ( assert ) {
@ -159,7 +154,6 @@ QUnit.test( 'insertContent', 3, function ( assert ) {
['3', '2', '1'],
'strings get converted into data when inserting content'
);
fragment.destroy();
} );
QUnit.test( 'wrapNodes/unwrapNodes', 10, function ( assert ) {
@ -205,7 +199,6 @@ QUnit.test( 'wrapNodes/unwrapNodes', 10, function ( assert ) {
fragment.unwrapNodes( 0, 2 );
assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' );
assert.deepEqual( fragment.getRange(), new ve.Range( 55, 61 ), 'range after unwrapping is same as original range' );
fragment.destroy();
// Make a 1 paragraph into 1 list with 1 item
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 9, 12 ) );
@ -234,13 +227,11 @@ QUnit.test( 'wrapNodes/unwrapNodes', 10, function ( assert ) {
fragment.unwrapNodes( 0, 2 );
assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' );
assert.deepEqual( fragment.getRange(), new ve.Range( 9, 12 ), 'range after unwrapping is same as original range' );
fragment.destroy();
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 8, 34 ) );
fragment.unwrapNodes( 3, 1 );
assert.deepEqual( fragment.getData(), doc.getData( new ve.Range( 5, 29 ) ), 'unwrapping multiple outer nodes and an inner node' );
assert.deepEqual( fragment.getRange(), new ve.Range( 5, 29 ), 'new range contains inner elements' );
fragment.destroy();
} );
QUnit.test( 'rewrapNodes', 4, function ( assert ) {
@ -284,7 +275,6 @@ QUnit.test( 'rewrapNodes', 4, function ( assert ) {
// The intermediate stage (plain text attached to the document) would be invalid
// if performed as an unwrap and a wrap
expectedData = ve.copyArray( doc.getData() );
fragment.destroy();
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 59, 65 ) );
fragment.rewrapNodes( 1, [ { 'type': 'heading', 'attributes': { 'level': 1 } } ] );
@ -296,7 +286,6 @@ QUnit.test( 'rewrapNodes', 4, function ( assert ) {
assert.deepEqual( doc.getData(), expectedData, 'rewrapping paragraphs as headings' );
assert.deepEqual( fragment.getRange(), new ve.Range( 59, 65 ), 'new range contains rewrapping elements' );
fragment.destroy();
} );
QUnit.test( 'wrapAllNodes', 10, function ( assert ) {
@ -335,7 +324,6 @@ QUnit.test( 'wrapAllNodes', 10, function ( assert ) {
fragment.unwrapNodes( 0, 2 );
assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' );
assert.deepEqual( fragment.getRange(), new ve.Range( 55, 61 ), 'range after unwrapping is same as original range' );
fragment.destroy();
// Make a 1 paragraph into 1 list with 1 item
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 9, 12 ) );
@ -364,7 +352,6 @@ QUnit.test( 'wrapAllNodes', 10, function ( assert ) {
fragment.unwrapNodes( 0, 2 );
assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' );
assert.deepEqual( fragment.getRange(), new ve.Range( 9, 12 ), 'range after unwrapping is same as original range' );
fragment.destroy();
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 5, 37 ) );
@ -380,7 +367,6 @@ QUnit.test( 'wrapAllNodes', 10, function ( assert ) {
expectedData,
'unwrapping 4 levels (table, tableSection, tableRow and tableCell)'
);
fragment.destroy();
} );
QUnit.test( 'rewrapAllNodes', 6, function ( assert ) {
@ -410,7 +396,6 @@ QUnit.test( 'rewrapAllNodes', 6, function ( assert ) {
'rewrapping multiple nodes via a valid intermediate state produces the same document as unwrapping then wrapping'
);
assert.deepEqual( fragment.getRange(), expectedFragment.getRange(), 'new range contains rewrapping elements' );
expectedFragment.destroy();
// Reverse of first test
fragment.rewrapAllNodes(
@ -434,7 +419,6 @@ QUnit.test( 'rewrapAllNodes', 6, function ( assert ) {
'rewrapping multiple nodes via a valid intermediate state produces the same document as unwrapping then wrapping'
);
assert.deepEqual( fragment.getRange(), new ve.Range( 5, 37 ), 'new range contains rewrapping elements' );
fragment.destroy();
// Rewrap a heading as a paragraph
// The intermediate stage (plain text attached to the document) would be invalid
@ -447,7 +431,6 @@ QUnit.test( 'rewrapAllNodes', 6, function ( assert ) {
assert.deepEqual( doc.getData(), expectedData, 'rewrapping a heading as a paragraph' );
assert.deepEqual( fragment.getRange(), new ve.Range( 0, 5 ), 'new range contains rewrapping elements' );
fragment.destroy();
} );
function runIsolateTest( assert, type, range, expected, label ) {
@ -461,7 +444,6 @@ function runIsolateTest( assert, type, range, expected, label ) {
expected( data );
assert.deepEqual( doc.getFullData(), data, label );
fragment.destroy();
}
QUnit.test( 'isolateAndUnwrap', 4, function ( assert ) {

View file

@ -2288,7 +2288,7 @@ ve.dm.example.isolationData = [
{ 'type': '/tableSection' },
{ 'type': '/table' },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'N', 'o', 't', ' ', 'a', 'l', 'l', 'o', 'w', 'e', 'd', ' ', 'b', 'y', ' ', 'd', 'm', ': ',
'N', 'o', 't', ' ', 'a', 'l', 'l', 'o', 'w', 'e', 'd', ' ', 'b', 'y', ' ', 'd', 'm', ':',
{ 'type': '/paragraph' },
{ 'type': 'list', 'attributes': { 'style': 'bullet' } },
{ 'type': 'listItem' },

View file

@ -81,18 +81,15 @@ ve.ui.LinkInspector.prototype.onSetup = function () {
if ( fragment.getRange().isCollapsed() ) {
// Expand to nearest word
expandedFragment = fragment.expandRange( 'word' );
fragment.destroy();
fragment = expandedFragment;
} else {
// Trim whitespace
trimmedFragment = fragment.trimRange();
fragment.destroy();
fragment = trimmedFragment;
}
if ( !fragment.getRange().isCollapsed() ) {
// Create annotation from selection
truncatedFragment = fragment.truncateRange( 255 );
fragment.destroy();
fragment = truncatedFragment;
annotation = this.getAnnotationFromTarget( fragment.getText() );
fragment.annotateContent( 'set', annotation );
@ -101,12 +98,11 @@ ve.ui.LinkInspector.prototype.onSetup = function () {
} else {
// Expand range to cover annotation
expandedFragment = fragment.expandRange( 'annotation', annotation );
fragment.destroy();
fragment = expandedFragment;
}
// Update selection
fragment.select().destroy();
fragment.select();
};
/**
@ -128,8 +124,6 @@ ve.ui.LinkInspector.prototype.onOpen = function () {
this.targetInput.setAnnotation( annotation );
this.targetInput.$input.focus().select();
}, this ), 200 );
fragment.destroy();
};
/**
@ -174,7 +168,6 @@ ve.ui.LinkInspector.prototype.onClose = function ( action ) {
// Insert default text and select it
fragment.insertContent( target, false );
adjustedFragment = fragment.adjustRange( -target.length, 0 );
fragment.destroy();
fragment = adjustedFragment;
// Move cursor to the end of the inserted content
@ -204,8 +197,6 @@ ve.ui.LinkInspector.prototype.onClose = function ( action ) {
);
// Reset state
this.isNewAnnotation = false;
fragment.destroy();
};
/**

View file

@ -238,8 +238,6 @@ ve.ui.Context.prototype.update = function () {
// Remember selection for next time
this.selection = selection.clone();
fragment.destroy();
return this;
};

View file

@ -79,7 +79,6 @@ ve.ui.Toolbar.prototype.onContextChange = function () {
}
}
this.emit( 'updateState', nodes, fragment.getAnnotations(), fragment.getAnnotations( true ) );
fragment.destroy();
};
/**

View file

@ -170,7 +170,7 @@ ve.Surface.prototype.isEnabled = function () {
* @method
*/
ve.Surface.prototype.resetSelection = function () {
this.model.getFragment().select().destroy();
this.model.getFragment().select();
this.view.surfaceObserver.poll();
};