Răsfoiți Sursa

Merge branch 'master' into t/78

Szymon Kupś 8 ani în urmă
părinte
comite
9575b17cd1

+ 49 - 1
packages/ckeditor5-image/src/imagecaption/imagecaptionengine.js

@@ -42,7 +42,6 @@ export default class ImageCaptionEngine extends Plugin {
 		const schema = document.schema;
 		const data = editor.data;
 		const editing = editor.editing;
-
 		/**
 		 * Last selected caption editable.
 		 * It is used for hiding editable when is empty and image widget is no longer selected.
@@ -51,6 +50,8 @@ export default class ImageCaptionEngine extends Plugin {
 		 * @member {module:engine/view/editableelement~EditableElement} #_lastSelectedCaption
 		 */
 
+		this._viewCaptionsToUpdate = [];
+
 		/**
 		 * Function used to create editable caption element in the editing view.
 		 *
@@ -80,6 +81,12 @@ export default class ImageCaptionEngine extends Plugin {
 		// Model to view converter for the editing pipeline.
 		editing.modelToView.on( 'insert:caption', captionModelToView( this._createCaption ) );
 
+		// Always show caption in view when something is inserted in model.
+		editing.modelToView.on( 'insert', ( evt, data ) => this._fixCaptionVisibility( data.item ), { priority: 'high' } );
+
+		// Hide caption when everything is removed from it.
+		editing.modelToView.on( 'remove', ( evt, data ) => this._fixCaptionVisibility( data.sourcePosition.parent ), { priority: 'high' } );
+
 		// Update view before each rendering.
 		this.listenTo( viewDocument, 'render', () => this._updateCaptionVisibility(), { priority: 'high' } );
 	}
@@ -118,6 +125,30 @@ export default class ImageCaptionEngine extends Plugin {
 			this._lastSelectedCaption = viewCaption;
 		}
 	}
+
+	/**
+	 * Fixes caption visibility during model to view conversion.
+	 * Checks if changed node is placed inside caption element and fixes it's visibility in the view.
+	 *
+	 * @private
+	 * @param {module:engine/model/node~Node} node
+	 */
+	_fixCaptionVisibility( node ) {
+		const modelCaption = getParentCaption( node );
+		const mapper = this.editor.editing.mapper;
+
+		if ( modelCaption ) {
+			const viewCaption = mapper.toViewElement( modelCaption );
+
+			if ( viewCaption ) {
+				if ( modelCaption.childCount ) {
+					viewCaption.removeClass( 'ck-hidden' );
+				} else {
+					viewCaption.addClass( 'ck-hidden' );
+				}
+			}
+		}
+	}
 }
 
 // Checks whether data inserted to the model document have image element that has no caption element inside it.
@@ -196,3 +227,20 @@ function insertViewCaptionAndBind( viewCaption, modelCaption, viewImage, mapper
 	viewWriter.insert( viewPosition, viewCaption );
 	mapper.bindElements( modelCaption, viewCaption );
 }
+
+/**
+ * Checks if provided node or one of its ancestors is caption element and returns it.
+ *
+ * @param {module:engine/model/node~Node} node
+ * @returns {module:engine/model/element~Element|null}
+ */
+function getParentCaption( node ) {
+	const ancestors = node.getAncestors( { includeNode: true } );
+	const caption = ancestors.find( ancestor => ancestor.name == 'caption' );
+
+	if ( caption && caption.parent && caption.parent.name == 'image' ) {
+		return caption;
+	}
+
+	return null;
+}

+ 55 - 1
packages/ckeditor5-image/tests/imagecaption/imagecaptionengine.js

@@ -80,7 +80,7 @@ describe( 'ImageCaptionEngine', () => {
 				expect( editor.getData() ).to.equal( '<figure class="image"><img src="img.png"><figcaption>Foo bar baz.</figcaption></figure>' );
 			} );
 
-			it( 'should convert caption to figcaption with hidden class if it\'s empty', () => {
+			it( 'should not convert caption to figcaption if it\'s empty', () => {
 				setModelData( document, '<image src="img.png"><caption></caption></image>' );
 
 				expect( editor.getData() ).to.equal( '<figure class="image"><img src="img.png"></figure>' );
@@ -144,6 +144,60 @@ describe( 'ImageCaptionEngine', () => {
 					'<figure class="image ck-widget" contenteditable="false"><img src="img.png"></img><span></span>Foo bar baz.</figure>'
 				);
 			} );
+
+			it( 'should show caption when something is inserted inside', () => {
+				setModelData( document, '<image src="img.png"><caption></caption></image>' );
+				const image = document.getRoot().getChild( 0 );
+				const caption = image.getChild( 0 );
+
+				document.enqueueChanges( () => {
+					const batch = document.batch();
+					batch.insert( ModelPosition.createAt( caption ), 'foo bar' );
+				} );
+
+				expect( getViewData( viewDocument ) ).to.equal(
+					'[]<figure class="image ck-widget" contenteditable="false">' +
+						'<img src="img.png"></img>' +
+						'<figcaption class="ck-editable" contenteditable="true">foo bar</figcaption>' +
+					'</figure>'
+				);
+			} );
+
+			it( 'should hide when everything is removed from caption', () => {
+				setModelData( document, '<image src="img.png"><caption>foo bar baz</caption></image>' );
+				const image = document.getRoot().getChild( 0 );
+				const caption = image.getChild( 0 );
+
+				document.enqueueChanges( () => {
+					const batch = document.batch();
+					batch.remove( ModelRange.createIn( caption ) );
+				} );
+
+				expect( getViewData( viewDocument ) ).to.equal(
+					'[]<figure class="image ck-widget" contenteditable="false">' +
+					'<img src="img.png"></img>' +
+					'<figcaption class="ck-editable ck-hidden" contenteditable="true"></figcaption>' +
+					'</figure>'
+				);
+			} );
+
+			it( 'should show when not everything is removed from caption', () => {
+				setModelData( document, '<image src="img.png"><caption>foo bar baz</caption></image>' );
+				const image = document.getRoot().getChild( 0 );
+				const caption = image.getChild( 0 );
+
+				document.enqueueChanges( () => {
+					const batch = document.batch();
+					batch.remove( ModelRange.createFromParentsAndOffsets( caption, 0, caption, 8 ) );
+				} );
+
+				expect( getViewData( viewDocument ) ).to.equal(
+					'[]<figure class="image ck-widget" contenteditable="false">' +
+					'<img src="img.png"></img>' +
+					'<figcaption class="ck-editable" contenteditable="true">baz</figcaption>' +
+					'</figure>'
+				);
+			} );
 		} );
 	} );