From d37f68adcbbc0c537e727024cd6923f979e5d488 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Mon, 10 Jul 2017 12:33:05 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix=20autosave+transition=20on?= =?UTF-8?q?=20title=20blur=20with=20empty=20title=20(#767)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refs TryGhost/Ghost#8525 - fix `saveTitle` action - don't abort title save when we have an empty title - force a "dirty" state so that the save actually happens - add acceptance test for title blur behaviour - extract multiple instances `"(Untitled)"` into a const --- .../app/mixins/editor-base-controller.js | 14 ++++++---- ghost/admin/mirage/config/posts.js | 4 +++ ghost/admin/tests/acceptance/editor-test.js | 28 +++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/ghost/admin/app/mixins/editor-base-controller.js b/ghost/admin/app/mixins/editor-base-controller.js index ae64ebdd01..aa5e11e45a 100644 --- a/ghost/admin/app/mixins/editor-base-controller.js +++ b/ghost/admin/app/mixins/editor-base-controller.js @@ -25,6 +25,7 @@ const {testing} = Ember; // to know if the model has been changed (`controller.hasDirtyAttributes`) const watchedProps = ['model.scratch', 'model.titleScratch', 'model.hasDirtyAttributes', 'model.tags.[]']; +const DEFAULT_TITLE = '(Untitled)'; const TITLE_DEBOUNCE = testing ? 10 : 700; PostModel.eachAttribute(function (name) { @@ -148,7 +149,7 @@ export default Mixin.create({ // Set a default title if (!this.get('model.titleScratch').trim()) { - this.set('model.titleScratch', '(Untitled)'); + this.set('model.titleScratch', DEFAULT_TITLE); } this.set('model.title', this.get('model.titleScratch')); @@ -492,9 +493,9 @@ export default Mixin.create({ model.set('titleScratch', newTitle); - // if model is not new and title is not '(Untitled)', or model is new and + // if model is not new and title is not DEFAULT_TITLE, or model is new and // has a title, don't generate a slug - if ((!model.get('isNew') || model.get('title')) && newTitle !== '(Untitled)') { + if ((!model.get('isNew') || model.get('title')) && newTitle !== DEFAULT_TITLE) { return; } @@ -508,7 +509,7 @@ export default Mixin.create({ let title = this.get('model.titleScratch'); // Only set an "untitled" slug once per post - if (title === '(Untitled)' && this.get('model.slug')) { + if (title === DEFAULT_TITLE && this.get('model.slug')) { return; } @@ -606,10 +607,13 @@ export default Mixin.create({ let currentTitle = this.get('model.title'); let newTitle = this.get('model.titleScratch').trim(); - if (newTitle === currentTitle) { + if (currentTitle && newTitle && newTitle === currentTitle) { return; } + // this is necessary to force a save when the title is blank + this.set('hasDirtyAttributes', true); + if (this.get('model.isDraft')) { this.send('save', { silent: true, diff --git a/ghost/admin/mirage/config/posts.js b/ghost/admin/mirage/config/posts.js index 476a1dbce7..e2e9444dc3 100644 --- a/ghost/admin/mirage/config/posts.js +++ b/ghost/admin/mirage/config/posts.js @@ -7,6 +7,10 @@ export default function mockPosts(server) { server.post('/posts', function ({posts}) { let attrs = this.normalizedRequestAttrs(); + // mirage expects `author` to be a reference but we only have an ID + attrs.authorId = attrs.author; + delete attrs.author; + if (isBlank(attrs.slug) && !isBlank(attrs.title)) { attrs.slug = dasherize(attrs.title); } diff --git a/ghost/admin/tests/acceptance/editor-test.js b/ghost/admin/tests/acceptance/editor-test.js index 337fe21718..77008286f4 100644 --- a/ghost/admin/tests/acceptance/editor-test.js +++ b/ghost/admin/tests/acceptance/editor-test.js @@ -520,5 +520,33 @@ describe('Acceptance: Editor', function() { expect(find('select[name="post-setting-author"]').val()).to.equal('2'); expect(server.db.posts[0].authorId).to.equal(author.id); }); + + it('autosaves when title loses focus', async function () { + let role = server.create('role', {name: 'Administrator'}); + server.create('user', {name: 'Admin', roles: [role]}); + + await visit('/editor'); + + // NOTE: there were checks here for the title element having focus + // but they were very temperamental whilst running tests in the + // browser so they've been left out for now + + expect( + currentURL(), + 'url on initial visit' + ).to.equal('/editor'); + + await triggerEvent(testSelector('editor-title-input'), 'blur'); + + expect( + find(testSelector('editor-title-input')).val(), + 'title value after autosave' + ).to.equal('(Untitled)'); + + expect( + currentURL(), + 'url after autosave' + ).to.equal('/editor/1'); + }); }); });