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

Commit ef8be75

Browse files
committed
Changed: Fixed detaching model.LiveRange in model.LiveSelection.
1 parent 0aec182 commit ef8be75

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

src/model/liveselection.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ export default class LiveSelection extends Selection {
116116
* Unbinds all events previously bound by document selection.
117117
*/
118118
destroy() {
119-
for ( let i = 0; i < this._ranges.length; i++ ) {
120-
this._ranges[ i ].detach();
119+
while ( this._ranges.length ) {
120+
this._popRange();
121121
}
122122

123123
this.stopListening();
@@ -255,7 +255,10 @@ export default class LiveSelection extends Selection {
255255
* @inheritDoc
256256
*/
257257
_popRange() {
258-
this._ranges.pop().detach();
258+
const range = this._ranges.pop();
259+
260+
range.detach();
261+
this.stopListening( range );
259262
}
260263

261264
/**
@@ -302,6 +305,7 @@ export default class LiveSelection extends Selection {
302305
this._checkRange( range );
303306

304307
const liveRange = LiveRange.createFromRange( range );
308+
305309
this.listenTo( liveRange, 'change', ( evt, oldRange ) => {
306310
if ( liveRange.root == this._document.graveyard ) {
307311
this._fixGraveyardSelection( liveRange, oldRange );
@@ -638,7 +642,9 @@ export default class LiveSelection extends Selection {
638642

639643
const newRange = this._prepareRange( selectionRange );
640644
const index = this._ranges.indexOf( gyRange );
645+
641646
gyRange.detach();
647+
this.stopListening( gyRange );
642648

643649
this._ranges.splice( index, 1, newRange );
644650
}

tests/model/liveselection.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,21 @@ describe( 'LiveSelection', () => {
171171
selection.addRange( liveRange );
172172
selection.addRange( range );
173173

174-
const ranges = selection._ranges;
174+
const ranges = Array.from( selection._ranges );
175175

176176
sinon.spy( ranges[ 0 ], 'detach' );
177177
sinon.spy( ranges[ 1 ], 'detach' );
178178

179+
sinon.spy( selection, 'stopListening' );
180+
179181
selection.destroy();
180182

181183
expect( ranges[ 0 ].detach.called ).to.be.true;
182184
expect( ranges[ 1 ].detach.called ).to.be.true;
183185

186+
expect( selection.stopListening.calledWith( ranges[ 0 ] ) ).to.be.true;
187+
expect( selection.stopListening.calledWith( ranges[ 1 ] ) ).to.be.true;
188+
184189
ranges[ 0 ].detach.restore();
185190
ranges[ 1 ].detach.restore();
186191
} );
@@ -226,6 +231,8 @@ describe( 'LiveSelection', () => {
226231
sinon.spy( ranges[ 0 ], 'detach' );
227232
sinon.spy( ranges[ 1 ], 'detach' );
228233

234+
sinon.spy( selection, 'stopListening' );
235+
229236
selection.removeAllRanges();
230237
} );
231238

@@ -240,9 +247,12 @@ describe( 'LiveSelection', () => {
240247
expect( selection.focus.isEqual( new Position( root, [ 0, 0 ] ) ) ).to.be.true;
241248
} );
242249

243-
it( 'should detach ranges', () => {
250+
it( 'should detach ranges and stop listening to removed ranges', () => {
244251
expect( ranges[ 0 ].detach.called ).to.be.true;
245252
expect( ranges[ 1 ].detach.called ).to.be.true;
253+
254+
expect( selection.stopListening.calledWith( ranges[ 0 ] ) ).to.be.true;
255+
expect( selection.stopListening.calledWith( ranges[ 1 ] ) ).to.be.true;
246256
} );
247257

248258
it( 'should refresh attributes', () => {
@@ -261,7 +271,7 @@ describe( 'LiveSelection', () => {
261271
} ).to.throw( CKEditorError, /model-selection-added-not-range/ );
262272
} );
263273

264-
it( 'should detach removed ranges', () => {
274+
it( 'should detach and stop listening to removed ranges', () => {
265275
selection.addRange( liveRange );
266276
selection.addRange( range );
267277

@@ -270,10 +280,15 @@ describe( 'LiveSelection', () => {
270280
sinon.spy( oldRanges[ 0 ], 'detach' );
271281
sinon.spy( oldRanges[ 1 ], 'detach' );
272282

283+
sinon.spy( selection, 'stopListening' );
284+
273285
selection.setRanges( [] );
274286

275287
expect( oldRanges[ 0 ].detach.called ).to.be.true;
276288
expect( oldRanges[ 1 ].detach.called ).to.be.true;
289+
290+
expect( selection.stopListening.calledWith( oldRanges[ 0 ] ) ).to.be.true;
291+
expect( selection.stopListening.calledWith( oldRanges[ 1 ] ) ).to.be.true;
277292
} );
278293

279294
it( 'should refresh attributes', () => {
@@ -599,6 +614,26 @@ describe( 'LiveSelection', () => {
599614

600615
expect( selection.getFirstPosition().path ).to.deep.equal( [ 0, 6 ] );
601616
} );
617+
618+
it( 'detach and stop listening to a range that ended up in in graveyard', () => {
619+
selection.collapse( new Position( root, [ 1, 3 ] ) );
620+
621+
const range = selection._ranges[ 0 ];
622+
623+
sinon.spy( range, 'detach' );
624+
sinon.spy( selection, 'stopListening' );
625+
626+
doc.applyOperation( wrapInDelta(
627+
new RemoveOperation(
628+
new Position( root, [ 1, 2 ] ),
629+
2,
630+
doc.version
631+
)
632+
) );
633+
634+
expect( range.detach.called ).to.be.true;
635+
expect( selection.stopListening.calledWith( range ) ).to.be.true;
636+
} );
602637
} );
603638
} );
604639

0 commit comments

Comments
 (0)