瀏覽代碼

Internal: Introduced automatic marker re-rendering during conversion for markers which view element was unbound.

Szymon Cofalik 6 年之前
父節點
當前提交
9acb2edeed

+ 1 - 1
packages/ckeditor5-engine/src/controller/editingcontroller.js

@@ -87,7 +87,7 @@ export default class EditingController {
 		// Also convert model selection.
 		this.listenTo( doc, 'change', () => {
 			this.view.change( writer => {
-				this.downcastDispatcher.convertChanges( doc.differ, writer );
+				this.downcastDispatcher.convertChanges( doc.differ, markers, writer );
 				this.downcastDispatcher.convertSelection( selection, markers, writer );
 			} );
 		}, { priority: 'low' } );

+ 13 - 3
packages/ckeditor5-engine/src/conversion/downcastdispatcher.js

@@ -109,7 +109,7 @@ export default class DowncastDispatcher {
 	 * @param {Object} [conversionApi] Additional properties for interface that will be passed to events fired
 	 * by `DowncastDispatcher`.
 	 */
-	constructor( conversionApi = {} ) {
+	constructor( conversionApi ) {
 		/**
 		 * Interface passed by dispatcher to the events callbacks.
 		 *
@@ -122,9 +122,10 @@ export default class DowncastDispatcher {
 	 * Takes {@link module:engine/model/differ~Differ model differ} object with buffered changes and fires conversion basing on it.
 	 *
 	 * @param {module:engine/model/differ~Differ} differ Differ object with buffered changes.
+	 * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model.
 	 * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.
 	 */
-	convertChanges( differ, writer ) {
+	convertChanges( differ, markers, writer ) {
 		// Before the view is updated, remove markers which have changed.
 		for ( const change of differ.getMarkersToRemove() ) {
 			this.convertMarkerRemove( change.name, change.range, writer );
@@ -142,6 +143,15 @@ export default class DowncastDispatcher {
 			}
 		}
 
+		for ( const markerName of this.conversionApi.mapper._unboundMarkers ) {
+			const markerRange = markers.get( markerName ).getRange();
+
+			this.convertMarkerRemove( markerName, markerRange, writer );
+			this.convertMarkerAdd( markerName, markerRange, writer );
+		}
+
+		this.conversionApi.mapper._unboundMarkers.clear();
+
 		// After the view is updated, convert markers which have changed.
 		for ( const change of differ.getMarkersToAdd() ) {
 			this.convertMarkerAdd( change.name, change.range, writer );
@@ -252,7 +262,7 @@ export default class DowncastDispatcher {
 	 * @fires addMarker
 	 * @fires attribute
 	 * @param {module:engine/model/selection~Selection} selection Selection to convert.
-	 * @param {Array.<module:engine/model/markercollection~Marker>} markers Array of markers containing model markers.
+	 * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model.
 	 * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.
 	 */
 	convertSelection( selection, markers, writer ) {

+ 34 - 8
packages/ckeditor5-engine/tests/conversion/downcastdispatcher.js

@@ -4,6 +4,8 @@
  */
 
 import DowncastDispatcher from '../../src/conversion/downcastdispatcher';
+import Mapper from '../../src/conversion/mapper';
+
 import Model from '../../src/model/model';
 import ModelText from '../../src/model/text';
 import ModelElement from '../../src/model/element';
@@ -13,13 +15,14 @@ import View from '../../src/view/view';
 import ViewContainerElement from '../../src/view/containerelement';
 
 describe( 'DowncastDispatcher', () => {
-	let dispatcher, doc, root, differStub, model, view;
+	let dispatcher, doc, root, differStub, model, view, mapper;
 
 	beforeEach( () => {
 		model = new Model();
 		view = new View();
 		doc = model.document;
-		dispatcher = new DowncastDispatcher();
+		mapper = new Mapper();
+		dispatcher = new DowncastDispatcher( { mapper } );
 		root = doc.createRoot();
 
 		differStub = {
@@ -48,7 +51,7 @@ describe( 'DowncastDispatcher', () => {
 			differStub.getChanges = () => [ { type: 'insert', position, length: 1 } ];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertInsert.calledOnce ).to.be.true;
@@ -63,7 +66,7 @@ describe( 'DowncastDispatcher', () => {
 			differStub.getChanges = () => [ { type: 'remove', position, length: 2, name: '$text' } ];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertRemove.calledWith( position, 2, '$text' ) ).to.be.true;
@@ -80,7 +83,7 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertAttribute.calledWith( range, 'key', null, 'foo' ) ).to.be.true;
@@ -102,7 +105,7 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertInsert.calledTwice ).to.be.true;
@@ -122,7 +125,7 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertMarkerAdd.calledWith( 'foo', fooRange ) );
@@ -141,11 +144,34 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
+			} );
+
+			expect( dispatcher.convertMarkerRemove.calledWith( 'foo', fooRange ) );
+			expect( dispatcher.convertMarkerRemove.calledWith( 'bar', barRange ) );
+		} );
+
+		it( 'should re-render markers which view elements got unbound during conversion', () => {
+			sinon.stub( dispatcher, 'convertMarkerRemove' );
+			sinon.stub( dispatcher, 'convertMarkerAdd' );
+
+			const fooRange = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 1 ) );
+			const barRange = model.createRange( model.createPositionAt( root, 3 ), model.createPositionAt( root, 6 ) );
+
+			model.markers._set( 'foo', fooRange );
+			model.markers._set( 'bar', barRange );
+
+			// Stub `_unboundMarkers`.
+			dispatcher.conversionApi.mapper._unboundMarkers = new Set( [ 'foo', 'bar' ] );
+
+			view.change( writer => {
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertMarkerRemove.calledWith( 'foo', fooRange ) );
 			expect( dispatcher.convertMarkerRemove.calledWith( 'bar', barRange ) );
+			expect( dispatcher.convertMarkerAdd.calledWith( 'foo', fooRange ) );
+			expect( dispatcher.convertMarkerAdd.calledWith( 'bar', barRange ) );
 		} );
 	} );