Ghost/ghost/admin/app/components/gh-post-settings-menu.js
Naz 3cd1c56d4e Added email only checkbox to PSM
closes https://github.com/TryGhost/Team/issues/896

- Having this checkbox allows user to control posts email_only flag
- Also sets the post automatically to "public" when the email-only toggle is switched on as the access would be controlled form within email and not through the internal gatekeeping mechanism
2021-08-04 17:13:52 +04:00

516 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Component from '@ember/component';
import boundOneWay from 'ghost-admin/utils/bound-one-way';
import moment from 'moment';
import {action} from '@ember/object';
import {alias, or} from '@ember/object/computed';
import {computed} from '@ember/object';
import {inject as service} from '@ember/service';
export default Component.extend({
feature: service(),
store: service(),
config: service(),
ajax: service(),
ghostPaths: service(),
notifications: service(),
slugGenerator: service(),
session: service(),
settings: service(),
ui: service(),
tagName: '',
post: null,
isViewingSubview: false,
canonicalUrlScratch: alias('post.canonicalUrlScratch'),
customExcerptScratch: alias('post.customExcerptScratch'),
codeinjectionFootScratch: alias('post.codeinjectionFootScratch'),
codeinjectionHeadScratch: alias('post.codeinjectionHeadScratch'),
metaDescriptionScratch: alias('post.metaDescriptionScratch'),
metaTitleScratch: alias('post.metaTitleScratch'),
ogDescriptionScratch: alias('post.ogDescriptionScratch'),
ogTitleScratch: alias('post.ogTitleScratch'),
twitterDescriptionScratch: alias('post.twitterDescriptionScratch'),
twitterTitleScratch: alias('post.twitterTitleScratch'),
slugValue: boundOneWay('post.slug'),
seoDescription: or('metaDescriptionScratch', 'customExcerptScratch', 'post.excerpt'),
facebookDescription: or('ogDescriptionScratch', 'customExcerptScratch', 'seoDescription', 'post.excerpt', 'settings.description', ''),
facebookImage: or('post.ogImage', 'post.featureImage', 'settings.ogImage', 'settings.coverImage'),
facebookTitle: or('ogTitleScratch', 'seoTitle'),
twitterDescription: or('twitterDescriptionScratch', 'customExcerptScratch', 'seoDescription', 'post.excerpt', 'settings.description', ''),
twitterImage: or('post.twitterImage', 'post.featureImage', 'settings.twitterImage', 'settings.coverImage'),
twitterTitle: or('twitterTitleScratch', 'seoTitle'),
showEmailNewsletter: or('session.user.isOwnerOnly', 'session.user.isAdminOnly', 'session.user.isEditor'),
showEmailOnlyInput: computed('post.isPost', function () {
return this.feature.get('emailOnlyPosts') && this.get('post.isPost');
}),
showVisibilityInput: computed('post.emailOnly', function () {
if (this.get('post.emailOnly')) {
return false;
}
return this.get('session.user.isOwnerOnly') || this.get('session.user.isAdminOnly') || this.get('session.user.isEditor');
}),
seoTitle: computed('metaTitleScratch', 'post.titleScratch', function () {
return this.metaTitleScratch || this.post.titleScratch || '(Untitled)';
}),
seoURL: computed('post.{slug,canonicalUrl}', 'config.blogUrl', function () {
const urlParts = [];
if (this.post.canonicalUrl) {
try {
const canonicalUrl = new URL(this.post.canonicalUrl);
urlParts.push(canonicalUrl.host);
urlParts.push(...canonicalUrl.pathname.split('/').reject(p => !p));
} catch (e) {
// no-op, invalid URL
}
} else {
const blogUrl = new URL(this.config.get('blogUrl'));
urlParts.push(blogUrl.host);
urlParts.push(...blogUrl.pathname.split('/').reject(p => !p));
urlParts.push(this.post.slug);
}
return urlParts.join(' ');
}),
willDestroyElement() {
this._super(...arguments);
let post = this.post;
let errors = post.get('errors');
// reset the publish date if it has an error
if (errors.has('publishedAtBlogDate') || errors.has('publishedAtBlogTime')) {
post.set('publishedAtBlogTZ', post.get('publishedAtUTC'));
post.validate({attribute: 'publishedAtBlog'});
}
this.setSidebarWidthVariable(0);
},
actions: {
showSubview(subview) {
this.set('isViewingSubview', true);
this.set('subview', subview);
},
closeSubview() {
this.set('isViewingSubview', false);
this.set('subview', null);
},
discardEnter() {
return false;
},
toggleEmailOnly() {
this.toggleProperty('post.emailOnly');
this.set('post.visibility', 'public');
},
toggleFeatured() {
this.toggleProperty('post.featured');
// If this is a new post. Don't save the post. Defer the save
// to the user pressing the save button
if (this.get('post.isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
/**
* triggered by user manually changing slug
*/
updateSlug(newSlug) {
return this.updateSlugTask
.perform(newSlug)
.catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
setPublishedAtBlogDate(date) {
let post = this.post;
let dateString = moment(date).format('YYYY-MM-DD');
post.get('errors').remove('publishedAtBlogDate');
if (post.get('isNew') || date === post.get('publishedAtBlogDate')) {
post.validate({property: 'publishedAtBlog'});
} else {
post.set('publishedAtBlogDate', dateString);
return this.savePostTask.perform();
}
},
async setVisibility(segment) {
this.post.set('visibilityFilter', segment);
try {
await this.post.validate({property: 'visibility'});
await this.post.validate({property: 'visibilityFilter'});
if (this.post.changedAttributes().visibilityFilter) {
await this.savePostTask.perform();
}
} catch (e) {
if (!e) {
// validation error
return;
}
throw e;
}
},
setPublishedAtBlogTime(time) {
let post = this.post;
post.get('errors').remove('publishedAtBlogDate');
if (post.get('isNew') || time === post.get('publishedAtBlogTime')) {
post.validate({property: 'publishedAtBlog'});
} else {
post.set('publishedAtBlogTime', time);
return this.savePostTask.perform();
}
},
setCustomExcerpt(excerpt) {
let post = this.post;
let currentExcerpt = post.get('customExcerpt');
if (excerpt === currentExcerpt) {
return;
}
post.set('customExcerpt', excerpt);
return post.validate({property: 'customExcerpt'}).then(() => this.savePostTask.perform());
},
setHeaderInjection(code) {
let post = this.post;
let currentCode = post.get('codeinjectionHead');
if (code === currentCode) {
return;
}
post.set('codeinjectionHead', code);
return post.validate({property: 'codeinjectionHead'}).then(() => this.savePostTask.perform());
},
setFooterInjection(code) {
let post = this.post;
let currentCode = post.get('codeinjectionFoot');
if (code === currentCode) {
return;
}
post.set('codeinjectionFoot', code);
return post.validate({property: 'codeinjectionFoot'}).then(() => this.savePostTask.perform());
},
setMetaTitle(metaTitle) {
// Grab the post and current stored meta title
let post = this.post;
let currentTitle = post.get('metaTitle');
// If the title entered matches the stored meta title, do nothing
if (currentTitle === metaTitle) {
return;
}
// If the title entered is different, set it as the new meta title
post.set('metaTitle', metaTitle);
// Make sure the meta title is valid and if so, save it into the post
return post.validate({property: 'metaTitle'}).then(() => {
if (post.get('isNew')) {
return;
}
return this.savePostTask.perform();
});
},
setMetaDescription(metaDescription) {
// Grab the post and current stored meta description
let post = this.post;
let currentDescription = post.get('metaDescription');
// If the title entered matches the stored meta title, do nothing
if (currentDescription === metaDescription) {
return;
}
// If the title entered is different, set it as the new meta title
post.set('metaDescription', metaDescription);
// Make sure the meta title is valid and if so, save it into the post
return post.validate({property: 'metaDescription'}).then(() => {
if (post.get('isNew')) {
return;
}
return this.savePostTask.perform();
});
},
setCanonicalUrl(value) {
// Grab the post and current stored meta description
let post = this.post;
let currentCanonicalUrl = post.canonicalUrl;
// If the value entered matches the stored value, do nothing
if (currentCanonicalUrl === value) {
return;
}
// If the value supplied is different, set it as the new value
post.set('canonicalUrl', value);
// Make sure the value is valid and if so, save it into the post
return post.validate({property: 'canonicalUrl'}).then(() => {
if (post.get('isNew')) {
return;
}
return this.savePostTask.perform();
});
},
setOgTitle(ogTitle) {
// Grab the post and current stored facebook title
let post = this.post;
let currentTitle = post.get('ogTitle');
// If the title entered matches the stored facebook title, do nothing
if (currentTitle === ogTitle) {
return;
}
// If the title entered is different, set it as the new facebook title
post.set('ogTitle', ogTitle);
// Make sure the facebook title is valid and if so, save it into the post
return post.validate({property: 'ogTitle'}).then(() => {
if (post.get('isNew')) {
return;
}
return this.savePostTask.perform();
});
},
setOgDescription(ogDescription) {
// Grab the post and current stored facebook description
let post = this.post;
let currentDescription = post.get('ogDescription');
// If the title entered matches the stored facebook description, do nothing
if (currentDescription === ogDescription) {
return;
}
// If the description entered is different, set it as the new facebook description
post.set('ogDescription', ogDescription);
// Make sure the facebook description is valid and if so, save it into the post
return post.validate({property: 'ogDescription'}).then(() => {
if (post.get('isNew')) {
return;
}
return this.savePostTask.perform();
});
},
setTwitterTitle(twitterTitle) {
// Grab the post and current stored twitter title
let post = this.post;
let currentTitle = post.get('twitterTitle');
// If the title entered matches the stored twitter title, do nothing
if (currentTitle === twitterTitle) {
return;
}
// If the title entered is different, set it as the new twitter title
post.set('twitterTitle', twitterTitle);
// Make sure the twitter title is valid and if so, save it into the post
return post.validate({property: 'twitterTitle'}).then(() => {
if (post.get('isNew')) {
return;
}
return this.savePostTask.perform();
});
},
setTwitterDescription(twitterDescription) {
// Grab the post and current stored twitter description
let post = this.post;
let currentDescription = post.get('twitterDescription');
// If the description entered matches the stored twitter description, do nothing
if (currentDescription === twitterDescription) {
return;
}
// If the description entered is different, set it as the new twitter description
post.set('twitterDescription', twitterDescription);
// Make sure the twitter description is valid and if so, save it into the post
return post.validate({property: 'twitterDescription'}).then(() => {
if (post.get('isNew')) {
return;
}
return this.savePostTask.perform();
});
},
setCoverImage(image) {
this.set('post.featureImage', image);
if (this.get('post.isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
clearCoverImage() {
this.set('post.featureImage', '');
if (this.get('post.isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
setOgImage(image) {
this.set('post.ogImage', image);
if (this.get('post.isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
clearOgImage() {
this.set('post.ogImage', '');
if (this.get('post.isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
setTwitterImage(image) {
this.set('post.twitterImage', image);
if (this.get('post.isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
clearTwitterImage() {
this.set('post.twitterImage', '');
if (this.get('post.isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
this.post.rollbackAttributes();
});
},
changeAuthors(newAuthors) {
let post = this.post;
// return if nothing changed
if (newAuthors.mapBy('id').join() === post.get('authors').mapBy('id').join()) {
return;
}
post.set('authors', newAuthors);
post.validate({property: 'authors'});
// if this is a new post (never been saved before), don't try to save it
if (post.get('isNew')) {
return;
}
this.savePostTask.perform().catch((error) => {
this.showError(error);
post.rollbackAttributes();
});
},
deletePost() {
if (this.deletePost) {
this.deletePost();
}
}
},
showError(error) {
// TODO: remove null check once ValidationEngine has been removed
if (error) {
this.notifications.showAPIError(error);
}
},
setSidebarWidthFromElement: action(function (element) {
const width = element.getBoundingClientRect().width;
this.setSidebarWidthVariable(width);
}),
setSidebarWidthVariable(width) {
document.documentElement.style.setProperty('--editor-sidebar-width', `${width}px`);
}
});