diff --git a/core/client/components/gh-codemirror.js b/core/client/components/gh-codemirror.js
index a739d0dd5a..c65fee6d41 100644
--- a/core/client/components/gh-codemirror.js
+++ b/core/client/components/gh-codemirror.js
@@ -38,6 +38,14 @@ var onScrollHandler = function (cm) {
};
var Codemirror = Ember.TextArea.extend(MarkerManager, {
+ focus: true,
+
+ setFocus: function () {
+ if (this.focus) {
+ this.$().val(this.$().val()).focus();
+ }
+ }.on('didInsertElement'),
+
didInsertElement: function () {
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
@@ -90,6 +98,10 @@ var Codemirror = Ember.TextArea.extend(MarkerManager, {
offset: 10
}));
+ codemirror.on('focus', function () {
+ codemirror.component.sendAction('onFocusIn');
+ });
+
this.set('codemirror', codemirror);
},
diff --git a/core/client/controllers/editor/new.js b/core/client/controllers/editor/new.js
index 3a1e0735df..94c109c0c9 100644
--- a/core/client/controllers/editor/new.js
+++ b/core/client/controllers/editor/new.js
@@ -9,7 +9,7 @@ var EditorNewController = Ember.ObjectController.extend(EditorControllerMixin, {
var self = this;
return this._super(options).then(function (model) {
if (model.get('id')) {
- self.transitionToRoute('editor.edit', model);
+ self.replaceRoute('editor.edit', model);
}
});
}
diff --git a/core/client/controllers/post-settings-menu.js b/core/client/controllers/post-settings-menu.js
index 91e6234f4a..2b9b1d4a31 100644
--- a/core/client/controllers/post-settings-menu.js
+++ b/core/client/controllers/post-settings-menu.js
@@ -87,12 +87,12 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
});
}),
//Requests slug from title
- generateSlugPlaceholder: function () {
+ generateAndSetSlug: function (destination) {
var self = this,
title = this.get('titleScratch');
this.get('slugGenerator').generateSlug(title).then(function (slug) {
- self.set('slugPlaceholder', slug);
+ self.set(destination, slug);
});
},
@@ -163,13 +163,15 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
// observe titleScratch, keeping the post's slug in sync
// with it until saved for the first time.
addTitleObserver: function () {
- if (this.get('isNew')) {
+ if (this.get('isNew') || this.get('title') === '(Untitled)') {
this.addObserver('titleScratch', this, 'titleObserver');
}
}.observes('model'),
titleObserver: function () {
if (this.get('isNew') && !this.get('title')) {
- Ember.run.debounce(this, 'generateSlugPlaceholder', 700);
+ Ember.run.debounce(this, 'generateAndSetSlug', ['slugPlaceholder'], 700);
+ } else if (this.get('title') === '(Untitled)') {
+ Ember.run.debounce(this, 'generateAndSetSlug', ['slug'], 700);
}
},
slugPlaceholder: Ember.computed(function (key, value) {
diff --git a/core/client/mixins/editor-base-controller.js b/core/client/mixins/editor-base-controller.js
index 094da3cba3..762c7669ef 100644
--- a/core/client/mixins/editor-base-controller.js
+++ b/core/client/mixins/editor-base-controller.js
@@ -187,6 +187,7 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
},
shouldFocusTitle: Ember.computed.alias('model.isNew'),
+ shouldFocusEditor: Ember.computed.not('model.isNew'),
actions: {
save: function (options) {
@@ -210,6 +211,7 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
if (!this.get('titleScratch')) {
this.set('titleScratch', '(Untitled)');
}
+
this.set('title', this.get('titleScratch'));
return this.get('model').save(options).then(function (model) {
@@ -296,6 +298,12 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
if (this.get('model.isDraft')) {
this.send('save', {silent: true, disableNProgress: true});
}
+ },
+
+ autoSaveNew: function () {
+ if (this.get('isNew')) {
+ this.send('autoSave');
+ }
}
}
});
diff --git a/core/client/templates/editor/edit.hbs b/core/client/templates/editor/edit.hbs
index 4946cea1f9..421e12a92e 100644
--- a/core/client/templates/editor/edit.hbs
+++ b/core/client/templates/editor/edit.hbs
@@ -6,7 +6,8 @@
- {{gh-trim-focus-input type="text" id="entry-title" placeholder="Your Post Title" value=titleScratch tabindex="1" focus=shouldFocusTitle}}
+ {{gh-trim-focus-input type="text" id="entry-title" placeholder="Your Post Title" value=titleScratch
+ tabindex="1" focus=shouldFocusTitle}}
@@ -17,9 +18,8 @@
{{gh-codemirror value=scratch scrollInfo=view.markdownScrollInfo
- setCodeMirror="setCodeMirror"
- openModal="openModal"
- typingPause="autoSave"}}
+ setCodeMirror="setCodeMirror" openModal="openModal" typingPause="autoSave"
+ focus=shouldFocusEditor onFocusIn="autoSaveNew"}}
diff --git a/core/client/views/editor-save-button.js b/core/client/views/editor-save-button.js
index c24db2706a..35f376ba92 100644
--- a/core/client/views/editor-save-button.js
+++ b/core/client/views/editor-save-button.js
@@ -18,7 +18,7 @@ var EditorSaveButtonView = Ember.View.extend({
'saveText': Ember.computed('controller.willPublish', function () {
return this.get('controller.willPublish') ? this.get('publishText') : this.get('draftText');
- }),
+ })
});
export default EditorSaveButtonView;
diff --git a/core/test/functional/base.js b/core/test/functional/base.js
index e49d58931c..8974e056cb 100644
--- a/core/test/functional/base.js
+++ b/core/test/functional/base.js
@@ -126,6 +126,22 @@ screens = {
casper.writeContentToCodeMirror = function (content) {
var lines = content.split('\n');
+ // If we are on a new editor, the autosave is going to get triggered when we try to type, so we need to trigger
+ // that and wait for it to sort itself out
+ if (/ghost\/editor\/$/.test(casper.getCurrentUrl())) {
+ casper.waitForSelector('.CodeMirror-wrap textarea', function onSuccess() {
+ casper.click('.CodeMirror-wrap textarea');
+ }, function onTimeout() {
+ casper.test.fail('CodeMirror was not found on initial load.');
+ }, 2000);
+
+ casper.waitForUrl(/\/ghost\/editor\/\d+\/$/, function onSuccess() {
+ // do nothing
+ }, function onTimeout() {
+ casper.test.fail('The url didn\'t change: ' + casper.getCurrentUrl());
+ }, 2000);
+ }
+
casper.waitForSelector('.CodeMirror-wrap textarea', function onSuccess() {
casper.each(lines, function (self, line) {
self.sendKeys('.CodeMirror-wrap textarea', line, {keepFocus: true});
@@ -136,7 +152,7 @@ casper.writeContentToCodeMirror = function (content) {
return this;
}, function onTimeout() {
- casper.test.fail('CodeMirror was not found.');
+ casper.test.fail('CodeMirror was not found on main load.');
}, 2000);
};
diff --git a/core/test/functional/client/app_test.js b/core/test/functional/client/app_test.js
index 675685aeee..033ca251cd 100644
--- a/core/test/functional/client/app_test.js
+++ b/core/test/functional/client/app_test.js
@@ -73,7 +73,7 @@ CasperTest.begin('Can transition to the editor and back', 6, function suite(test
});
casper.thenTransitionAndWaitForScreenLoad('editor', function testTransitionToEditor() {
- test.assertUrlMatch(/ghost\/editor\/$/, 'Landed on the correct URL');
+ test.assertUrlMatch(/ghost\/editor\//, 'Landed on the correct URL');
test.assertExists('.entry-markdown', 'Ghost editor is present');
test.assertExists('.entry-preview', 'Ghost preview is present');
});
diff --git a/core/test/functional/client/content_test.js b/core/test/functional/client/content_test.js
index 80f1adab7c..5738cd34d1 100644
--- a/core/test/functional/client/content_test.js
+++ b/core/test/functional/client/content_test.js
@@ -62,7 +62,7 @@ CasperTest.begin('Content list shows correct post status', 5, function testStati
});
// Select first non-draft, non-static post. Should be second in the list at this stage of testing.
- casper.thenClick('.content-list-content li:nth-of-type(2) a');
+ casper.thenClick('.content-list-content li:nth-of-type(3) a');
// Test for status of 'Published'
casper.then(function checkStatus() {
diff --git a/core/test/functional/client/editor_test.js b/core/test/functional/client/editor_test.js
index ec8d487640..91b72c5b20 100644
--- a/core/test/functional/client/editor_test.js
+++ b/core/test/functional/client/editor_test.js
@@ -330,15 +330,6 @@ CasperTest.begin('Publish menu - existing post', 23, function suite(test) {
test.assertUrlMatch(/ghost\/editor\/$/, 'Landed on the correct URL');
});
- casper.then(function createTestPost() {
- casper.sendKeys('#entry-title', testPost.title);
- casper.writeContentToCodeMirror(testPost.html);
- });
-
- casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
- test.assertSelectorHasText('.entry-preview .rendered-markdown', 'test', 'Editor value is correct');
- });
-
casper.thenClick('.js-publish-splitbutton .dropdown-toggle');
casper.waitForOpaque('.js-publish-splitbutton .dropdown-menu', function onSuccess() {
@@ -348,6 +339,15 @@ CasperTest.begin('Publish menu - existing post', 23, function suite(test) {
);
});
+ casper.then(function createTestPost() {
+ casper.sendKeys('#entry-title', testPost.title);
+ casper.writeContentToCodeMirror(testPost.html);
+ });
+
+ casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
+ test.assertSelectorHasText('.entry-preview .rendered-markdown', 'test', 'Editor value is correct');
+ });
+
casper.thenClick('.js-publish-splitbutton .dropdown-toggle');
// Create a post in draft status
@@ -501,7 +501,6 @@ CasperTest.begin('Publish menu - new post status is correct after failed save',
// Fill title and content
casper.then(function writePost() {
casper.sendKeys('#entry-title', new Array(160).join('x'));
- casper.writeContentToCodeMirror('body content');
});
casper.then(function switchMenuToPublish() {