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() {