mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 04:13:30 +03:00
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')}}
|
{{#if (feature 'editorSubtitle')}}
|
||||||
<GhTextarea
|
<GhTextarea
|
||||||
@class="gh-editor-subtitle"
|
@class={{concat "gh-editor-subtitle " (if @excerptErrorMessage "red")}}
|
||||||
@placeholder="Add a post excerpt..."
|
@placeholder="Add a subtitle..."
|
||||||
@shouldFocus={{false}}
|
@shouldFocus={{false}}
|
||||||
@tabindex="1"
|
@tabindex="1"
|
||||||
@autoExpand=".gh-koenig-editor"
|
@autoExpand=".gh-koenig-editor"
|
||||||
@value={{readonly this.excerpt}}
|
@value={{readonly this.excerpt}}
|
||||||
@input={{this.updateExcerpt}}
|
@input={{this.onExcerptInput}}
|
||||||
@focus-out={{optional @blurExcerpt}}
|
|
||||||
@keyDown={{this.onExcerptKeydown}}
|
@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}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -153,18 +153,8 @@ export default class GhKoenigEditorReactComponent extends Component {
|
|||||||
// Subhead ("excerpt") Actions -------------------------------------------
|
// Subhead ("excerpt") Actions -------------------------------------------
|
||||||
|
|
||||||
@action
|
@action
|
||||||
updateExcerpt(event) {
|
onExcerptInput(event) {
|
||||||
this.args.onExcerptChange?.(event.target.value);
|
this.args.setExcerpt?.(event.target.value);
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
focusExcerpt() {
|
|
||||||
this.args.onExcerptFocus?.();
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
blurExcerpt() {
|
|
||||||
this.args.onExcerptBlur?.();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -285,8 +285,13 @@ export default class LexicalEditorController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
updateExcerptScratch(excerpt) {
|
updateExcerpt(excerpt) {
|
||||||
this.set('post.customExcerptScratch', 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
|
// 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;
|
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 {
|
.gh-editor-title-divider {
|
||||||
margin: 1.6rem 0 4.8rem;
|
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 {
|
.gh-editor .tk-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15px;
|
top: 15px;
|
||||||
|
@ -62,11 +62,12 @@
|
|||||||
<GhKoenigEditorLexical
|
<GhKoenigEditorLexical
|
||||||
@title={{readonly this.post.titleScratch}}
|
@title={{readonly this.post.titleScratch}}
|
||||||
@excerpt={{readonly this.post.customExcerpt}}
|
@excerpt={{readonly this.post.customExcerpt}}
|
||||||
|
@setExcerpt={{this.updateExcerpt}}
|
||||||
|
@excerptErrorMessage={{this.excerptErrorMessage}}
|
||||||
@titleAutofocus={{this.shouldFocusTitle}}
|
@titleAutofocus={{this.shouldFocusTitle}}
|
||||||
@titlePlaceholder={{concat (capitalize this.post.displayName) " title"}}
|
@titlePlaceholder={{concat (capitalize this.post.displayName) " title"}}
|
||||||
@titleHasTk={{this.titleHasTk}}
|
@titleHasTk={{this.titleHasTk}}
|
||||||
@onTitleChange={{this.updateTitleScratch}}
|
@onTitleChange={{this.updateTitleScratch}}
|
||||||
@onExcerptChange={{this.updateExcerptScratch}}
|
|
||||||
@onTitleBlur={{perform this.saveTitleTask}}
|
@onTitleBlur={{perform this.saveTitleTask}}
|
||||||
@body={{readonly this.post.lexicalScratch}}
|
@body={{readonly this.post.lexicalScratch}}
|
||||||
@bodyPlaceholder={{concat "Begin writing your " this.post.displayName "..."}}
|
@bodyPlaceholder={{concat "Begin writing your " this.post.displayName "..."}}
|
||||||
@ -95,6 +96,7 @@
|
|||||||
}}
|
}}
|
||||||
@postType={{this.post.displayName}}
|
@postType={{this.post.displayName}}
|
||||||
@registerAPI={{this.registerEditorAPI}}
|
@registerAPI={{this.registerEditorAPI}}
|
||||||
|
@savePostTask={{this.savePostTask}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="gh-editor-wordcount-container">
|
<div class="gh-editor-wordcount-container">
|
||||||
|
@ -62,7 +62,11 @@ export default BaseValidator.create({
|
|||||||
|
|
||||||
customExcerpt(model) {
|
customExcerpt(model) {
|
||||||
if (!validator.isLength(model.customExcerpt || '', 0, 300)) {
|
if (!validator.isLength(model.customExcerpt || '', 0, 300)) {
|
||||||
|
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.');
|
model.errors.add('customExcerpt', 'Excerpt cannot be longer than 300 characters.');
|
||||||
|
}
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5,6 +5,7 @@ import {authenticateSession, invalidateSession} from 'ember-simple-auth/test-sup
|
|||||||
import {beforeEach, describe, it} from 'mocha';
|
import {beforeEach, describe, it} from 'mocha';
|
||||||
import {blur, click, currentRouteName, currentURL, fillIn, find, findAll, triggerEvent, typeIn} from '@ember/test-helpers';
|
import {blur, click, currentRouteName, currentURL, fillIn, find, findAll, triggerEvent, typeIn} from '@ember/test-helpers';
|
||||||
import {datepickerSelect} from 'ember-power-datepicker/test-support';
|
import {datepickerSelect} from 'ember-power-datepicker/test-support';
|
||||||
|
import {enableLabsFlag} from '../helpers/labs-flag';
|
||||||
import {expect} from 'chai';
|
import {expect} from 'chai';
|
||||||
import {selectChoose} from 'ember-power-select/test-support';
|
import {selectChoose} from 'ember-power-select/test-support';
|
||||||
import {setupApplicationTest} from 'ember-mocha';
|
import {setupApplicationTest} from 'ember-mocha';
|
||||||
@ -490,6 +491,38 @@ describe('Acceptance: Editor', function () {
|
|||||||
).to.equal(0);
|
).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
|
// https://github.com/TryGhost/Ghost/issues/11786
|
||||||
// NOTE: Flaky test with moving to Lexical editor, skipping for now
|
// NOTE: Flaky test with moving to Lexical editor, skipping for now
|
||||||
it.skip('save shortcut works when tags/authors field is focused', async function () {
|
it.skip('save shortcut works when tags/authors field is focused', async function () {
|
||||||
|
Loading…
Reference in New Issue
Block a user