From e80a3207feff693aab07c2f1680693357c9ca42b Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Thu, 31 Dec 2015 13:39:31 -0500 Subject: [PATCH] Minimize rerender from new Mobiledoc Move the editor destroy/setup flow into willRender and didRender. Compare a new mobiledoc to the local mobiledoc and the upstream one before destroying and recreating the editor. Refs #42 --- .../components/mobiledoc-editor/component.js | 53 +++++++++++++------ .../mobiledoc-editor/component-test.js | 29 ++++++++++ 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/addon/components/mobiledoc-editor/component.js b/addon/components/mobiledoc-editor/component.js index 054fa64..9cddb43 100644 --- a/addon/components/mobiledoc-editor/component.js +++ b/addon/components/mobiledoc-editor/component.js @@ -146,15 +146,31 @@ export default Component.extend({ return Ember.A([]); }), - editor: computed('mobiledoc', 'isEditingDisabled', function() { - if (this._lastEditor) { - this._lastEditor.destroy(); - this._lastEditor = null; + willRender() { + // Use a default mobiledoc. If there are no changes, then return + // early. + let mobiledoc = this.get('mobiledoc') || EMPTY_MOBILEDOC; + if ( + ( + (this._localMobiledoc && this._localMobiledoc === mobiledoc) || + (this._upstreamMobiledoc && this._upstreamMobiledoc === mobiledoc) + ) && (this._lastIsEditingDisabled === this.get('isEditingDisabled')) + ) { + // No change to mobiledoc, no need to recreate the editor + return; + } + this._lastIsEditingDisabled = this.get('isEditingDisabled'); + this._upstreamMobiledoc = mobiledoc; + this._localMobiledoc = null; + + // Teardown any old editor that might be around. + let editor = this.get('editor'); + if (editor) { + editor.destroy(); } - let editor; - let mobiledoc = this.get('mobiledoc'); - let editorOptions = this.get('editorOptions'); + // Create a new editor. + let editorOptions = this.get('editorOptions'); editorOptions.mobiledoc = mobiledoc; editorOptions.cardOptions = { [ADD_HOOK]: ({env, options, payload}, isEditing=false) => { @@ -178,8 +194,10 @@ export default Component.extend({ editor, postModel: env.postModel }); - Ember.run.schedule('afterRender', () => { - this.get('componentCards').pushObject(card); + Ember.run.join(() => { + Ember.run.schedule('afterRender', () => { + this.get('componentCards').pushObject(card); + }); }); return { card, element }; }, @@ -192,7 +210,10 @@ export default Component.extend({ editor = new window.Mobiledoc.Editor(editorOptions); editor.on('update', () => { let updatedMobileDoc = editor.serialize(); - this.sendAction('on-change', updatedMobileDoc); + this._localMobiledoc = updatedMobileDoc; + Ember.run.join(() => { + this.sendAction('on-change', updatedMobileDoc); + }); }); editor.cursorDidChange(() => { if (this.isDestroyed) { return; } @@ -200,7 +221,7 @@ export default Component.extend({ const markupTags = arrayToMap(editor.markupsInSelection, 'tagName'); const sectionTags = arrayToMap(editor.activeSections, 'tagName'); - Ember.run(() => { + Ember.run.join(() => { this.set('activeMarkupTagNames', markupTags); this.set('activeSectionTagNames', sectionTags); }); @@ -215,15 +236,13 @@ export default Component.extend({ if (this.get('isEditingDisabled')) { editor.disableEditing(); } - this._lastEditor = editor; - return editor; - }), + this.set('editor', editor); + }, didRender() { let editor = this.get('editor'); - let editorElement = this.$('.mobiledoc-editor__editor')[0]; - if (this._renderedEditor !== editor) { - this._renderedEditor = editor; + if (!editor.hasRendered) { + let editorElement = this.$('.mobiledoc-editor__editor')[0]; editor.render(editorElement); } }, diff --git a/tests/integration/components/mobiledoc-editor/component-test.js b/tests/integration/components/mobiledoc-editor/component-test.js index 21e6136..0185f5c 100644 --- a/tests/integration/components/mobiledoc-editor/component-test.js +++ b/tests/integration/components/mobiledoc-editor/component-test.js @@ -66,6 +66,35 @@ test('it boots mobiledoc editor with mobiledoc', function(assert) { ); }); +test('it does not update the editor when the same mobiledoc is set', function(assert) { + assert.expect(2); + let mobiledoc = simpleMobileDoc('Howdy'); + let editor; + let createdEditors = 0; + + this.set('mobiledoc', mobiledoc); + this.register('component:gather-editor', Ember.Component.extend({ + didRender() { + createdEditors++; + editor = this.get('editor'); + } + })); + this.render(hbs` + {{#mobiledoc-editor mobiledoc=(readonly mobiledoc) + on-change=(action (mut mobiledoc)) as |editor|}} + {{gather-editor editor=editor.editor}} + {{/mobiledoc-editor}} + `); + + assert.equal(createdEditors, 1, 'initial editor created'); + + editor.run((postEditor) => { + postEditor.insertText(editor.range.tail, 'Friend'); + }); + + assert.equal(createdEditors, 1, 'editor maintained'); +}); + test('it updates the editor when the mobiledoc changes', function(assert) { assert.expect(2); let mobiledoc1 = simpleMobileDoc('Howdy');