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

Commit 420166a

Browse files
author
Piotr Jasiun
authored
Merge pull request #1572 from ckeditor/t/1571
Fix: Remove clone groups in `view.DowncastWriter` manually. Closes #1571.
2 parents 6c15b88 + f9eabee commit 420166a

File tree

3 files changed

+56
-9
lines changed

3 files changed

+56
-9
lines changed

src/conversion/downcast-converters.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,12 +625,12 @@ export function removeUIElement() {
625625

626626
conversionApi.mapper.unbindElementsFromMarkerName( data.markerName );
627627

628-
const viewWriter = conversionApi.writer;
629-
630628
for ( const element of elements ) {
631-
viewWriter.clear( ViewRange.createOn( element ), element );
629+
conversionApi.writer.clear( ViewRange.createOn( element ), element );
632630
}
633631

632+
conversionApi.writer.clearClonedElementsGroup( data.markerName );
633+
634634
evt.stop();
635635
};
636636
}
@@ -970,6 +970,8 @@ export function removeHighlight( highlightDescriptor ) {
970970
}
971971
}
972972

973+
conversionApi.writer.clearClonedElementsGroup( data.markerName );
974+
973975
evt.stop();
974976
};
975977
}

src/view/downcastwriter.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default class DowncastWriter {
4040
* The keys are `id`s, the values are `Set`s holding {@link module:engine/view/attributeelement~AttributeElement}s.
4141
*
4242
* @private
43-
* @type {Map}
43+
* @type {Map.<String,Set>}
4444
*/
4545
this._cloneGroups = new Map();
4646
}
@@ -921,6 +921,24 @@ export default class DowncastWriter {
921921
return newElement;
922922
}
923923

924+
/**
925+
* Cleans up memory by removing obsolete cloned elements group from the writer.
926+
*
927+
* Should be used whenever all {@link module:engine/view/attributeelement~AttributeElement attribute elements}
928+
* with the same {@link module:engine/view/attributeelement~AttributeElement#id id} are going to be removed from the view and
929+
* the group will no longer be needed.
930+
*
931+
* Cloned elements group are not removed automatically in case if the group is still needed after all its elements
932+
* were removed from the view.
933+
*
934+
* Keep in mind that group names are equal to the `id` property of the attribute element.
935+
*
936+
* @param {String} groupName Name of the group to clear.
937+
*/
938+
clearClonedElementsGroup( groupName ) {
939+
this._cloneGroups.delete( groupName );
940+
}
941+
924942
/**
925943
* Wraps children with provided `attribute`. Only children contained in `parent` element between
926944
* `startOffset` and `endOffset` will be wrapped.
@@ -1519,11 +1537,6 @@ export default class DowncastWriter {
15191537
group.delete( element );
15201538
// Not removing group from element on purpose!
15211539
// If other parts of code have reference to this element, they will be able to get references to other elements from the group.
1522-
// If all other elements are removed from the set, everything will be garbage collected.
1523-
1524-
if ( group.size === 0 ) {
1525-
this._cloneGroups.delete( id );
1526-
}
15271540
}
15281541
}
15291542

tests/view/downcastwriter/move.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import DowncastWriter from '../../../src/view/downcastwriter';
77
import { stringify, parse } from '../../../src/dev-utils/view';
88
import ContainerElement from '../../../src/view/containerelement';
99
import AttributeElement from '../../../src/view/attributeelement';
10+
import RootEditableElement from '../../../src/view/rooteditableelement';
1011
import EmptyElement from '../../../src/view/emptyelement';
1112
import UIElement from '../../../src/view/uielement';
1213
import Range from '../../../src/view/range';
1314
import Position from '../../../src/view/position';
1415
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
1516
import Document from '../../../src/view/document';
17+
import Mapper from '../../../src/conversion/mapper';
1618

1719
describe( 'DowncastWriter', () => {
1820
describe( 'move()', () => {
@@ -180,5 +182,35 @@ describe( 'DowncastWriter', () => {
180182
writer.move( srcRange, dstPosition );
181183
} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
182184
} );
185+
186+
it( 'should not break marker mappings if marker element was split and the original element was removed', () => {
187+
const mapper = new Mapper();
188+
189+
const srcContainer = new ContainerElement( 'p' );
190+
const dstContainer = new ContainerElement( 'p' );
191+
192+
const root = new RootEditableElement( 'div' );
193+
root._appendChild( [ srcContainer, dstContainer ] );
194+
195+
const attrElemA = new AttributeElement( 'span' );
196+
attrElemA._id = 'foo';
197+
198+
const attrElemB = new AttributeElement( 'span' );
199+
attrElemB._id = 'foo';
200+
201+
writer.insert( new Position( srcContainer, 0 ), [ attrElemA, attrElemB ] );
202+
203+
mapper.bindElementToMarker( attrElemA, 'foo' );
204+
205+
expect( mapper.markerNameToElements( 'foo' ).size ).to.equal( 2 );
206+
207+
writer.remove( Range.createOn( attrElemA ) );
208+
209+
expect( mapper.markerNameToElements( 'foo' ).size ).to.equal( 1 );
210+
211+
writer.move( Range.createOn( attrElemB ), new Position( dstContainer, 0 ) );
212+
213+
expect( mapper.markerNameToElements( 'foo' ).size ).to.equal( 1 );
214+
} );
183215
} );
184216
} );

0 commit comments

Comments
 (0)