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

Commit 6f5ec0d

Browse files
authored
Merge pull request #254 from ckeditor/t/248
Other: Made the UI destruction a fail–safe, repeatable process. Closes #248.
2 parents 25ba4dc + 38c00ab commit 6f5ec0d

File tree

8 files changed

+81
-35
lines changed

8 files changed

+81
-35
lines changed

src/panel/balloon/contextualballoon.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,14 +205,4 @@ export default class ContextualBalloon extends Plugin {
205205
_getBalloonPosition() {
206206
return this._stack.values().next().value.position;
207207
}
208-
209-
/**
210-
* @inheritDoc
211-
*/
212-
destroy() {
213-
this.editor.ui.view.body.remove( this.view );
214-
this.view.destroy();
215-
this._stack.clear();
216-
super.destroy();
217-
}
218208
}

src/view.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,7 @@ export default class View {
309309
destroy() {
310310
this.stopListening();
311311

312-
return Promise.all( this._viewCollections.map( c => c.destroy() ) )
313-
.then( () => {
314-
this._unboundChildren.clear();
315-
this._viewCollections.clear();
316-
317-
this.element = this.template = this.locale = this.t =
318-
this._viewCollections = this._unboundChildren = null;
319-
} );
312+
return Promise.all( this._viewCollections.map( c => c.destroy() ) );
320313
}
321314

322315
/**

tests/editableui/editableuiview.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ describe( 'EditableUIView', () => {
8585
} );
8686
} );
8787

88+
it( 'can be called multiple times', done => {
89+
expect( () => {
90+
view.destroy().then( () => {
91+
return view.destroy().then( () => {
92+
done();
93+
} );
94+
} );
95+
} ).to.not.throw();
96+
} );
97+
8898
describe( 'when #editableElement as an argument', () => {
8999
it( 'reverts contentEditable property of editableElement (was false)', () => {
90100
editableElement = document.createElement( 'div' );

tests/editorui/editoruiview.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,15 @@ describe( 'EditorUIView', () => {
5151
expect( el.parentNode ).to.be.null;
5252
} );
5353
} );
54+
55+
it( 'can be called multiple times', done => {
56+
expect( () => {
57+
view.destroy().then( () => {
58+
return view.destroy().then( () => {
59+
done();
60+
} );
61+
} );
62+
} ).to.not.throw();
63+
} );
5464
} );
5565
} );

tests/panel/balloon/contextualballoon.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,17 @@ describe( 'ContextualBalloon', () => {
352352
} );
353353

354354
describe( 'destroy()', () => {
355-
it( 'should remove balloon panel view from editor body collection and clear stack', () => {
355+
it( 'can be called multiple times', () => {
356+
expect( () => {
357+
balloon.destroy();
358+
balloon.destroy();
359+
} ).to.not.throw();
360+
} );
361+
362+
it( 'should not touch the DOM', () => {
356363
balloon.destroy();
357364

358-
expect( editor.ui.view.body.getIndex( balloon.view ) ).to.equal( -1 );
359-
expect( balloon.visibleView ).to.null;
365+
expect( editor.ui.view.body.getIndex( balloon.view ) ).to.not.equal( -1 );
360366
} );
361367
} );
362368
} );

tests/toolbar/contextual/contextualtoolbar.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ describe( 'ContextualToolbar', () => {
291291
} );
292292

293293
describe( 'destroy()', () => {
294+
it( 'can be called multiple times', () => {
295+
expect( () => {
296+
contextualToolbar.destroy();
297+
contextualToolbar.destroy();
298+
} ).to.not.throw();
299+
} );
300+
294301
it( 'should not fire `_selectionChangeDebounced` after plugin destroy', done => {
295302
const spy = sandbox.spy();
296303

tests/toolbar/sticky/stickytoolbarview.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,16 @@ describe( 'StickyToolbarView', () => {
178178
expect( view.destroy() ).to.be.instanceof( Promise );
179179
} );
180180

181+
it( 'can be called multiple times', done => {
182+
expect( () => {
183+
view.destroy().then( () => {
184+
return view.destroy().then( () => {
185+
done();
186+
} );
187+
} );
188+
} ).to.not.throw();
189+
} );
190+
181191
it( 'calls destroy on parent class', () => {
182192
const spy = testUtils.sinon.spy( ToolbarView.prototype, 'destroy' );
183193

tests/view.js

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -262,41 +262,55 @@ describe( 'View', () => {
262262
beforeEach( createViewWithChildren );
263263

264264
it( 'should return a promise', () => {
265-
expect( view.destroy() ).to.be.instanceof( Promise );
265+
const promise = view.destroy();
266+
267+
expect( promise ).to.be.instanceof( Promise );
268+
269+
return promise;
270+
} );
271+
272+
it( 'can be called multiple times', done => {
273+
expect( () => {
274+
view.destroy().then( () => {
275+
return view.destroy().then( () => {
276+
done();
277+
} );
278+
} );
279+
} ).to.not.throw();
266280
} );
267281

268-
it( 'should set basic properties null', () => {
282+
it( 'should not touch the basic properties', () => {
269283
return view.destroy().then( () => {
270-
expect( view.element ).to.be.null;
271-
expect( view.template ).to.be.null;
272-
expect( view.locale ).to.be.null;
273-
expect( view.t ).to.be.null;
284+
expect( view.element ).to.be.an.instanceof( HTMLElement );
285+
expect( view.template ).to.be.an.instanceof( Template );
286+
expect( view.locale ).to.be.an( 'object' );
287+
expect( view.locale.t ).to.be.a( 'function' );
274288

275-
expect( view._unboundChildren ).to.be.null;
276-
expect( view._viewCollections ).to.be.null;
289+
expect( view._viewCollections ).to.be.instanceOf( Collection );
290+
expect( view._unboundChildren ).to.be.instanceOf( ViewCollection );
277291
} );
278292
} );
279293

280-
it( 'clears #_unboundChildren', () => {
294+
it( 'should not clear the #_unboundChildren', () => {
281295
const cached = view._unboundChildren;
282296

283297
return view.addChildren( [ new View(), new View() ] )
284298
.then( () => {
285-
expect( cached ).to.have.length.above( 2 );
299+
expect( cached ).to.have.length( 4 );
286300

287301
return view.destroy().then( () => {
288-
expect( cached ).to.have.length( 0 );
302+
expect( cached ).to.have.length( 4 );
289303
} );
290304
} );
291305
} );
292306

293-
it( 'clears #_viewCollections', () => {
307+
it( 'should not clear the #_viewCollections', () => {
294308
const cached = view._viewCollections;
295309

296310
expect( cached ).to.have.length( 1 );
297311

298312
return view.destroy().then( () => {
299-
expect( cached ).to.have.length( 0 );
313+
expect( cached ).to.have.length( 1 );
300314
} );
301315
} );
302316

@@ -326,11 +340,15 @@ describe( 'View', () => {
326340
} );
327341

328342
it( 'destroy a template–less view', () => {
343+
let promise;
344+
329345
view = new View();
330346

331347
expect( () => {
332-
view.destroy();
348+
promise = view.destroy();
333349
} ).to.not.throw();
350+
351+
return promise;
334352
} );
335353

336354
// https://github.com/ckeditor/ckeditor5-ui/issues/203
@@ -383,6 +401,8 @@ function setTestViewClass( templateDef ) {
383401
constructor() {
384402
super();
385403

404+
this.locale = { t() {} };
405+
386406
if ( templateDef ) {
387407
this.template = new Template( templateDef );
388408
}

0 commit comments

Comments
 (0)