mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-24 22:35:41 +00:00
Merge "Implement SurfaceFragment.rewrapAllNodes"
This commit is contained in:
commit
8d54ef4135
|
@ -662,6 +662,13 @@ ve.dm.SurfaceFragment.prototype.wrapAllNodes = function ( wrapper ) {
|
|||
/**
|
||||
* Unwrap nodes in the fragment out of one or more elements.
|
||||
*
|
||||
* Unwrap only removes elements from inside the fragment.
|
||||
*
|
||||
* Example:
|
||||
* // fragment is a selection of: <ul><li><p>text</p></li></ul>
|
||||
* fragment.unwrapAllNodes( 2 );
|
||||
* // fragment is now a selection of: <p>text</p>
|
||||
*
|
||||
* @method
|
||||
* @param {number} depth Number of nodes to unwrap
|
||||
* @chainable
|
||||
|
@ -671,7 +678,7 @@ ve.dm.SurfaceFragment.prototype.unwrapAllNodes = function ( depth ) {
|
|||
if ( !this.surface ) {
|
||||
return this;
|
||||
}
|
||||
var i, tx, newRange, wrapper = [],
|
||||
var i, tx, newRange, unwrapper = [],
|
||||
innerRange = new ve.Range( this.range.start + depth, this.range.end - depth );
|
||||
|
||||
if ( this.range.end - this.range.start < depth * 2 ) {
|
||||
|
@ -679,12 +686,12 @@ ve.dm.SurfaceFragment.prototype.unwrapAllNodes = function ( depth ) {
|
|||
}
|
||||
|
||||
for ( i = 0; i < depth; i++ ) {
|
||||
wrapper.push( this.surface.getDocument().data[this.range.start + i] );
|
||||
unwrapper.push( this.surface.getDocument().data[this.range.start + i] );
|
||||
}
|
||||
|
||||
newRange = new ve.Range( this.range.start, this.range.end - ( depth * 2 ) );
|
||||
|
||||
tx = ve.dm.Transaction.newFromWrap( this.document, innerRange, wrapper, [], [], [] );
|
||||
tx = ve.dm.Transaction.newFromWrap( this.document, innerRange, unwrapper, [], [], [] );
|
||||
this.surface.change( tx, !this.noAutoSelect && newRange );
|
||||
|
||||
this.range = newRange;
|
||||
|
@ -705,12 +712,30 @@ ve.dm.SurfaceFragment.prototype.unwrapAllNodes = function ( depth ) {
|
|||
* @param {Object} [wrapper.attributes] Attributes of wrapper
|
||||
* @chainable
|
||||
*/
|
||||
ve.dm.SurfaceFragment.prototype.rewrapAllNodes = function () {
|
||||
ve.dm.SurfaceFragment.prototype.rewrapAllNodes = function ( depth, wrapper ) {
|
||||
// Handle null fragment
|
||||
if ( !this.surface ) {
|
||||
return this;
|
||||
}
|
||||
// TODO: Implement
|
||||
var i, tx, newRange, unwrapper = [],
|
||||
depthChange = wrapper.length - depth,
|
||||
innerRange = new ve.Range( this.range.start + depth, this.range.end - depth );
|
||||
|
||||
if ( this.range.end - this.range.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[this.range.start + i] );
|
||||
}
|
||||
|
||||
newRange = new ve.Range( this.range.start, this.range.end + ( depthChange * 2 ) );
|
||||
|
||||
tx = ve.dm.Transaction.newFromWrap( this.document, innerRange, unwrapper, wrapper, [], [] );
|
||||
this.surface.change( tx, !this.noAutoSelect && newRange );
|
||||
|
||||
this.range = newRange;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
|
|
@ -459,7 +459,7 @@ ve.dm.Transaction.newFromContentBranchConversion = function ( doc, range, type,
|
|||
*
|
||||
* @param {ve.dm.Document} doc Document to generate a transaction for
|
||||
* @param {ve.Range} range Range to wrap/unwrap/replace around
|
||||
* @param {Array} unwrapOuter Oopening elements to unwrap. These must be immediately *outside* the range.
|
||||
* @param {Array} unwrapOuter Opening elements to unwrap. These must be immediately *outside* the range.
|
||||
* @param {Array} wrapOuter Opening elements to wrap around the range.
|
||||
* @param {Array} unwrapEach Opening elements to unwrap from each top-level element in the range.
|
||||
* @param {Array} wrapEach Opening elements to wrap around each top-level element in the range.
|
||||
|
|
|
@ -255,6 +255,69 @@ QUnit.test( 'wrapAllNodes/unwrapAllNodes', 10, function ( assert ) {
|
|||
);
|
||||
});
|
||||
|
||||
QUnit.test( 'rewrapAllNodes', 6, function ( assert ) {
|
||||
var expectedData,
|
||||
doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
|
||||
surface = new ve.dm.Surface( doc ),
|
||||
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 5, 37 ) ),
|
||||
expectedDoc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
|
||||
expectedSurface = new ve.dm.Surface( expectedDoc ),
|
||||
expectedFragment = new ve.dm.SurfaceFragment( expectedSurface, new ve.Range( 5, 37 ) ),
|
||||
created = { 'changed': { 'created' : 1 } };
|
||||
|
||||
// Compare a rewrap operation with its equivalent unwrap + wrap
|
||||
// This type of test can only exist if the intermediate state is valid
|
||||
fragment.rewrapAllNodes(
|
||||
4,
|
||||
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
);
|
||||
expectedFragment.unwrapAllNodes( 4 );
|
||||
expectedFragment.wrapAllNodes(
|
||||
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
);
|
||||
assert.deepEqual(
|
||||
doc.getData(),
|
||||
expectedDoc.getData(),
|
||||
'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' );
|
||||
|
||||
// Reverse of first test
|
||||
fragment.rewrapAllNodes(
|
||||
2,
|
||||
[
|
||||
{ 'type': 'table', },
|
||||
{ 'type': 'tableSection', 'attributes': { 'style': 'body' } },
|
||||
{ 'type': 'tableRow' },
|
||||
{ 'type': 'tableCell', 'attributes': { 'style': 'data' } }
|
||||
]
|
||||
);
|
||||
|
||||
expectedData = ve.copyArray( ve.dm.example.data );
|
||||
expectedData[5].internal = created;
|
||||
expectedData[6].internal = created;
|
||||
expectedData[7].internal = created;
|
||||
expectedData[8].internal = created;
|
||||
assert.deepEqual(
|
||||
doc.getData(),
|
||||
expectedData,
|
||||
'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' );
|
||||
|
||||
// Rewrap a heading as a paragraph
|
||||
// The intermediate stage (plain text attached to the document) would be invalid
|
||||
// if performed as an unwrap and a wrap
|
||||
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 0, 5 ) );
|
||||
fragment.rewrapAllNodes( 1, [ { 'type': 'paragraph' } ] );
|
||||
|
||||
expectedData.splice( 0, 1, { 'type': 'paragraph', 'internal': created } );
|
||||
expectedData.splice( 4, 1, { 'type': '/paragraph' } );
|
||||
|
||||
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' );
|
||||
});
|
||||
|
||||
function runIsolateTest( assert, range, expected, label ) {
|
||||
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.isolationData ) ),
|
||||
surface = new ve.dm.Surface( doc ),
|
||||
|
|
Loading…
Reference in a new issue