8
0
Просмотр исходного кода

Replaced render event listener with view postfixer.

Szymon Kupś 8 лет назад
Родитель
Сommit
6323c9df11
1 измененных файлов с 59 добавлено и 275 удалено
  1. 59 275
      packages/ckeditor5-image/src/imagecaption/imagecaptionengine.js

+ 59 - 275
packages/ckeditor5-image/src/imagecaption/imagecaptionengine.js

@@ -79,8 +79,8 @@ export default class ImageCaptionEngine extends Plugin {
 		// Hide caption when everything is removed from it.
 		editing.downcastDispatcher.on( 'remove', this._fixCaptionVisibility( data => data.position.parent ), { priority: 'high' } );
 
-		// Update view before each rendering.
-		this.listenTo( view.document.selection, 'change', () => this._updateCaptionVisibility( view ) );
+		// Update caption visibility on view in post fixer.
+		view.document.registerPostFixer( writer => this._updateCaptionVisibility( writer ) );
 	}
 
 	/**
@@ -88,18 +88,14 @@ export default class ImageCaptionEngine extends Plugin {
 	 * and then visible when the image is selected.
 	 *
 	 * @private
+	 * @param {module:engine/view/writer~Writer} viewWriter
+	 * @returns {Boolean} Returns `true` when view is updated.
 	 */
