diff --git a/src/conversion/downcasthelpers.js b/src/conversion/downcasthelpers.js
index 97dc6e241..e8cc47832 100644
--- a/src/conversion/downcasthelpers.js
+++ b/src/conversion/downcasthelpers.js
@@ -444,10 +444,11 @@ export function createViewElementFromHighlightDescriptor( descriptor ) {
* The converter automatically consumes the corresponding value from the consumables list and stops the event (see
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).
*
- * modelDispatcher.on( 'attribute:bold', wrapItem( ( modelAttributeValue, viewWriter ) => {
+ * modelDispatcher.on( 'attribute:bold', wrap( ( modelAttributeValue, viewWriter ) => {
* return viewWriter.createAttributeElement( 'strong' );
* } );
*
+ * @protected
* @param {Function} elementCreator Function returning a view element that will be used for wrapping.
* @returns {Function} Set/change attribute converter.
*/
diff --git a/tests/conversion/downcast-selection-converters.js b/tests/conversion/downcast-selection-converters.js
index 719066914..fffc3e5d5 100644
--- a/tests/conversion/downcast-selection-converters.js
+++ b/tests/conversion/downcast-selection-converters.js
@@ -16,7 +16,7 @@ import {
clearAttributes,
} from '../../src/conversion/downcast-selection-converters';
-import DowncastHelpers, { insertText, wrap } from '../../src/conversion/downcasthelpers';
+import DowncastHelpers, { insertText } from '../../src/conversion/downcasthelpers';
import createViewRoot from '../view/_utils/createroot';
import { stringify as stringifyView } from '../../src/dev-utils/view';
@@ -45,10 +45,8 @@ describe( 'downcast-selection-converters', () => {
dispatcher.on( 'insert:$text', insertText() );
- const strongCreator = ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'strong' );
- dispatcher.on( 'attribute:bold', wrap( strongCreator ) );
-
downcastHelpers = new DowncastHelpers( dispatcher );
+ downcastHelpers.attributeToElement( { model: 'bold', view: 'strong' } );
downcastHelpers.markerToHighlight( { model: 'marker', view: { classes: 'marker' }, converterPriority: 1 } );
// Default selection converters.
diff --git a/tests/conversion/downcasthelpers.js b/tests/conversion/downcasthelpers.js
index 5912139a3..8be542608 100644
--- a/tests/conversion/downcasthelpers.js
+++ b/tests/conversion/downcasthelpers.js
@@ -20,7 +20,7 @@ import ViewText from '../../src/view/text';
import log from '@ckeditor/ckeditor5-utils/src/log';
import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
-import DowncastHelpers, { createViewElementFromHighlightDescriptor, wrap } from '../../src/conversion/downcasthelpers';
+import DowncastHelpers, { createViewElementFromHighlightDescriptor } from '../../src/conversion/downcasthelpers';
import { stringify } from '../../src/dev-utils/view';
@@ -107,6 +107,10 @@ describe( 'DowncastHelpers', () => {
} );
describe( 'attributeToElement()', () => {
+ beforeEach( () => {
+ downcastHelpers.elementToElement( { model: 'paragraph', view: 'p' } );
+ } );
+
it( 'should be chainable', () => {
expect( downcastHelpers.attributeToElement( { model: 'bold', view: 'strong' } ) ).to.equal( downcastHelpers );
} );
@@ -264,6 +268,143 @@ describe( 'DowncastHelpers', () => {
expect( viewToString( viewRoot ) ).to.equal( '
' );
} );
+
+ it( 'should convert insert/change/remove of attribute in model into wrapping element in a view', () => {
+ const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { bold: true } ) );
+
+ downcastHelpers.attributeToElement( {
+ model: 'bold',
+ view: ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'b' )
+ } );
+
+ model.change( writer => {
+ writer.insert( modelElement, modelRootStart );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+
+ model.change( writer => {
+ writer.removeAttribute( 'bold', writer.createRangeIn( modelElement ) );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+ } );
+
+ it( 'should convert insert/remove of attribute in model with wrapping element generating function as a parameter', () => {
+ const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { style: 'bold' } ) );
+
+ downcastHelpers.attributeToElement( {
+ model: 'style',
+ view: ( modelAttributeValue, viewWriter ) => {
+ if ( modelAttributeValue == 'bold' ) {
+ return viewWriter.createAttributeElement( 'b' );
+ }
+ }
+ } );
+
+ model.change( writer => {
+ writer.insert( modelElement, modelRootStart );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+
+ model.change( writer => {
+ writer.removeAttribute( 'style', writer.createRangeIn( modelElement ) );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+ } );
+
+ it( 'should update range on re-wrapping attribute (#475)', () => {
+ const modelElement = new ModelElement( 'paragraph', null, [
+ new ModelText( 'x' ),
+ new ModelText( 'foo', { link: 'http://foo.com' } ),
+ new ModelText( 'x' )
+ ] );
+
+ downcastHelpers.attributeToElement( {
+ model: 'link',
+ view: ( modelAttributeValue, viewWriter ) => {
+ return viewWriter.createAttributeElement( 'a', { href: modelAttributeValue } );
+ }
+ } );
+
+ model.change( writer => {
+ writer.insert( modelElement, modelRootStart );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+
+ // Set new attribute on old link but also on non-linked characters.
+ model.change( writer => {
+ writer.setAttribute( 'link', 'http://foobar.com', writer.createRangeIn( modelElement ) );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+ } );
+
+ it( 'should support unicode', () => {
+ const modelElement = new ModelElement( 'paragraph', null, [ 'நி', new ModelText( 'லைக்', { bold: true } ), 'கு' ] );
+
+ downcastHelpers.attributeToElement( {
+ model: 'bold',
+ view: ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'b' )
+ } );
+
+ model.change( writer => {
+ writer.insert( modelElement, modelRootStart );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+
+ model.change( writer => {
+ writer.removeAttribute( 'bold', writer.createRangeIn( modelElement ) );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+ } );
+
+ it( 'should be possible to override ', () => {
+ const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { bold: true } ) );
+
+ downcastHelpers.attributeToElement( {
+ model: 'bold',
+ view: ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'b' )
+ } );
+ downcastHelpers.attributeToElement( {
+ model: 'bold',
+ view: ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'strong' ),
+ converterPriority: 'high'
+ } );
+
+ model.change( writer => {
+ writer.insert( modelElement, modelRootStart );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+ } );
+
+ it( 'should not convert and not consume if creator function returned null', () => {
+ sinon.spy( controller.downcastDispatcher, 'fire' );
+
+ const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { italic: true } ) );
+
+ downcastHelpers.attributeToElement( {
+ model: 'italic',
+ view: () => null
+ } );
+
+ const spy = sinon.spy();
+ controller.downcastDispatcher.on( 'attribute:italic', spy );
+
+ model.change( writer => {
+ writer.insert( modelElement, modelRootStart );
+ } );
+
+ expect( viewToString( viewRoot ) ).to.equal( '' );
+ expect( controller.downcastDispatcher.fire.calledWith( 'attribute:italic:$text' ) ).to.be.true;
+ expect( spy.called ).to.be.true;
+ } );
} );
describe( 'attributeToAttribute()', () => {
@@ -1424,136 +1565,6 @@ describe( 'downcast-converters', () => {
} );
} );
- describe( 'wrap', () => {
- it( 'should convert insert/change/remove of attribute in model into wrapping element in a view', () => {
- const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { bold: true } ) );
- const creator = ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'b' );
-
- dispatcher.on( 'attribute:bold', wrap( creator ) );
-
- model.change( writer => {
- writer.insert( modelElement, modelRootStart );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
-
- model.change( writer => {
- writer.removeAttribute( 'bold', writer.createRangeIn( modelElement ) );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
- } );
-
- it( 'should convert insert/remove of attribute in model with wrapping element generating function as a parameter', () => {
- const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { style: 'bold' } ) );
-
- const elementGenerator = ( modelAttributeValue, viewWriter ) => {
- if ( modelAttributeValue == 'bold' ) {
- return viewWriter.createAttributeElement( 'b' );
- }
- };
-
- dispatcher.on( 'attribute:style', wrap( elementGenerator ) );
-
- model.change( writer => {
- writer.insert( modelElement, modelRootStart );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
-
- model.change( writer => {
- writer.removeAttribute( 'style', writer.createRangeIn( modelElement ) );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
- } );
-
- it( 'should update range on re-wrapping attribute (#475)', () => {
- const modelElement = new ModelElement( 'paragraph', null, [
- new ModelText( 'x' ),
- new ModelText( 'foo', { link: 'http://foo.com' } ),
- new ModelText( 'x' )
- ] );
-
- const elementGenerator = ( modelAttributeValue, viewWriter ) => {
- return viewWriter.createAttributeElement( 'a', { href: modelAttributeValue } );
- };
-
- dispatcher.on( 'attribute:link', wrap( elementGenerator ) );
-
- model.change( writer => {
- writer.insert( modelElement, modelRootStart );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
-
- // Set new attribute on old link but also on non-linked characters.
- model.change( writer => {
- writer.setAttribute( 'link', 'http://foobar.com', writer.createRangeIn( modelElement ) );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
- } );
-
- it( 'should support unicode', () => {
- const modelElement = new ModelElement( 'paragraph', null, [ 'நி', new ModelText( 'லைக்', { bold: true } ), 'கு' ] );
- const creator = ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'b' );
-
- dispatcher.on( 'attribute:bold', wrap( creator ) );
-
- model.change( writer => {
- writer.insert( modelElement, modelRootStart );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
-
- model.change( writer => {
- writer.removeAttribute( 'bold', writer.createRangeIn( modelElement ) );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
- } );
-
- it( 'should be possible to override wrap', () => {
- const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { bold: true } ) );
-
- dispatcher.on( 'attribute:bold', wrap( ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'b' ) ) );
-
- dispatcher.on(
- 'attribute:bold',
- wrap( ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'strong' ) ),
- { priority: 'high' }
- );
-
- model.change( writer => {
- writer.insert( modelElement, modelRootStart );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
- } );
-
- it( 'should not convert and not consume if creator function returned null', () => {
- const elementGenerator = () => null;
-
- sinon.spy( dispatcher, 'fire' );
-
- const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar', { italic: true } ) );
-
- dispatcher.on( 'attribute:italic', wrap( elementGenerator ) );
-
- const spy = sinon.spy();
- dispatcher.on( 'attribute:italic', spy );
-
- model.change( writer => {
- writer.insert( modelElement, modelRootStart );
- } );
-
- expect( viewToString( viewRoot ) ).to.equal( '' );
- expect( dispatcher.fire.calledWith( 'attribute:italic:$text' ) ).to.be.true;
- expect( spy.called ).to.be.true;
- } );
- } );
-
// Remove converter is by default already added in `EditingController` instance.
describe( 'remove', () => {
it( 'should remove items from view accordingly to changes in model #1', () => {