Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Introduced model.Differ#refreshItem() #1756

Merged
merged 1 commit into from
Jul 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/model/differ.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,32 @@ export default class Differ {
return this._changesInElement.size == 0 && this._changedMarkers.size == 0;
}

/**
* Marks given `item` in differ to be "refreshed". It means that the item will be marked as removed and inserted in the differ changes
* set, so it will be effectively re-converted when differ changes will be handled by a dispatcher.
*
* @param {module:engine/model/item~Item} item Item to refresh.
*/
refreshItem( item ) {
if ( this._isInInsertedElement( item.parent ) ) {
return;
}

this._markRemove( item.parent, item.startOffset, item.offsetSize );
this._markInsert( item.parent, item.startOffset, item.offsetSize );

const range = Range._createOn( item );

for ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {
const markerRange = marker.getRange();

this.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );
}

// Clear cache after each buffered operation as it is no longer valid.
this._cachedChanges = null;
}

/**
* Buffers the given operation. An operation has to be buffered before it is executed.
*
Expand Down
70 changes: 70 additions & 0 deletions tests/model/differ.js
Original file line number Diff line number Diff line change
Expand Up @@ -1759,6 +1759,76 @@ describe( 'Differ', () => {
} );
} );

describe( 'refreshItem()', () => {
it( 'should mark given element to be removed and added again', () => {
const p = root.getChild( 0 );

differ.refreshItem( p );

expectChanges( [
{ type: 'remove', name: 'paragraph', length: 1, position: model.createPositionBefore( p ) },
{ type: 'insert', name: 'paragraph', length: 1, position: model.createPositionBefore( p ) }
], true );
} );

it( 'should mark given text proxy to be removed and added again', () => {
const p = root.getChild( 0 );
const range = model.createRangeIn( p );
const textProxy = [ ...range.getItems() ][ 0 ];

differ.refreshItem( textProxy );

expectChanges( [
{ type: 'remove', name: '$text', length: 3, position: model.createPositionAt( p, 0 ) },
{ type: 'insert', name: '$text', length: 3, position: model.createPositionAt( p, 0 ) }
], true );
} );

it( 'inside a new element', () => {
// Since the refreshed element is inside a new element, it should not be listed on changes list.
model.change( () => {
insert( new Element( 'blockQuote', null, new Element( 'paragraph' ) ), new Position( root, [ 2 ] ) );

differ.refreshItem( root.getChild( 2 ).getChild( 0 ) );

expectChanges( [
{ type: 'insert', name: 'blockQuote', length: 1, position: new Position( root, [ 2 ] ) }
] );
} );
} );

it( 'markers refreshing', () => {
model.change( () => {
// Refreshed element contains marker.
model.markers._set( 'markerA', new Range( new Position( root, [ 1, 1 ] ), new Position( root, [ 1, 2 ] ) ) );

// Marker contains refreshed element.
model.markers._set( 'markerB', new Range( new Position( root, [ 0 ] ), new Position( root, [ 2 ] ) ) );

// Intersecting.
model.markers._set( 'markerC', new Range( new Position( root, [ 0, 2 ] ), new Position( root, [ 1, 2 ] ) ) );

// Not intersecting.
model.markers._set( 'markerD', new Range( new Position( root, [ 0, 0 ] ), new Position( root, [ 1 ] ) ) );
} );

const markersToRefresh = [ 'markerA', 'markerB', 'markerC' ];

differ.refreshItem( root.getChild( 1 ) );

expectChanges( [
{ type: 'remove', name: 'paragraph', length: 1, position: new Position( root, [ 1 ] ) },
{ type: 'insert', name: 'paragraph', length: 1, position: new Position( root, [ 1 ] ) }
] );

const markersToRemove = differ.getMarkersToRemove().map( entry => entry.name );
const markersToAdd = differ.getMarkersToAdd().map( entry => entry.name );

expect( markersToRefresh ).to.deep.equal( markersToRemove );
expect( markersToRefresh ).to.deep.equal( markersToAdd );
} );
} );

describe( 'getChanges()', () => {
let position, p1, rangeAttrChange, range;

Expand Down