Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
⚡️ Add "Excerpt" field to post settings menu (#810)
Browse files Browse the repository at this point in the history
refs TryGhost/Ghost#8793

- add `customExcerpt` attr to Post model + reorder attrs to be alphabetical
- add "Excerpt" field to PSM
- add validation for `customExcerpt` length (max 300 chars)
- add style adjustments for custom excerpt UI
  • Loading branch information
kevinansfield authored and aileen committed Aug 1, 2017
1 parent 91ac2de commit 45210fb
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 17 deletions.
16 changes: 16 additions & 0 deletions app/components/gh-post-settings-menu.js
Expand Up @@ -30,6 +30,7 @@ export default Component.extend(SettingsMenuMixin, {

model: null,
slugValue: boundOneWay('model.slug'),
customExcerptScratch: alias('model.customExcerptScratch'),
metaTitleScratch: alias('model.metaTitleScratch'),
metaDescriptionScratch: alias('model.metaDescriptionScratch'),

Expand Down Expand Up @@ -245,6 +246,21 @@ export default Component.extend(SettingsMenuMixin, {
}
},

setCustomExcerpt(excerpt) {
let model = this.get('model');
let currentExcerpt = model.get('customExcerpt');

if (excerpt === currentExcerpt) {
return;
}

model.set('customExcerpt', excerpt);

return model.validate({property: 'customExcerpt'}).then(() => {
return model.save();
});
},

setMetaTitle(metaTitle) {
// Grab the model and current stored meta title
let model = this.get('model');
Expand Down
1 change: 1 addition & 0 deletions app/mixins/editor-base-controller.js
Expand Up @@ -158,6 +158,7 @@ export default Mixin.create({
}

this.set('model.title', this.get('model.titleScratch'));
this.set('model.customExcerpt', this.get('model.customExcerptScratch'));
this.set('model.metaTitle', this.get('model.metaTitleScratch'));
this.set('model.metaDescription', this.get('model.metaDescriptionScratch'));

Expand Down
34 changes: 18 additions & 16 deletions app/models/post.js
Expand Up @@ -73,32 +73,33 @@ export default Model.extend(Comparable, ValidationEngine, {

validationType: 'post',

uuid: attr('string'),
title: attr('string', {defaultValue: ''}),
slug: attr('string'),
mobiledoc: attr('json-string', {defaultValue: () => BLANK_DOC}),
html: attr('string'),
featureImage: attr('string'),
author: belongsTo('user', {async: true}),
authorId: attr('string'),
createdAtUTC: attr('moment-utc'),
createdBy: attr(),
customExcerpt: attr(),
featured: attr('boolean', {defaultValue: false}),
page: attr('boolean', {defaultValue: false}),
plaintext: attr('string'),
status: attr('string', {defaultValue: 'draft'}),
featureImage: attr('string'),
html: attr('string'),
locale: attr('string'),
metaTitle: attr('string'),
metaDescription: attr('string'),
author: belongsTo('user', {async: true}),
authorId: attr('string'),
updatedAtUTC: attr('moment-utc'),
updatedBy: attr(),
metaTitle: attr('string'),
mobiledoc: attr('json-string', {defaultValue: () => BLANK_DOC}),
page: attr('boolean', {defaultValue: false}),
plaintext: attr('string'),
publishedAtUTC: attr('moment-utc'),
publishedBy: belongsTo('user', {async: true}),
createdAtUTC: attr('moment-utc'),
createdBy: attr(),
slug: attr('string'),
status: attr('string', {defaultValue: 'draft'}),
tags: hasMany('tag', {
embedded: 'always',
async: false
}),
title: attr('string', {defaultValue: ''}),
updatedAtUTC: attr('moment-utc'),
updatedBy: attr(),
url: attr('string'),
uuid: attr('string'),

scratch: null,
titleScratch: null,
Expand All @@ -114,6 +115,7 @@ export default Model.extend(Comparable, ValidationEngine, {
publishedAtBlogDate: '',
publishedAtBlogTime: '',

customExcerptScratch: boundOneWay('customExcerpt'),
metaTitleScratch: boundOneWay('metaTitle'),
metaDescriptionScratch: boundOneWay('metaDescription'),

Expand Down
9 changes: 9 additions & 0 deletions app/styles/components/settings-menu.css
Expand Up @@ -179,6 +179,15 @@
stroke: color(var(--red) lightness(-10%));
}

.settings-menu-content .selectize-input {
padding: 7px 12px;
}

.post-setting-custom-excerpt {
font-size: 1.5rem;
line-height: 1.35em;
}


/* Background
/* ---------------------------------------------------------- */
Expand Down
6 changes: 6 additions & 0 deletions app/templates/components/gh-post-settings-menu.hbs
Expand Up @@ -73,6 +73,12 @@
plugins="remove_button, drag_drop"}}
</div>

{{#gh-form-group errors=model.errors hasValidated=model.hasValidated property="customExcerpt"}}
<label for="custom-excerpt">Excerpt</label>
{{gh-textarea customExcerptScratch class="post-setting-custom-excerpt" id="custom-excerpt" name="post-setting-custom-excerpt" focusOut=(action "setCustomExcerpt" customExcerptScratch) stopEnterKeyDownPropagation="true" update=(action (mut customExcerptScratch)) data-test-field="custom-excerpt"}}
{{gh-error-message errors=model.errors property="customExcerpt" data-test-error="custom-excerpt"}}
{{/gh-form-group}}

{{#unless session.user.isAuthor}}
<div class="form-group for-select">
<label for="author-list">Author</label>
Expand Down
11 changes: 10 additions & 1 deletion app/validators/post.js
Expand Up @@ -3,7 +3,7 @@ import moment from 'moment';
import {isEmpty, isPresent} from 'ember-utils';

export default BaseValidator.create({
properties: ['title', 'metaTitle', 'metaDescription', 'publishedAtBlogTime', 'publishedAtBlogDate'],
properties: ['title', 'customExcerpt', 'metaTitle', 'metaDescription', 'publishedAtBlogTime', 'publishedAtBlogDate'],

title(model) {
let title = model.get('title');
Expand All @@ -19,6 +19,15 @@ export default BaseValidator.create({
}
},

customExcerpt(model) {
let customExcerpt = model.get('customExcerpt');

if (!validator.isLength(customExcerpt, 0, 300)) {
model.get('errors').add('customExcerpt', 'Excerpt cannot be longer than 300 characters.');
this.invalidate();
}
},

metaTitle(model) {
let metaTitle = model.get('metaTitle');

Expand Down
32 changes: 32 additions & 0 deletions tests/acceptance/editor-test.js
Expand Up @@ -548,5 +548,37 @@ describe('Acceptance: Editor', function() {
'url after autosave'
).to.equal('/editor/1');
});

it('saves post settings fields', async function () {
let post = server.create('post');

await visit(`/editor/${post.id}`);

// TODO: implement tests for other fields

// changing custom excerpt auto-saves
await click(testSelector('psm-trigger'));
await fillIn(testSelector('field', 'custom-excerpt'), 'Testing excerpt');
await triggerEvent(testSelector('field', 'custom-excerpt'), 'blur');

expect(
server.db.posts[0].custom_excerpt,
'saved excerpt'
).to.equal('Testing excerpt');

// excerpt has validation
await fillIn(testSelector('field', 'custom-excerpt'), Array(302).join('a'));
await triggerEvent(testSelector('field', 'custom-excerpt'), 'blur');

expect(
find(testSelector('error', 'custom-excerpt')).text().trim(),
'excerpt too long error'
).to.match(/cannot be longer than 300/);

expect(
server.db.posts[0].custom_excerpt,
'saved excerpt after validation error'
).to.equal('Testing excerpt');
});
});
});

0 comments on commit 45210fb

Please sign in to comment.