Added validation logic to in-editor subtitle (#20284)
closes https://linear.app/tryghost/issue/MOM-150 - use our validation engine to display an error state when >300 characters have been typed in the subtitle input field --------- Co-authored-by: Sanne de Vries <sannedv@protonmail.com> Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
This commit is contained in:
parent
9891abd61c
commit
833ac83921
@ -59,18 +59,22 @@
|
||||
|
||||
{{#if (feature 'editorSubtitle')}}
|
||||
<GhTextarea
|
||||
@class="gh-editor-subtitle"
|
||||
@placeholder="Add a post excerpt..."
|
||||
@class={{concat "gh-editor-subtitle " (if @excerptErrorMessage "red")}}
|
||||
@placeholder="Add a subtitle..."
|
||||
@shouldFocus={{false}}
|
||||
@tabindex="1"
|
||||
@autoExpand=".gh-koenig-editor"
|
||||
@value={{readonly this.excerpt}}
|
||||
@input={{this.updateExcerpt}}
|
||||
@focus-out={{optional @blurExcerpt}}
|
||||
@input={{this.onExcerptInput}}
|
||||
@keyDown={{this.onExcerptKeydown}}
|
||||
data-test-editor-subhead-input={{true}}
|
||||
data-test-textarea="subtitle"
|
||||
/>
|
||||
<hr class="gh-editor-title-divider">
|
||||
{{#if @excerptErrorMessage}}
|
||||
<div class="gh-editor-subtitle-error" data-test-error="subtitle">
|
||||
{{@excerptErrorMessage}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<hr class="gh-editor-title-divider {{if @excerptErrorMessage "gh-editor-title-divider-error" ""}}">
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
@ -153,18 +153,8 @@ export default class GhKoenigEditorReactComponent extends Component {
|
||||
// Subhead ("excerpt") Actions -------------------------------------------
|
||||
|
||||
@action
|
||||
updateExcerpt(event) {
|
||||
this.args.onExcerptChange?.(event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
focusExcerpt() {
|
||||
this.args.onExcerptFocus?.();
|
||||
}
|
||||
|
||||
@action
|
||||
blurExcerpt() {
|
||||
this.args.onExcerptBlur?.();
|
||||
onExcerptInput(event) {
|
||||
this.args.setExcerpt?.(event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -285,8 +285,13 @@ export default class LexicalEditorController extends Controller {
|
||||
}
|
||||
|
||||
@action
|
||||
updateExcerptScratch(excerpt) {
|
||||
this.set('post.customExcerptScratch', excerpt);
|
||||
updateExcerpt(excerpt) {
|
||||
this.post.customExcerpt = excerpt;
|
||||
this.post.validate({property: 'customExcerpt'});
|
||||
}
|
||||
|
||||
get excerptErrorMessage() {
|
||||
return this.post.errors.errorsFor('customExcerpt')?.[0]?.message;
|
||||
}
|
||||
|
||||
// updates local willPublish/Schedule values, does not get applied to
|
||||
|
@ -811,10 +811,22 @@ body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.gh-editor-subtitle-error {
|
||||
margin-top: .8rem;
|
||||
color: var(--red-d1);
|
||||
font-size: 1.4rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.gh-editor-title-divider {
|
||||
margin: 1.6rem 0 4.8rem;
|
||||
}
|
||||
|
||||
.gh-editor-title-divider-error {
|
||||
margin: .4rem 0 4.8rem;
|
||||
border-top: 1px solid var(--red);
|
||||
}
|
||||
|
||||
.gh-editor .tk-indicator {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
|
@ -62,11 +62,12 @@
|
||||
<GhKoenigEditorLexical
|
||||
@title={{readonly this.post.titleScratch}}
|
||||
@excerpt={{readonly this.post.customExcerpt}}
|
||||
@setExcerpt={{this.updateExcerpt}}
|
||||
@excerptErrorMessage={{this.excerptErrorMessage}}
|
||||
@titleAutofocus={{this.shouldFocusTitle}}
|
||||
@titlePlaceholder={{concat (capitalize this.post.displayName) " title"}}
|
||||
@titleHasTk={{this.titleHasTk}}
|
||||
@onTitleChange={{this.updateTitleScratch}}
|
||||
@onExcerptChange={{this.updateExcerptScratch}}
|
||||
@onTitleBlur={{perform this.saveTitleTask}}
|
||||
@body={{readonly this.post.lexicalScratch}}
|
||||
@bodyPlaceholder={{concat "Begin writing your " this.post.displayName "..."}}
|
||||
@ -95,6 +96,7 @@
|
||||
}}
|
||||
@postType={{this.post.displayName}}
|
||||
@registerAPI={{this.registerEditorAPI}}
|
||||
@savePostTask={{this.savePostTask}}
|
||||
/>
|
||||
|
||||
<div class="gh-editor-wordcount-container">
|
||||
|
@ -62,7 +62,11 @@ export default BaseValidator.create({
|
||||
|
||||
customExcerpt(model) {
|
||||
if (!validator.isLength(model.customExcerpt || '', 0, 300)) {
|
||||
model.errors.add('customExcerpt', 'Excerpt cannot be longer than 300 characters.');
|
||||
if (model.feature.editorSubtitle) {
|
||||
model.errors.add('customExcerpt', 'Please keep the subtitle under 300 characters.');
|
||||
} else {
|
||||
model.errors.add('customExcerpt', 'Excerpt cannot be longer than 300 characters.');
|
||||
}
|
||||
this.invalidate();
|
||||
}
|
||||
},
|
||||
|
@ -5,6 +5,7 @@ import {authenticateSession, invalidateSession} from 'ember-simple-auth/test-sup
|
||||
import {beforeEach, describe, it} from 'mocha';
|
||||
import {blur, click, currentRouteName, currentURL, fillIn, find, findAll, triggerEvent, typeIn} from '@ember/test-helpers';
|
||||
import {datepickerSelect} from 'ember-power-datepicker/test-support';
|
||||
import {enableLabsFlag} from '../helpers/labs-flag';
|
||||
import {expect} from 'chai';
|
||||
import {selectChoose} from 'ember-power-select/test-support';
|
||||
import {setupApplicationTest} from 'ember-mocha';
|
||||
@ -490,6 +491,38 @@ describe('Acceptance: Editor', function () {
|
||||
).to.equal(0);
|
||||
});
|
||||
|
||||
it('handles in-editor excerpt update and validation', async function () {
|
||||
enableLabsFlag(this.server, 'editorSubtitle');
|
||||
|
||||
let post = this.server.create('post', {authors: [author], customExcerpt: 'Existing excerpt'});
|
||||
|
||||
await visit(`/editor/post/${post.id}`);
|
||||
|
||||
expect(find('[data-test-textarea="subtitle"]'), 'initial textarea').to.be.visible;
|
||||
expect(find('[data-test-textarea="subtitle"]'), 'initial textarea').to.have.value('Existing excerpt');
|
||||
|
||||
await fillIn('[data-test-textarea="subtitle"]', 'New excerpt');
|
||||
expect(find('[data-test-textarea="subtitle"]'), 'updated textarea').to.have.value('New excerpt');
|
||||
|
||||
await triggerEvent('[data-test-textarea="subtitle"]', 'keydown', {
|
||||
key: 's',
|
||||
keyCode: 83, // s
|
||||
metaKey: ctrlOrCmd === 'command',
|
||||
ctrlKey: ctrlOrCmd === 'ctrl'
|
||||
});
|
||||
|
||||
expect(post.customExcerpt, 'saved excerpt').to.equal('New excerpt');
|
||||
|
||||
await fillIn('[data-test-textarea="subtitle"]', Array(302).join('a'));
|
||||
|
||||
expect(find('[data-test-error="subtitle"]'), 'subtitle error').to.exist;
|
||||
expect(find('[data-test-error="subtitle"]')).to.have.trimmed.text('Please keep the subtitle under 300 characters.');
|
||||
|
||||
await fillIn('[data-test-textarea="subtitle"]', Array(300).join('a'));
|
||||
|
||||
expect(find('[data-test-error="subtitle"]'), 'subtitle error').to.not.exist;
|
||||
});
|
||||
|
||||
// https://github.com/TryGhost/Ghost/issues/11786
|
||||
// NOTE: Flaky test with moving to Lexical editor, skipping for now
|
||||
it.skip('save shortcut works when tags/authors field is focused', async function () {
|
||||
|
Loading…
Reference in New Issue
Block a user