8
0
فهرست منبع

Introduced model marker to view stapm conversion.

Oskar Wróbel 9 سال پیش
والد
کامیت
fd6aff923f

+ 27 - 36
packages/ckeditor5-engine/src/conversion/buildmodelconverter.js

@@ -152,8 +152,7 @@ class ModelConverterBuilder {
 	}
 
 	/**
-	 * Registers what type of non-collapsed marker should be converted. For collapsed markers conversion, see
-	 * {@link #fromCollapsedMarker}.
+	 * Registers what type of marker should be converted.
 	 *
 	 * @chainable
 	 * @param {String} markerName Name of marker to convert.
@@ -163,27 +162,7 @@ class ModelConverterBuilder {
 		this._from = {
 			type: 'marker',
 			name: markerName,
-			priority: null,
-			collapsed: false
-		};
-
-		return this;
-	}
-
-	/**
-	 * Registers what type of collapsed marker should be converted. For non-collapsed markers conversion,
-	 * see {@link #fromMarker}.
-	 *
-	 * @chainable
-	 * @param {String} markerName Name of marker to convert.
-	 * @returns {module:engine/conversion/buildmodelconverter~ModelConverterBuilder}
-	 */
-	fromCollapsedMarker( markerName ) {
-		this._from = {
-			type: 'marker',
-			name: markerName,
-			priority: null,
-			collapsed: true
+			priority: null
 		};
 
 		return this;
@@ -265,22 +244,35 @@ class ModelConverterBuilder {
 
 				dispatcher.on( 'selectionAttribute:' + this._from.key, convertSelectionAttribute( element ), { priority } );
 			} else {
-				if ( this._from.collapsed ) {
-					// From collapsed marker to view element -> insertUIElement, removeUIElement.
-					element = typeof element == 'string' ? new ViewUIElement( element ) : element;
+				element = typeof element == 'string' ? new ViewAttributeElement( element ) : element;
 
-					dispatcher.on( 'addMarker:' + this._from.name, insertUIElement( element ), { priority } );
-					dispatcher.on( 'removeMarker:' + this._from.name, removeUIElement( element ), { priority } );
-				} else {
-					// From non-collapsed marker to view element -> wrapRange and unwrapRange.
-					element = typeof element == 'string' ? new ViewAttributeElement( element ) : element;
+				dispatcher.on( 'addMarker:' + this._from.name, wrapRange( element ), { priority } );
+				dispatcher.on( 'removeMarker:' + this._from.name, unwrapRange( element ), { priority } );
 
-					dispatcher.on( 'addMarker:' + this._from.name, wrapRange( element ), { priority } );
-					dispatcher.on( 'removeMarker:' + this._from.name, unwrapRange( element ), { priority } );
+				dispatcher.on( 'selectionMarker:' + this._from.name, convertSelectionMarker( element ), { priority } );
+			}
+		}
+	}
 
-					dispatcher.on( 'selectionMarker:' + this._from.name, convertSelectionMarker( element ), { priority } );
-				}
+	toStamp( element ) {
+		for ( let dispatcher of this._dispatchers ) {
+			if ( this._from.type == 'element' || this._from.type == 'attribute' ) {
+				/**
+				 * To-stamp conversion is supported only for model markers.
+				 *
+				 * @error build-model-converter-element-to-stamp
+				 */
+				throw new CKEditorError(
+					'build-model-converter-non-marker-to-stamp: To-stamp conversion is supported only from model markers.'
+				);
 			}
+
+			const priority = this._from.priority === null ? 'normal' : this._from.priority;
+
+			element = typeof element == 'string' ? new ViewUIElement( element ) : element;
+
+			dispatcher.on( 'addMarker:' + this._from.name, insertUIElement( element ), { priority } );
+			dispatcher.on( 'removeMarker:' + this._from.name, removeUIElement( element ), { priority } );
 		}
 	}
 
