From 7083bd0628c473a7e4375007dfc0eea5f953a999 Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Fri, 22 Nov 2024 18:24:17 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20slug=20not=20always=20up?= =?UTF-8?q?dating=20for=20draft=20posts=20(#21691)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref https://linear.app/ghost/issue/ONC-548/ There have been reported cases of the editor not updating the slug for draft posts. The logic should be as follows: for a draft post, if the title was updated and we do not detect a custom slug, update it. This got out of sync due to actions where the save was triggered but the title onBlur effect (which updates the slug) was not triggered. This has been resolved by evaluating the slug in the before save actions. --- ghost/admin/app/controllers/lexical-editor.js | 18 +++++------------- ghost/admin/tests/acceptance/editor-test.js | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/ghost/admin/app/controllers/lexical-editor.js b/ghost/admin/app/controllers/lexical-editor.js index e1e465e31a..84a1bcb650 100644 --- a/ghost/admin/app/controllers/lexical-editor.js +++ b/ghost/admin/app/controllers/lexical-editor.js @@ -734,26 +734,19 @@ export default class LexicalEditorController extends Controller { } @task - *beforeSaveTask(options = {}) { + *beforeSaveTask() { if (this.post?.isDestroyed || this.post?.isDestroying) { return; } - // ensure we remove any blank cards when performing a full save - if (!options.backgroundSave) { - // TODO: not yet implemented in react editor - // if (this._koenig) { - // this._koenig.cleanup(); - // this.set('hasDirtyAttributes', true); - // } + if (this.post.status === 'draft') { + if (this.post.titleScratch !== this.post.title) { + yield this.generateSlugTask.perform(); + } } - // Set the properties that are indirected - - // Set lexical equal to what's in the editor this.set('post.lexical', this.post.lexicalScratch || null); - // Set a default title if (!this.post.titleScratch?.trim()) { this.set('post.titleScratch', DEFAULT_TITLE); } @@ -774,7 +767,6 @@ export default class LexicalEditorController extends Controller { if (!this.get('post.slug')) { this.saveTitleTask.cancelAll(); - yield this.generateSlugTask.perform(); } } diff --git a/ghost/admin/tests/acceptance/editor-test.js b/ghost/admin/tests/acceptance/editor-test.js index 73840eefc8..61a1130bfa 100644 --- a/ghost/admin/tests/acceptance/editor-test.js +++ b/ghost/admin/tests/acceptance/editor-test.js @@ -623,6 +623,24 @@ describe('Acceptance: Editor', function () { expect(find('[data-test-editor-post-status]')).to.contain.text('New'); }); + it('updates slug when title changes without blur', async function () { + let post = this.server.create('post', {authors: [author]}); + + await visit(`/editor/post/${post.id}`); + await fillIn('[data-test-editor-title-input]', 'Test Title'); + + await triggerEvent('[data-test-editor-title-input]', 'keydown', { + keyCode: 83, // s + metaKey: ctrlOrCmd === 'command', + ctrlKey: ctrlOrCmd === 'ctrl' + }); + + let [lastRequest] = this.server.pretender.handledRequests.slice(-1); + let body = JSON.parse(lastRequest.requestBody); + expect(body.posts[0].slug).to.equal('test-title'); + expect(post.slug).to.equal('test-title'); + }); + it('handles TKs in title', async function () { let post = this.server.create('post', {authors: [author]});