From 3f4f6037b85e14214bc028d4d6597a241b99c23e Mon Sep 17 00:00:00 2001 From: Szymon Cofalik Date: Fri, 16 Aug 2019 14:55:38 +0200 Subject: [PATCH] Feature: Introduced `conversion.Mapper#flushUnboundMarkers`. --- src/conversion/downcastdispatcher.js | 4 +-- src/conversion/mapper.js | 48 +++++++++++++++++----------- tests/conversion/mapper.js | 42 +++++++++++++----------- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/conversion/downcastdispatcher.js b/src/conversion/downcastdispatcher.js index fb3dddaf5..ee45d46b3 100644 --- a/src/conversion/downcastdispatcher.js +++ b/src/conversion/downcastdispatcher.js @@ -143,15 +143,13 @@ export default class DowncastDispatcher { } } - for ( const markerName of this.conversionApi.mapper._unboundMarkers ) { + for ( const markerName of this.conversionApi.mapper.flushUnboundMarkerNames() ) { 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 ); diff --git a/src/conversion/mapper.js b/src/conversion/mapper.js index 0dc713f06..07dc106c8 100644 --- a/src/conversion/mapper.js +++ b/src/conversion/mapper.js @@ -88,13 +88,13 @@ export default class Mapper { this._elementToMarkerNames = new Map(); /** - * Stores markers which has changed due to unbinding a view element (so it is assumed that the view element has been removed, - * moved or renamed). In some cases such markers need to be refreshed (re-rendered). + * Stores marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element + * has been removed, moved or renamed). * - * @protected + * @private * @member {Set.} */ - this._unboundMarkers = new Set(); + this._unboundMarkerNames = new Set(); // Default mapper algorithm for mapping model position to view position. this.on( 'modelToViewPosition', ( evt, data ) => { @@ -153,7 +153,7 @@ export default class Mapper { if ( this._elementToMarkerNames.has( viewElement ) ) { for ( const markerName of this._elementToMarkerNames.get( viewElement ) ) { - this._unboundMarkers.add( markerName ); + this._unboundMarkerNames.add( markerName ); } } @@ -208,29 +208,41 @@ export default class Mapper { * @param {String} name Marker name. */ unbindElementFromMarkerName( element, name ) { - const elements = this._markerNameToElements.get( name ); - - if ( !elements ) { - return; - } + const nameToElements = this._markerNameToElements.get( name ); - elements.delete( element ); + if ( nameToElements ) { + nameToElements.delete( element ); - if ( elements.size == 0 ) { - this._markerNameToElements.delete( name ); + if ( nameToElements.size == 0 ) { + this._markerNameToElements.delete( name ); + } } - const names = this._elementToMarkerNames.get( element ); + const elementToNames = this._elementToMarkerNames.get( element ); - if ( names ) { - names.delete( name ); + if ( elementToNames ) { + elementToNames.delete( name ); - if ( names.size == 0 ) { + if ( elementToNames.size == 0 ) { this._elementToMarkerNames.delete( element ); } } } + /** + * Returns all marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element + * has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared. + * + * @returns {Array.} + */ + flushUnboundMarkerNames() { + const markerNames = Array.from( this._unboundMarkerNames ); + + this._unboundMarkerNames.clear(); + + return markerNames; + } + /** * Removes all model to view and view to model bindings. */ @@ -239,7 +251,7 @@ export default class Mapper { this._viewToModelMapping = new WeakMap(); this._markerNameToElements = new Map(); this._elementToMarkerNames = new Map(); - this._unboundMarkers = new Set(); + this._unboundMarkerNames = new Set(); } /** diff --git a/tests/conversion/mapper.js b/tests/conversion/mapper.js index d667d9882..e98f09cce 100644 --- a/tests/conversion/mapper.js +++ b/tests/conversion/mapper.js @@ -52,8 +52,6 @@ describe( 'Mapper', () => { expect( Array.from( mapper.markerNameToElements( 'foo' ) ) ).to.deep.equal( [ viewA, viewD ] ); mapper.unbindViewElement( viewD ); - expect( Array.from( mapper._unboundMarkers ) ).to.deep.equal( [ 'foo', 'bar' ] ); - mapper.clearBindings(); expect( mapper.toModelElement( viewA ) ).to.be.undefined; @@ -65,7 +63,7 @@ describe( 'Mapper', () => { expect( mapper.toViewElement( modelC ) ).to.be.undefined; expect( mapper.markerNameToElements( 'foo' ) ).to.be.null; - expect( Array.from( mapper._unboundMarkers ) ).to.deep.equal( [] ); + expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [] ); } ); } ); @@ -139,21 +137,6 @@ describe( 'Mapper', () => { expect( mapper.toModelElement( viewA ) ).to.be.undefined; expect( mapper.toViewElement( modelA ) ).to.equal( viewB ); } ); - - it( 'should add marker names to _unboundMarkers set', () => { - const viewA = new ViewElement( 'a' ); - const modelA = new ModelElement( 'a' ); - - const mapper = new Mapper(); - mapper.bindElements( modelA, viewA ); - - mapper.bindElementToMarker( viewA, 'foo' ); - mapper.bindElementToMarker( viewA, 'bar' ); - - mapper.unbindViewElement( viewA ); - - expect( Array.from( mapper._unboundMarkers ) ).to.deep.equal( [ 'foo', 'bar' ] ); - } ); } ); describe( 'Standard mapping', () => { @@ -784,4 +767,27 @@ describe( 'Mapper', () => { expect( viewMappedAncestor ).to.equal( viewP ); } ); } ); + + describe( 'flushUnboundMarkerNames()', () => { + it( 'should return marker names of markers which elements has been unbound and clear that list', () => { + const viewA = new ViewElement( 'a' ); + const viewB = new ViewElement( 'b' ); + + const mapper = new Mapper(); + + mapper.bindElementToMarker( viewA, 'foo' ); + mapper.bindElementToMarker( viewA, 'bar' ); + mapper.bindElementToMarker( viewB, 'bar' ); + + mapper.unbindViewElement( viewA ); + + expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [ 'foo', 'bar' ] ); + expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [] ); + + mapper.unbindViewElement( viewB ); + + expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [ 'bar' ] ); + expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [] ); + } ); + } ); } );