Skip to content

Commit

Permalink
Wrap ember code in runloops correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
bantic committed Jan 12, 2016
1 parent ba833a5 commit 282d8b3
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 25 deletions.
65 changes: 40 additions & 25 deletions addon/components/mobiledoc-editor/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ export default Component.extend({

return Ember.merge({
placeholder: this.get('placeholder'),
spellcheck: this.get('spellcheck'),
autofocus: this.get('autofocus'),
cards: this.get('cards') || [],
atoms: this.get('atoms') || []
spellcheck: this.get('spellcheck'),
autofocus: this.get('autofocus'),
cards: this.get('cards') || [],
atoms: this.get('atoms') || []
}, options);
}),

Expand All @@ -63,6 +63,7 @@ export default Component.extend({
this.set('activeMarkupTagNames', {});
this.set('activeSectionTagNames', {});
this._ignoreCursorDidChange = false;
this._startedRunLoop = false;
},

actions: {
Expand Down Expand Up @@ -148,7 +149,6 @@ export default Component.extend({
cancelLink() {
this.set('linkOffsets', null);
}

},

editingContexts: computed(function() {
Expand Down Expand Up @@ -203,44 +203,60 @@ export default Component.extend({
editor,
postModel: env.postModel
});
Ember.run.join(() => {
Ember.run.schedule('afterRender', () => {
this.get('componentCards').pushObject(card);
});
Ember.run.schedule('afterRender', () => {
this.get('componentCards').pushObject(card);
});
return { card, element };
},
[REMOVE_HOOK]: (card) => {
Ember.run.join(() => {
this.get('componentCards').removeObject(card);
});
this.get('componentCards').removeObject(card);
}
};
editor = new MobiledocEditor(editorOptions);
editor.willRender(() => {
// The editor's render/rerender will happen after this `editor.willRender`,
// so we explicitly start a runloop here if there is none, so that the
// add/remove card hooks happen inside a runloop.
// When pasting text that gets turned into a card, for example,
// the add card hook would run outside the runloop if we didn't begin a new
// one now.
if (!Ember.run.currentRunLoop) {
this._startedRunLoop = true;
Ember.run.begin();
}
});
editor.didRender(() => {
// If we had explicitly started a run loop in `editor.willRender`,
// we must explicitly end it here.
if (this._startedRunLoop) {
this._startedRunLoop = false;
Ember.run.end();
}
});
editor.on('update', () => {
let updatedMobileDoc = editor.serialize();
this._localMobiledoc = updatedMobileDoc;
Ember.run.join(() => {
let updatedMobileDoc = editor.serialize();
this._localMobiledoc = updatedMobileDoc;
this.sendAction('on-change', updatedMobileDoc);
});
});
editor.cursorDidChange(() => {
if (this.isDestroyed) { return; }

const markupTags = arrayToMap(editor.markupsInSelection, 'tagName');
const sectionTags = arrayToMap(editor.activeSections, 'tagName');

Ember.run.join(() => {
const markupTags = arrayToMap(editor.markupsInSelection, 'tagName');
const sectionTags = arrayToMap(editor.activeSections, 'tagName');

this.set('activeMarkupTagNames', markupTags);
this.set('activeSectionTagNames', sectionTags);
});

let isCursorOffEditor = !this.get('editor').cursor.offsets.head.section;
if (!isCursorOffEditor && !this._ignoreCursorDidChange) {
this.set('linkOffsets', null);
} else {
this._ignoreCursorDidChange = false;
}
let isCursorOffEditor = !this.get('editor').cursor.offsets.head.section;
if (!isCursorOffEditor && !this._ignoreCursorDidChange) {
this.set('linkOffsets', null);
} else {
this._ignoreCursorDidChange = false;
}
});
});
if (this.get('isEditingDisabled')) {
editor.disableEditing();
Expand Down Expand Up @@ -283,5 +299,4 @@ export default Component.extend({
postEditor.setRange(range);
});
}

});
33 changes: 33 additions & 0 deletions tests/integration/components/mobiledoc-editor/component-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,39 @@ test('it does not create a new editor when the same mobiledoc is set', function(
'editor is same reference');
});

test('wraps component-card adding in runloop correctly', function(assert) {
assert.expect(3);
let mobiledoc = simpleMobileDoc('Howdy');
let editor;

this.set('mobiledoc', mobiledoc);
this.register('component:gather-editor', Ember.Component.extend({
didRender() {
editor = this.get('editor');
}
}));
this.registry.register('template:components/demo-card', hbs`
<div id="demo-card">demo-card</div>
`);
this.set('cards', [createComponentCard('demo-card')]);
this.set('mobiledoc', simpleMobileDoc(''));
this.render(hbs`
{{#mobiledoc-editor mobiledoc=mobiledoc cards=cards as |editor|}}
{{gather-editor editor=editor.editor}}
{{/mobiledoc-editor}}
`);

// Add a card without being in a runloop
assert.ok(!Ember.run.currentRunLoop, 'precond - no run loop');
editor.run((postEditor) => {
let card = postEditor.builder.createCardSection('demo-card');
postEditor.insertSection(card);
});
assert.ok(!Ember.run.currentRunLoop, 'postcond - no run loop after editor.run');

assert.ok(this.$('#demo-card').length, 'demo card is added');
});

test('it updates the editor when the mobiledoc changes', function(assert) {
assert.expect(2);
let mobiledoc1 = simpleMobileDoc('Howdy');
Expand Down

0 comments on commit 282d8b3

Please sign in to comment.