mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-28 00:00:49 +00:00
ve.dm.SurfaceFragment: Implement wrapNodes and wrapAllNodes
Change-Id: I378f0aad0286a6c90adeb4602a57d6617154e8b6
This commit is contained in:
parent
8a725f8f92
commit
eabe5e6f61
|
@ -75,6 +75,7 @@ class VisualEditorHooks {
|
|||
'dm/ve.dm.Transaction.test.js',
|
||||
'dm/ve.dm.TransactionProcessor.test.js',
|
||||
'dm/ve.dm.Surface.test.js',
|
||||
'dm/ve.dm.SurfaceFragment.test.js',
|
||||
// VisualEditor ContentEditable Tests
|
||||
'ce/ve.ce.test.js',
|
||||
'ce/ve.ce.Document.test.js',
|
||||
|
|
|
@ -169,6 +169,7 @@ $wgResourceModules += array(
|
|||
've/dm/ve.dm.TransactionProcessor.js',
|
||||
've/dm/ve.dm.Transaction.js',
|
||||
've/dm/ve.dm.Surface.js',
|
||||
've/dm/ve.dm.SurfaceFragment.js',
|
||||
've/dm/ve.dm.Document.js',
|
||||
've/dm/ve.dm.DocumentSynchronizer.js',
|
||||
've/dm/ve.dm.Converter.js',
|
||||
|
|
|
@ -460,6 +460,13 @@ ve.dm.SurfaceFragment.prototype.convertNodes = function ( type, attr ) {
|
|||
* A wrapper object is a linear model element; a plain object containing a type property and an
|
||||
* optional attributes property.
|
||||
*
|
||||
* Example:
|
||||
* // fragment is a selection of: <p>a</p><p>b</p>
|
||||
* fragment.wrapNodes(
|
||||
* [{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
* )
|
||||
* // fragment is now a selection of: <ul><li><p>a</p></li></ul><ul><li><p>b</p></li></ul>
|
||||
*
|
||||
* @method
|
||||
* @param {Object|Object[]} wrapper Wrapper object, or array of wrapper objects (see above)
|
||||
* @param {String} wrapper.type Node type of wrapper
|
||||
|
@ -471,7 +478,12 @@ ve.dm.SurfaceFragment.prototype.wrapNodes = function ( wrapper ) {
|
|||
if ( !this.surface ) {
|
||||
return this;
|
||||
}
|
||||
// TODO: Implement
|
||||
if ( !ve.isArray( wrapper ) ) {
|
||||
wrapper = [wrapper];
|
||||
}
|
||||
var tx = ve.dm.Transaction.newFromWrap( this.document, this.range, [], [], [], wrapper );
|
||||
this.range = tx.translateRange( this.range );
|
||||
this.surface.change( tx, this.autoSelect && this.range );
|
||||
return this;
|
||||
};
|
||||
|
||||
|
@ -519,6 +531,13 @@ ve.dm.SurfaceFragment.prototype.rewrapNodes = function ( type, wrapper ) {
|
|||
* A wrapper object is a linear model element; a plain object containing a type property and an
|
||||
* optional attributes property.
|
||||
*
|
||||
* Example:
|
||||
* // fragment is a selection of: <p>a</p><p>b</p>
|
||||
* fragment.wrapAllNodes(
|
||||
* [{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
* )
|
||||
* // fragment is now a selection of: <ul><li><p>a</p><p>b</p></li></ul>
|
||||
*
|
||||
* @method
|
||||
* @param {Object|Object[]} wrapper Wrapper object, or array of wrapper objects (see above)
|
||||
* @param {String} wrapper.type Node type of wrapper
|
||||
|
@ -530,7 +549,12 @@ ve.dm.SurfaceFragment.prototype.wrapAllNodes = function ( wrapper ) {
|
|||
if ( !this.surface ) {
|
||||
return this;
|
||||
}
|
||||
// TODO: Implement
|
||||
if ( !ve.isArray( wrapper ) ) {
|
||||
wrapper = [wrapper];
|
||||
}
|
||||
var tx = ve.dm.Transaction.newFromWrap( this.document, this.range, [], wrapper, [], [] );
|
||||
this.range = tx.translateRange( this.range );
|
||||
this.surface.change( tx, this.autoSelect && this.range );
|
||||
return this;
|
||||
};
|
||||
|
||||
|
|
|
@ -112,3 +112,95 @@ QUnit.test( 'insertContent', 3, function ( assert ) {
|
|||
'strings get converted into data when inserting content'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'wrapNodes', 2, function ( assert ) {
|
||||
var doc = new ve.dm.Document( ve.dm.example.data ),
|
||||
surface = new ve.dm.Surface( doc ),
|
||||
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 55, 61 ) );
|
||||
// Make 2 paragraphs into 2 lists of 1 item each
|
||||
fragment.wrapNodes(
|
||||
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
);
|
||||
assert.deepEqual(
|
||||
doc.getData( new ve.Range( 55, 69 ) ),
|
||||
[
|
||||
{ 'type': 'list', 'attributes': { 'style': 'bullet' } },
|
||||
{ 'type': 'listItem' },
|
||||
{ 'type': 'paragraph' },
|
||||
'l',
|
||||
{ 'type': '/paragraph' },
|
||||
{ 'type': '/listItem' },
|
||||
{ 'type': '/list' },
|
||||
{ 'type': 'list', 'attributes': { 'style': 'bullet' } },
|
||||
{ 'type': 'listItem' },
|
||||
{ 'type': 'paragraph' },
|
||||
'm',
|
||||
{ 'type': '/paragraph' },
|
||||
{ 'type': '/listItem' },
|
||||
{ 'type': '/list' }
|
||||
],
|
||||
'wrapping nodes can add multiple levels of wrapping to multiple elements'
|
||||
);
|
||||
// Make a 1 paragraph into 1 list with 1 item
|
||||
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 9, 12 ) );
|
||||
fragment.wrapNodes(
|
||||
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
);
|
||||
assert.deepEqual(
|
||||
doc.getData( new ve.Range( 9, 16 ) ),
|
||||
[
|
||||
{ 'type': 'list', 'attributes': { 'style': 'bullet' } },
|
||||
{ 'type': 'listItem' },
|
||||
{ 'type': 'paragraph' },
|
||||
'd',
|
||||
{ 'type': '/paragraph' },
|
||||
{ 'type': '/listItem' },
|
||||
{ 'type': '/list' }
|
||||
],
|
||||
'wrapping nodes can add multiple levels of wrapping to a single element'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'wrapAllNodes', 2, function ( assert ) {
|
||||
var doc = new ve.dm.Document( ve.dm.example.data ),
|
||||
surface = new ve.dm.Surface( doc ),
|
||||
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 55, 61 ) );
|
||||
// Make 2 paragraphs into 1 lists of 1 item with 2 paragraphs
|
||||
fragment.wrapAllNodes(
|
||||
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
);
|
||||
assert.deepEqual(
|
||||
doc.getData( new ve.Range( 55, 65 ) ),
|
||||
[
|
||||
{ 'type': 'list', 'attributes': { 'style': 'bullet' } },
|
||||
{ 'type': 'listItem' },
|
||||
{ 'type': 'paragraph' },
|
||||
'l',
|
||||
{ 'type': '/paragraph' },
|
||||
{ 'type': 'paragraph' },
|
||||
'm',
|
||||
{ 'type': '/paragraph' },
|
||||
{ 'type': '/listItem' },
|
||||
{ 'type': '/list' }
|
||||
],
|
||||
'wrapping nodes can add multiple levels of wrapping to multiple elements'
|
||||
);
|
||||
// Make a 1 paragraph into 1 list with 1 item
|
||||
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 9, 12 ) );
|
||||
fragment.wrapAllNodes(
|
||||
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
|
||||
);
|
||||
assert.deepEqual(
|
||||
doc.getData( new ve.Range( 9, 16 ) ),
|
||||
[
|
||||
{ 'type': 'list', 'attributes': { 'style': 'bullet' } },
|
||||
{ 'type': 'listItem' },
|
||||
{ 'type': 'paragraph' },
|
||||
'd',
|
||||
{ 'type': '/paragraph' },
|
||||
{ 'type': '/listItem' },
|
||||
{ 'type': '/list' }
|
||||
],
|
||||
'wrapping nodes can add multiple levels of wrapping to a single element'
|
||||
);
|
||||
} );
|
||||
|
|
Loading…
Reference in a new issue