mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-05 18:34:39 +03:00
Fix high latency autosave bug in editor.new
Closes #4400 - Added focusCursorAtEnd property to codemirror component, to set the cursor at document end on load. Used for posts that have been edited - centralized codemirror init code in component
This commit is contained in:
parent
2668a62209
commit
a9ce31ffe7
@ -42,9 +42,10 @@ onScrollHandler = function (cm) {
|
||||
|
||||
Codemirror = Ember.TextArea.extend(MarkerManager, {
|
||||
focus: true,
|
||||
focusCursorAtEnd: false,
|
||||
|
||||
setFocus: function () {
|
||||
if (this.focus) {
|
||||
if (this.get('focus')) {
|
||||
this.$().val(this.$().val()).focus();
|
||||
}
|
||||
}.on('didInsertElement'),
|
||||
@ -54,24 +55,28 @@ Codemirror = Ember.TextArea.extend(MarkerManager, {
|
||||
},
|
||||
|
||||
afterRenderEvent: function () {
|
||||
var self = this;
|
||||
|
||||
function initMarkers() {
|
||||
self.initMarkers.apply(self, arguments);
|
||||
}
|
||||
var codemirror;
|
||||
|
||||
// replaces CodeMirror with TouchEditor only if we're on mobile
|
||||
mobileCodeMirror.createIfMobile();
|
||||
|
||||
this.initCodemirror();
|
||||
this.codemirror.eachLine(initMarkers);
|
||||
codemirror = this.initCodemirror();
|
||||
this.set('codemirror', codemirror);
|
||||
|
||||
this.sendAction('setCodeMirror', this);
|
||||
|
||||
if (this.get('focus') && this.get('focusCursorAtEnd')) {
|
||||
codemirror.execCommand('goDocEnd');
|
||||
}
|
||||
},
|
||||
|
||||
// this needs to be placed on the 'afterRender' queue otherwise CodeMirror gets wonky
|
||||
initCodemirror: function () {
|
||||
// create codemirror
|
||||
var codemirror = CodeMirror.fromTextArea(this.get('element'), {
|
||||
var codemirror,
|
||||
self = this;
|
||||
|
||||
codemirror = CodeMirror.fromTextArea(this.get('element'), {
|
||||
mode: 'gfm',
|
||||
tabMode: 'indent',
|
||||
tabindex: '2',
|
||||
@ -92,7 +97,10 @@ Codemirror = Ember.TextArea.extend(MarkerManager, {
|
||||
}
|
||||
});
|
||||
|
||||
codemirror.component = this; // save reference to this
|
||||
// Codemirror needs a reference to the component
|
||||
// so that codemirror originating events can propogate
|
||||
// up the ember action pipeline
|
||||
codemirror.component = this;
|
||||
|
||||
// propagate changes to value property
|
||||
codemirror.on('change', onChangeHandler);
|
||||
@ -106,10 +114,14 @@ Codemirror = Ember.TextArea.extend(MarkerManager, {
|
||||
}));
|
||||
|
||||
codemirror.on('focus', function () {
|
||||
codemirror.component.sendAction('onFocusIn');
|
||||
self.sendAction('onFocusIn');
|
||||
});
|
||||
|
||||
this.set('codemirror', codemirror);
|
||||
codemirror.eachLine(function initMarkers() {
|
||||
self.initMarkers.apply(self, arguments);
|
||||
});
|
||||
|
||||
return codemirror;
|
||||
},
|
||||
|
||||
disableCodeMirror: function () {
|
||||
|
@ -32,30 +32,39 @@ var EditorBaseRoute = Ember.Mixin.create(styleBody, ShortcutsRoute, loadingIndic
|
||||
|
||||
willTransition: function (transition) {
|
||||
var controller = this.get('controller'),
|
||||
isDirty = controller.get('isDirty'),
|
||||
|
||||
scratch = controller.get('scratch'),
|
||||
controllerIsDirty = controller.get('isDirty'),
|
||||
model = controller.get('model'),
|
||||
isNew = model.get('isNew'),
|
||||
isSaving = model.get('isSaving'),
|
||||
isDeleted = model.get('isDeleted'),
|
||||
modelIsDirty = model.get('isDirty');
|
||||
state = model.getProperties('isDeleted', 'isSaving', 'isDirty', 'isNew'),
|
||||
fromNewToEdit,
|
||||
deletedWithoutChanges;
|
||||
|
||||
fromNewToEdit = this.get('routeName') === 'editor.new' &&
|
||||
transition.targetName === 'editor.edit' &&
|
||||
transition.intent.contexts &&
|
||||
transition.intent.contexts[0] &&
|
||||
transition.intent.contexts[0].id === model.get('id');
|
||||
|
||||
deletedWithoutChanges = state.isDeleted &&
|
||||
(state.isSaving || !state.isDirty);
|
||||
|
||||
this.send('closeSettingsMenu');
|
||||
|
||||
// when `isDeleted && isSaving`, model is in-flight, being saved
|
||||
// to the server. when `isDeleted && !isSaving && !modelIsDirty`,
|
||||
// the record has already been deleted and the deletion persisted.
|
||||
//
|
||||
// in either case we can probably just transition now.
|
||||
// in the former case the server will return the record, thereby updating it.
|
||||
// @TODO: this will break if the model fails server-side validation.
|
||||
if (!(isDeleted && isSaving) && !(isDeleted && !isSaving && !modelIsDirty) && isDirty) {
|
||||
if (!fromNewToEdit && !deletedWithoutChanges && controllerIsDirty) {
|
||||
transition.abort();
|
||||
this.send('openModal', 'leave-editor', [controller, transition]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNew) {
|
||||
// The controller may hold model state that will be lost in the transition,
|
||||
// so we need to apply it now.
|
||||
if (fromNewToEdit && controllerIsDirty) {
|
||||
if (scratch !== model.get('markdown')) {
|
||||
model.set('markdown', scratch);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.isNew) {
|
||||
model.deleteRecord();
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
<section id="entry-markdown-content" class="entry-markdown-content">
|
||||
{{gh-codemirror value=scratch scrollInfo=view.markdownScrollInfo
|
||||
setCodeMirror="setCodeMirror" openModal="openModal" typingPause="autoSave"
|
||||
focus=shouldFocusEditor onFocusIn="autoSaveNew"}}
|
||||
focus=shouldFocusEditor focusCursorAtEnd=model.isDirty onFocusIn="autoSaveNew"}}
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user