Merge "(bug 45423) Create SurfaceFragment.isolate method"

This commit is contained in:
jenkins-bot 2013-02-22 20:40:32 +00:00 committed by Gerrit Code Review
commit 1ef5c07a93
2 changed files with 131 additions and 1 deletions

View file

@ -690,3 +690,88 @@ ve.dm.SurfaceFragment.prototype.rewrapAllNodes = function () {
// TODO: Implement
return this;
};
/**
* Isolates the nodes in a fragment.
*
* The node selection is expanded to siblings and then these are isolated such that they are the
* sole children of a parent element which can be placed anywhere.
*
* @method
* @returns {ve.dm.SurfaceFragment} This fragment
*/
ve.dm.SurfaceFragment.prototype.isolate = function () {
// Handle null fragment
if ( !this.surface ) {
return this;
}
var nodes, startSplitNode, endSplitNode, tx,
startOffset, endOffset,
startSplitRequired = false,
endSplitRequired = false,
startSplitNodes = [],
endSplitNodes = [],
fragment = this;
function createSplits( splitNodes, insertBefore ) {
var i, length,
startOffsetChange = 0, endOffsetChange = 0, data = [];
for ( i = 0, length = splitNodes.length; i < length; i++ ) {
data.unshift( { 'type': '/' + splitNodes[i].type } );
data.push( splitNodes[i].getClonedElement() );
if ( insertBefore ) {
startOffsetChange += 2;
endOffsetChange += 2;
}
}
tx = ve.dm.Transaction.newFromInsertion( fragment.document, insertBefore ? startOffset : endOffset, data );
fragment.surface.change( tx, !fragment.noAutoSelect && tx.translateRange( fragment.range ) );
startOffset += startOffsetChange;
endOffset += endOffsetChange;
}
nodes = this.document.selectNodes( this.range, 'siblings' );
// Find start split point, if required
startSplitNode = nodes[0].node;
startOffset = startSplitNode.getOuterRange().start;
while ( startSplitNode.constructor.static.parentNodeTypes !== null ) {
if ( startSplitNode.parent.indexOf( startSplitNode ) > 0 ) {
startSplitRequired = true;
}
startSplitNode = startSplitNode.parent;
if ( startSplitRequired ) {
startSplitNodes.unshift(startSplitNode);
} else {
startOffset = startSplitNode.getOuterRange().start;
}
}
// Find end split point, if required
endSplitNode = nodes[nodes.length - 1].node;
endOffset = endSplitNode.getOuterRange().end;
while ( endSplitNode.constructor.static.parentNodeTypes !== null ) {
if ( endSplitNode.parent.indexOf( endSplitNode ) < endSplitNode.parent.getChildren().length - 1 ) {
endSplitRequired = true;
}
endSplitNode = endSplitNode.parent;
if ( endSplitRequired ) {
endSplitNodes.unshift(endSplitNode);
} else {
endOffset = endSplitNode.getOuterRange().end;
}
}
if ( startSplitRequired ) {
createSplits( startSplitNodes, true );
}
if ( endSplitRequired ) {
createSplits( endSplitNodes, false );
}
return this;
};

View file

@ -7,7 +7,7 @@
QUnit.module( 've.dm.SurfaceFragment' );
// Tests
/* Tests */
QUnit.test( 'constructor', 8, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
@ -225,3 +225,48 @@ QUnit.test( 'wrapAllNodes', 2, function ( assert ) {
'wrapping nodes can add multiple levels of wrapping to a single element'
);
} );
function runIsolateTest( assert, range, expected, label ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.isolationData ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, range ),
data;
data = ve.copyArray( doc.getFullData() );
fragment.isolate();
expected( data );
assert.deepEqual( doc.getFullData(), data, label );
}
QUnit.test( 'isolate', 2, function ( assert ) {
var rebuilt = { 'changed': { 'rebuilt': 1 } },
created = { 'changed': { 'created': 1 } },
createdAndRebuilt = { 'changed': { 'created': 1, 'rebuilt': 1 } };
runIsolateTest( assert, new ve.Range( 11, 21 ), function( data ) {
data[0].internal = rebuilt;
data.splice( 11, 0, { 'type': '/list' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt });
data.splice( 23, 0, { 'type': '/list' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt });
}, 'isolating list item "Item 2"');
runIsolateTest( assert, new ve.Range( 88, 108 ), function( data ) {
data[75].internal = rebuilt;
data[76].internal = rebuilt;
data[77].internal = rebuilt;
data.splice( 88, 0,
{ 'type': '/tableRow' },
{ 'type': '/tableSection' },
{ 'type': '/table' },
{ 'type': 'table', 'internal': createdAndRebuilt },
{ 'type': 'tableSection', 'attributes': { 'style': 'body' }, 'internal': createdAndRebuilt },
{ 'type': 'tableRow', 'internal': created }
);
data.splice( 115, 0,
{ 'type': '/tableSection' },
{ 'type': '/table' },
{ 'type': 'table', 'internal': createdAndRebuilt },
{ 'type': 'tableSection', 'attributes': { 'style': 'body' }, 'internal': createdAndRebuilt }
);
}, 'isolating table cells "Cell 2" & "Cell 3"');
} );