-	_updateCaptionVisibility( view ) {
+	_updateCaptionVisibility( viewWriter ) {
 		const mapper = this.editor.editing.mapper;
+		const lastCaption = this._lastSelectedCaption;
 		let viewCaption;
 
-		// Hide last selected caption if have no child elements.
-		if ( this._lastSelectedCaption && !this._lastSelectedCaption.childCount ) {
-			if ( !this._lastSelectedCaption.hasClass( 'ck-hidden' ) ) {
-				view.change( writer => writer.addClass( 'ck-hidden', this._lastSelectedCaption ) );
-			}
-		}
-
 		// If whole image is selected.
 		const modelSelection = this.editor.model.document.selection;
 		const selectedElement = modelSelection.getSelectedElement();
@@ -117,11 +113,32 @@ export default class ImageCaptionEngine extends Plugin {
 			viewCaption = mapper.toViewElement( modelCaption );
 		}
 
+		// Is currently any caption selected?
 		if ( viewCaption ) {
-			this._lastSelectedCaption = viewCaption;
-
-			if ( viewCaption.hasClass( 'ck-hidden' ) ) {
-				view.change( writer => writer.removeClass( 'ck-hidden', viewCaption ) );
+			// Was any caption selected before?
+			if ( lastCaption ) {
+				// Same caption as before?
+				if ( lastCaption === viewCaption ) {
+					return showCaption( viewCaption, viewWriter );
+				} else {
+					hideCaptionIfEmpty( lastCaption, viewWriter );
+					this._lastSelectedCaption = viewCaption;
+
+					return showCaption( viewCaption, viewWriter );
+				}
+			} else {
+				this._lastSelectedCaption = viewCaption;
+				return showCaption( viewCaption, viewWriter );
+			}
+		} else {
+			// Was any caption selected before?
+			if ( lastCaption ) {
+				const viewModified = hideCaptionIfEmpty( lastCaption, viewWriter );
+				this._lastSelectedCaption = null;
+
+				return viewModified;
+			} else {
+				return false;
 			}
 		}
 	}
@@ -135,10 +152,7 @@ export default class ImageCaptionEngine extends Plugin {
 	 * @returns {Function}
 	 */
 	_fixCaptionVisibility( nodeFinder ) {
-		return ( evt, data, consumable, conversionApi ) => {
-			// There is no consumable on 'remove' event.
-			conversionApi = conversionApi ? conversionApi : consumable;
-
+		return ( evt, data, conversionApi ) => {
 			const node = nodeFinder( data );
 			const modelCaption = getParentCaption( node );
 			const mapper = this.editor.editing.mapper;
@@ -248,262 +262,32 @@ function getParentCaption( node ) {
 	return null;
 }
 
+// Hides given caption in the view if it's empty.
 //
-// /**
-//  * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
-//  * For licensing, see LICENSE.md.
-//  */
-//
-// /**
-//  * @module image/imagecaption/imagecaptionengine
-//  */
-//
-// import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-// import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
-// import { upcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
-// import { isImage } from '../image/utils';
-// import {
-// 	captionElementCreator,
-// 	getCaptionFromImage,
-// 	matchImageCaption
-// } from './utils';
-//
-// /**
-//  * The image caption engine plugin.
-//  *
-//  * It registers proper converters. It takes care of adding a caption element if the image without it is inserted
-//  * to the model document.
-//  *
-//  * @extends module:core/plugin~Plugin
-//  */
-// export default class ImageCaptionEngine extends Plugin {
-// 	/**
-// 	 * @inheritDoc
-// 	 */
-// 	init() {
-// 		const editor = this.editor;
-// 		const view = editor.editing.view;
-// 		const schema = editor.model.schema;
-// 		const data = editor.data;
-// 		const editing = editor.editing;
-// 		const t = editor.t;
-//
-// 		/**
-// 		 * Last selected caption editable.
-// 		 * It is used for hiding the editable when it is empty and the image widget is no longer selected.
-// 		 *
-// 		 * @private
-// 		 * @member {module:engine/view/editableelement~EditableElement} #_lastSelectedCaption
-// 		 */
-//
-// 		// Schema configuration.
-// 		schema.register( 'caption', {
-// 			allowIn: 'image',
-// 			allowContentOf: '$block',
-// 			isLimit: true
-// 		} );
-//
-// 		// Add caption element to each image inserted without it.
-// 		editor.model.document.registerPostFixer( writer => this._insertMissingModelCaptionElement( writer ) );
-//
-// 		// View to model converter for the data pipeline.
-// 		editor.conversion.for( 'upcast' ).add( upcastElementToElement( {
-// 			view: matchImageCaption,
-// 			model: 'caption'
-// 		} ) );
-//
-// 		// Model to view converter for the data pipeline.
-// 		const createCaptionForData = writer => writer.createContainerElement( 'figcaption' );
-// 		data.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForData, false ) );
-//
-// 		// Model to view converter for the editing pipeline.
-// 		const createCaptionForEditing = captionElementCreator( view, t( 'Enter image caption' ) );
-// 		editing.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForEditing ) );
-//
-// 		// Always show caption in view when something is inserted in model.
-// 		editing.downcastDispatcher.on(
-// 			'insert',
-// 			this._fixCaptionVisibility( data => data.item ),
-// 			{ priority: 'high' }
-// 		);
-//
-// 		// Hide caption when everything is removed from it.
-// 		editing.downcastDispatcher.on( 'remove', this._fixCaptionVisibility( data => data.position.parent ), { priority: 'high' } );
-//
-// 		// Update caption visibility on view in post fixer.
-// 		view.document.registerPostFixer( writer => this._updateCaptionVisibility( writer ) );
-// 	}
-//
-// 	/**
-// 	 * Updates the view before each rendering, making sure that empty captions (so unnecessary ones) are hidden
-// 	 * and then visible when the image is selected.
-// 	 *
-// 	 * @private
-// 	 * @param {module:engine/view/writer~Writer} viewWriter
-// 	 * @returns {Boolean} Returns `true` when view is updated.
-// 	 */
-// 	_updateCaptionVisibility( viewWriter ) {
-// 		const mapper = this.editor.editing.mapper;
-// 		const lastCaption = this._lastSelectedCaption;
-// 		let viewChanged = false;
-// 		let viewCaption;
-//
-// 		// If whole image is selected.
-// 		const modelSelection = this.editor.model.document.selection;
-// 		const selectedElement = modelSelection.getSelectedElement();
-//
-// 		if ( selectedElement && selectedElement.is( 'image' ) ) {
-// 			const modelCaption = getCaptionFromImage( selectedElement );
-// 			viewCaption = mapper.toViewElement( modelCaption );
-// 		}
-//
-// 		// If selection is placed inside caption.
-// 		const position = modelSelection.getFirstPosition();
-// 		const modelCaption = getParentCaption( position.parent );
-//
-// 		if ( modelCaption ) {
-// 			viewCaption = mapper.toViewElement( modelCaption );
-// 		}
-//
-// 		// No changes if same caption is selected as previously.
-// 		if ( !viewCaption || viewCaption == lastCaption ) {
-// 			return false;
-// 		}
-//
-// 		// Hide last selected caption if empty
-// 		if ( lastCaption && !lastCaption.childCount && !lastCaption.hasClass( 'ck-hidden' ) ) {
-// 			viewWriter.addClass( 'ck-hidden', lastCaption );
-// 			viewChanged = true;
-// 		}
-//
-// 		this._lastSelectedCaption = viewCaption;
-//
-// 		if ( viewCaption.hasClass( 'ck-hidden' ) ) {
-// 			viewWriter.removeClass( 'ck-hidden', viewCaption );
-// 			viewChanged = true;
-// 		}
-//
-// 		return viewChanged;
-// 	}
-//
-// 	/**
-// 	 * Returns converter that fixes caption visibility during the model-to-view conversion.
-// 	 * Checks if the changed node is placed inside the caption element and fixes its visibility in the view.
-// 	 *
-// 	 * @private
-// 	 * @param {Function} nodeFinder
-// 	 * @returns {Function}
-// 	 */
-// 	_fixCaptionVisibility( nodeFinder ) {
-// 		return ( evt, data, consumable, conversionApi ) => {
-// 			// There is no consumable on 'remove' event.
-// 			conversionApi = conversionApi ? conversionApi : consumable;
-//
-// 			const node = nodeFinder( data );
-// 			const modelCaption = getParentCaption( node );
-// 			const mapper = this.editor.editing.mapper;
-// 			const viewWriter = conversionApi.writer;
-//
-// 			if ( modelCaption ) {
-// 				const viewCaption = mapper.toViewElement( modelCaption );
-//
-// 				if ( viewCaption ) {
-// 					if ( modelCaption.childCount ) {
-// 						viewWriter.removeClass( 'ck-hidden', viewCaption );
-// 					} else {
-// 						viewWriter.addClass( 'ck-hidden', viewCaption );
-// 					}
-// 				}
-// 			}
-// 		};
-// 	}
-//
-// 	/**
-// 	 * Checks whether data inserted to the model document have image element that has no caption element inside it.
-// 	 * If there is none - adds it to the image element.
-// 	 *
-// 	 * @private
-// 	 * @param {module:engine/model/writer~Writer} writer Writer to make changes with.
-// 	 * @returns {Boolean} `true` if any change has been applied, `false` otherwise.
-// 	 */
-// 	_insertMissingModelCaptionElement( writer ) {
-// 		const model = this.editor.model;
-// 		const changes = model.document.differ.getChanges();
-//
-// 		for ( const entry of changes ) {
-// 			if ( entry.type == 'insert' && entry.name == 'image' ) {
-// 				const item = entry.position.nodeAfter;
-//
-// 				if ( !getCaptionFromImage( item ) ) {
-// 					writer.appendElement( 'caption', item );
-//
-// 					return true;
-// 				}
-// 			}
-// 		}
-// 	}
-// }
-//
-// // Creates a converter that converts image caption model element to view element.
-// //
-// // @private
-// // @param {Function} elementCreator
-// // @param {Boolean} [hide=true] When set to `false` view element will not be inserted when it's empty.
-// // @return {Function}
-// function captionModelToView( elementCreator, hide = true ) {
-// 	return ( evt, data, conversionApi ) => {
-// 		const captionElement = data.item;
-//
-// 		// Return if element shouldn't be present when empty.
-// 		if ( !captionElement.childCount && !hide ) {
-// 			return;
-// 		}
-//
-// 		if ( isImage( captionElement.parent ) ) {
-// 			if ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {
-// 				return;
-// 			}
-//
-// 			const viewImage = conversionApi.mapper.toViewElement( data.range.start.parent );
-// 			const viewCaption = elementCreator( conversionApi.writer );
-// 			const viewWriter = conversionApi.writer;
-//
-// 			// Hide if empty.
-// 			if ( !captionElement.childCount ) {
-// 				viewWriter.addClass( 'ck-hidden', viewCaption );
-// 			}
-//
-// 			insertViewCaptionAndBind( viewCaption, data.item, viewImage, conversionApi );
-// 		}
-// 	};
-// }
-//
-// // Inserts `viewCaption` at the end of `viewImage` and binds it to `modelCaption`.
-// //
-// // @private
-// // @param {module:engine/view/containerelement~ContainerElement} viewCaption
-// // @param {module:engine/model/element~Element} modelCaption
-// // @param {module:engine/view/containerelement~ContainerElement} viewImage
-// // @param {Object} conversionApi
-// function insertViewCaptionAndBind( viewCaption, modelCaption, viewImage, conversionApi ) {
-// 	const viewPosition = ViewPosition.createAt( viewImage, 'end' );
-//
-// 	conversionApi.writer.insert( viewPosition, viewCaption );
-// 	conversionApi.mapper.bindElements( modelCaption, viewCaption );
-// }
-//
-// // Checks if the provided node or one of its ancestors is a caption element, and returns it.
-// //
-// // @private
-// // @param {module:engine/model/node~Node} node
-// // @returns {module:engine/model/element~Element|null}
-// function getParentCaption( node ) {
-// 	const ancestors = node.getAncestors( { includeSelf: true } );
-// 	const caption = ancestors.find( ancestor => ancestor.name == 'caption' );
-//
-// 	if ( caption && caption.parent && caption.parent.name == 'image' ) {
-// 		return caption;
-// 	}
+// @private
+// @param {module:engine/view/containerelement~ContainerElement} caption
+// @param {module:engine/view/writer~Writer} viewWriter
+// @returns {Boolean} Returns `true` if view was modified.
+function hideCaptionIfEmpty( caption, viewWriter ) {
+	if ( !caption.childCount && !caption.hasClass( 'ck-hidden' ) ) {
+		viewWriter.addClass( 'ck-hidden', caption );
+		return true;
+	}
+
+	return false;
+}
+
+// Shows the caption
 //
-// 	return null;
-// }
+// @private
+// @param {module:engine/view/containerelement~ContainerElement} caption
+// @param {module:engine/view/writer~Writer} viewWriter
+// @returns {Boolean} Returns `true` if view was modified.
+function showCaption( caption, viewWriter ) {
+	if ( caption.hasClass( 'ck-hidden' ) ) {
+		viewWriter.removeClass( 'ck-hidden', caption );
+		return true;
+	}
+
+	return false;
+}