@@ -321,7 +313,6 @@ class ModelConverterBuilder {
 			 * To-attribute conversion is supported only for model attributes.
 			 *
 			 * @error build-model-converter-element-to-attribute
-			 * @param {module:engine/model/range~Range} range
 			 */
 			throw new CKEditorError( 'build-model-converter-non-attribute-to-attribute: ' +
 				'To-attribute conversion is supported only from model attributes.' );

+ 102 - 24
packages/ckeditor5-engine/tests/conversion/buildmodelconverter.js

@@ -405,10 +405,22 @@ describe( 'Model converter builder', () => {
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
 		} );
+
+		it( 'should do nothing when marker range is collapsed', () => {
+			buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toElement( 'strong' );
+
+			dispatcher.convertMarker( 'addMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 2 ) );
+
+			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+
+			dispatcher.convertMarker( 'removeMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 2 ) );
+
+			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+		} );
 	} );
 
-	describe( 'model collapsed marker to view element conversion', () => {
-		let modelText, modelElement;
+	describe( 'model marker to view stamp conversion', () => {
+		let modelText, modelElement, range;
 
 		beforeEach( () => {
 			modelText = new ModelText( 'foobar' );
@@ -422,45 +434,99 @@ describe( 'Model converter builder', () => {
 			mapper.bindElements( modelElement, viewElement );
 		} );
 
-		it( 'using passed view element name', () => {
-			buildModelConverter().for( dispatcher ).fromCollapsedMarker( 'search' ).toElement( 'span' );
+		describe( 'collapsed range', () => {
+			beforeEach( () => {
+				range = ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 2 );
+			} );
 
-			dispatcher.convertMarker( 'addMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 3, modelElement, 3 ) );
+			it( 'using passed view element name', () => {
+				buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toStamp( 'span' );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foo<span></span>bar</p></div>' );
+				dispatcher.convertMarker( 'addMarker', 'search', range );
 
-			dispatcher.convertMarker( 'removeMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 3, modelElement, 3 ) );
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span></span>obar</p></div>' );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
+				dispatcher.convertMarker( 'removeMarker', 'search', range );
 
-		it( 'using passed view element', () => {
-			const viewElement = new ViewUIElement( 'span', { class: 'search' } );
-			buildModelConverter().for( dispatcher ).fromCollapsedMarker( 'search' ).toElement( viewElement );
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+			} );
 
-			dispatcher.convertMarker( 'addMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 3, modelElement, 3 ) );
+			it( 'using passed view element', () => {
+				const viewElement = new ViewUIElement( 'span', { class: 'search' } );
+				buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toStamp( viewElement );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foo<span class="search"></span>bar</p></div>' );
+				dispatcher.convertMarker( 'addMarker', 'search', range );
 
-			dispatcher.convertMarker( 'removeMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 3, modelElement, 3 ) );
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="search"></span>obar</p></div>' );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+				dispatcher.convertMarker( 'removeMarker', 'search', range );
+
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+			} );
+
+			it( 'using passed creator function', () => {
+				buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toStamp( ( data ) => {
+					const className = 'search search-color-' + data.name.split( ':' )[ 1 ];
+
+					return new ViewUIElement( 'span', { class: className } );
+				} );
+
+				dispatcher.convertMarker( 'addMarker', 'search:red', range );
+
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="search search-color-red"></span>obar</p></div>' );
+
+				dispatcher.convertMarker( 'removeMarker', 'search:red', range );
+
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+			} );
 		} );
 
-		it( 'using passed creator function', () => {
-			buildModelConverter().for( dispatcher ).fromCollapsedMarker( 'search' ).toElement( ( data ) => {
-				const className = 'search search-color-' + data.name.split( ':' )[ 1 ];
+		describe( 'non-collapsed range', () => {
+			beforeEach( () => {
+				range = ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 );
+			} );
+
+			it( 'using passed view element name', () => {
+				buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toStamp( 'span' );
+
+				dispatcher.convertMarker( 'addMarker', 'search', range );
 
-				return new ViewUIElement( 'span', { class: className } );
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span></span>ob<span></span>ar</p></div>' );
+
+				dispatcher.convertMarker( 'removeMarker', 'search', range );
+
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
 			} );
 
-			dispatcher.convertMarker( 'addMarker', 'search:red', ModelRange.createFromParentsAndOffsets( modelElement, 3, modelElement, 3 ) );
+			it( 'using passed view element', () => {
+				const viewElement = new ViewUIElement( 'span', { class: 'search' } );
+				buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toStamp( viewElement );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foo<span class="search search-color-red"></span>bar</p></div>' );
+				dispatcher.convertMarker( 'addMarker', 'search', range );
 
-			dispatcher.convertMarker( 'removeMarker', 'search:red', ModelRange.createFromParentsAndOffsets( modelElement, 3, modelElement, 3 ) );
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="search"></span>ob<span class="search"></span>ar</p></div>' );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+				dispatcher.convertMarker( 'removeMarker', 'search', range );
+
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+			} );
+
+			it( 'using passed creator function', () => {
+				buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toStamp( ( data ) => {
+					const className = 'search search-color-' + data.name.split( ':' )[ 1 ];
+
+					return new ViewUIElement( 'span', { class: className } );
+				} );
+
+				dispatcher.convertMarker( 'addMarker', 'search:red', range );
+
+				expect( viewToString( viewRoot ) )
+					.to.equal( '<div><p>fo<span class="search search-color-red"></span>ob<span class="search search-color-red"></span>ar</p></div>' );
+
+				dispatcher.convertMarker( 'removeMarker', 'search:red', range );
+
+				expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
+			} );
 		} );
 	} );
 
@@ -483,4 +549,16 @@ describe( 'Model converter builder', () => {
 			buildModelConverter().for( dispatcher ).fromElement( 'paragraph' ).toAttribute( 'paragraph', true );
 		} ).to.throw( CKEditorError, /^build-model-converter-non-attribute-to-attribute/ );
 	} );
+
+	it( 'should throw when trying to build model element to view stamp converter', () => {
+		expect( () => {
+			buildModelConverter().for( dispatcher ).fromElement( 'paragraph' ).toStamp( 'span' );
+		} ).to.throw( CKEditorError, /^build-model-converter-non-marker-to-stamp/ );
+	} );
+
+	it( 'should throw when trying to build model attribute to view stamp converter', () => {
+		expect( () => {
+			buildModelConverter().for( dispatcher ).fromAttribute( 'class' ).toStamp( 'span' );
+		} ).to.throw( CKEditorError, /^build-model-converter-non-marker-to-stamp/ );
+	} );
 } );