2017-08-22 10:53:26 +03:00
|
|
|
import Component from '@ember/component';
|
2017-03-10 17:30:01 +03:00
|
|
|
import SettingsMenuMixin from 'ghost-admin/mixins/settings-menu-component';
|
2016-05-24 15:06:59 +03:00
|
|
|
import boundOneWay from 'ghost-admin/utils/bound-one-way';
|
2017-05-30 16:07:12 +03:00
|
|
|
import formatMarkdown from 'ghost-admin/utils/format-markdown';
|
2017-04-05 20:45:35 +03:00
|
|
|
import moment from 'moment';
|
2017-08-22 10:53:26 +03:00
|
|
|
import {alias, or} from '@ember/object/computed';
|
|
|
|
import {computed} from '@ember/object';
|
|
|
|
import {run} from '@ember/runloop';
|
2017-10-30 12:38:01 +03:00
|
|
|
import {inject as service} from '@ember/service';
|
2017-06-08 18:00:10 +03:00
|
|
|
import {task, timeout} from 'ember-concurrency';
|
2014-06-08 10:02:21 +04:00
|
|
|
|
2017-06-08 18:00:10 +03:00
|
|
|
const PSM_ANIMATION_LENGTH = 400;
|
|
|
|
|
2017-03-10 17:30:01 +03:00
|
|
|
export default Component.extend(SettingsMenuMixin, {
|
2019-10-01 16:00:53 +03:00
|
|
|
feature: service(),
|
2017-10-30 12:38:01 +03:00
|
|
|
store: service(),
|
|
|
|
config: service(),
|
2019-11-05 12:10:24 +03:00
|
|
|
ajax: service(),
|
2017-10-30 12:38:01 +03:00
|
|
|
ghostPaths: service(),
|
|
|
|
notifications: service(),
|
|
|
|
slugGenerator: service(),
|
|
|
|
session: service(),
|
|
|
|
settings: service(),
|
|
|
|
ui: service(),
|
2014-09-16 02:46:40 +04:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
post: null,
|
2018-01-11 20:43:23 +03:00
|
|
|
|
|
|
|
_showSettingsMenu: false,
|
|
|
|
_showThrobbers: false,
|
2018-01-11 01:57:43 +03:00
|
|
|
|
2019-03-12 13:40:07 +03:00
|
|
|
canonicalUrlScratch: alias('post.canonicalUrlScratch'),
|
2018-01-11 01:57:43 +03:00
|
|
|
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'),
|
2014-08-10 18:40:04 +04:00
|
|
|
|
2020-07-14 14:14:02 +03:00
|
|
|
facebookDescription: or('ogDescriptionScratch', 'customExcerptScratch', 'seoDescription', 'post.excerpt', 'settings.description', ''),
|
2021-02-05 12:24:26 +03:00
|
|
|
facebookImage: or('post.ogImage', 'post.featureImage', 'settings.ogImage', 'settings.coverImage'),
|
2017-10-13 12:39:49 +03:00
|
|
|
facebookTitle: or('ogTitleScratch', 'seoTitle'),
|
2020-07-14 14:14:02 +03:00
|
|
|
twitterDescription: or('twitterDescriptionScratch', 'customExcerptScratch', 'seoDescription', 'post.excerpt', 'settings.description', ''),
|
2021-02-05 12:24:26 +03:00
|
|
|
twitterImage: or('post.twitterImage', 'post.featureImage', 'settings.twitterImage', 'settings.coverImage'),
|
2017-08-03 14:45:14 +03:00
|
|
|
twitterTitle: or('twitterTitleScratch', 'seoTitle'),
|
|
|
|
|
2019-10-09 11:23:36 +03:00
|
|
|
showVisibilityInput: or('session.user.isOwner', 'session.user.isAdmin', 'session.user.isEditor'),
|
2020-05-28 12:06:04 +03:00
|
|
|
showEmailNewsletter: or('session.user.isOwner', 'session.user.isAdmin', 'session.user.isEditor'),
|
2019-10-09 11:23:36 +03:00
|
|
|
|
2018-06-14 14:38:43 +03:00
|
|
|
seoTitle: computed('metaTitleScratch', 'post.titleScratch', function () {
|
|
|
|
return this.metaTitleScratch || this.post.titleScratch || '(Untitled)';
|
|
|
|
}),
|
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
seoDescription: computed('post.scratch', 'metaDescriptionScratch', function () {
|
2019-03-06 16:53:54 +03:00
|
|
|
let metaDescription = this.metaDescriptionScratch || '';
|
2018-01-11 01:57:43 +03:00
|
|
|
let mobiledoc = this.get('post.scratch');
|
2019-03-12 15:13:32 +03:00
|
|
|
let [markdownCard] = (mobiledoc && mobiledoc.cards) || [];
|
2018-06-14 14:38:43 +03:00
|
|
|
let markdown = markdownCard && markdownCard[1] && markdownCard[1].markdown;
|
2017-03-07 20:48:11 +03:00
|
|
|
let placeholder;
|
2014-09-23 13:37:08 +04:00
|
|
|
|
2017-08-03 14:45:14 +03:00
|
|
|
if (metaDescription) {
|
2014-09-23 13:37:08 +04:00
|
|
|
placeholder = metaDescription;
|
|
|
|
} else {
|
2017-05-30 16:07:12 +03:00
|
|
|
let div = document.createElement('div');
|
|
|
|
div.innerHTML = formatMarkdown(markdown, false);
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2014-09-23 13:37:08 +04:00
|
|
|
// Strip HTML
|
2017-05-30 16:07:12 +03:00
|
|
|
placeholder = div.textContent;
|
2014-09-23 13:37:08 +04:00
|
|
|
// Replace new lines and trim
|
|
|
|
placeholder = placeholder.replace(/\n+/g, ' ').trim();
|
|
|
|
}
|
|
|
|
|
|
|
|
return placeholder;
|
2014-09-19 03:42:07 +04:00
|
|
|
}),
|
|
|
|
|
2019-03-12 13:40:07 +03:00
|
|
|
seoURL: computed('post.{slug,canonicalUrl}', 'config.blogUrl', function () {
|
2015-10-28 14:36:45 +03:00
|
|
|
let blogUrl = this.get('config.blogUrl');
|
2019-03-12 13:40:07 +03:00
|
|
|
let seoSlug = this.post.slug || '';
|
|
|
|
let canonicalUrl = this.post.canonicalUrl || '';
|
2014-10-22 01:20:51 +04:00
|
|
|
|
2019-03-12 13:40:07 +03:00
|
|
|
if (canonicalUrl) {
|
|
|
|
if (canonicalUrl.match(/^\//)) {
|
|
|
|
return `${blogUrl}${canonicalUrl}`;
|
|
|
|
} else {
|
|
|
|
return canonicalUrl;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let seoURL = `${blogUrl}/${seoSlug}`;
|
|
|
|
|
|
|
|
// only append a slash to the URL if the slug exists
|
|
|
|
if (seoSlug) {
|
|
|
|
seoURL += '/';
|
|
|
|
}
|
2014-10-17 20:18:52 +04:00
|
|
|
|
2019-03-12 13:40:07 +03:00
|
|
|
return seoURL;
|
|
|
|
}
|
2014-09-19 03:42:07 +04:00
|
|
|
}),
|
2014-09-15 04:40:24 +04:00
|
|
|
|
2018-01-11 20:43:23 +03:00
|
|
|
didReceiveAttrs() {
|
|
|
|
this._super(...arguments);
|
|
|
|
|
|
|
|
// HACK: ugly method of working around the CSS animations so that we
|
|
|
|
// can add throbbers only when the animation has finished
|
|
|
|
// TODO: use liquid-fire to handle PSM slide-in and replace tabs manager
|
|
|
|
// with something more ember-like
|
2019-03-06 16:53:54 +03:00
|
|
|
if (this.showSettingsMenu && !this._showSettingsMenu) {
|
|
|
|
this.showThrobbers.perform();
|
2016-07-19 02:23:43 +03:00
|
|
|
}
|
2018-01-11 20:43:23 +03:00
|
|
|
|
|
|
|
// fired when menu is closed
|
2019-03-06 16:53:54 +03:00
|
|
|
if (!this.showSettingsMenu && this._showSettingsMenu) {
|
|
|
|
let post = this.post;
|
2018-01-11 20:43:23 +03:00
|
|
|
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'});
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove throbbers
|
|
|
|
this.set('_showThrobbers', false);
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this._showSettingsMenu = this.showSettingsMenu;
|
2014-07-01 16:18:47 +04:00
|
|
|
},
|
2014-10-25 01:09:50 +04:00
|
|
|
|
2014-06-08 10:02:21 +04:00
|
|
|
actions: {
|
2017-08-02 12:32:51 +03:00
|
|
|
showSubview(subview) {
|
2017-06-08 18:00:10 +03:00
|
|
|
this._super(...arguments);
|
2017-07-10 15:15:20 +03:00
|
|
|
|
2017-08-02 12:32:51 +03:00
|
|
|
this.set('subview', subview);
|
|
|
|
|
2017-07-10 15:15:20 +03:00
|
|
|
// Chrome appears to have an animation bug that cancels the slide
|
|
|
|
// transition unless there's a delay between the animation starting
|
|
|
|
// and the throbbers being removed
|
|
|
|
run.later(this, function () {
|
|
|
|
this.set('_showThrobbers', false);
|
|
|
|
}, 50);
|
2017-06-08 18:00:10 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
closeSubview() {
|
|
|
|
this._super(...arguments);
|
2017-08-02 12:32:51 +03:00
|
|
|
|
|
|
|
this.set('subview', null);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.showThrobbers.perform();
|
2017-06-08 18:00:10 +03:00
|
|
|
},
|
|
|
|
|
2015-10-28 14:36:45 +03:00
|
|
|
discardEnter() {
|
2015-09-24 20:49:36 +03:00
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2015-10-28 14:36:45 +03:00
|
|
|
toggleFeatured() {
|
2018-01-11 01:57:43 +03:00
|
|
|
this.toggleProperty('post.featured');
|
2014-10-25 01:09:50 +04:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
// If this is a new post. Don't save the post. Defer the save
|
2014-09-23 12:47:35 +04:00
|
|
|
// to the user pressing the save button
|
2018-01-11 01:57:43 +03:00
|
|
|
if (this.get('post.isNew')) {
|
2014-09-23 12:47:35 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2016-07-19 02:23:43 +03:00
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2014-07-01 16:18:47 +04:00
|
|
|
});
|
|
|
|
},
|
2014-10-25 01:09:50 +04:00
|
|
|
|
2014-06-09 00:48:14 +04:00
|
|
|
/**
|
|
|
|
* triggered by user manually changing slug
|
|
|
|
*/
|
2015-10-28 14:36:45 +03:00
|
|
|
updateSlug(newSlug) {
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.updateSlug
|
2017-06-13 18:04:09 +03:00
|
|
|
.perform(newSlug)
|
|
|
|
.catch((error) => {
|
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2017-06-13 18:04:09 +03:00
|
|
|
});
|
2014-06-08 10:02:21 +04:00
|
|
|
},
|
|
|
|
|
2017-04-11 16:39:45 +03:00
|
|
|
setPublishedAtBlogDate(date) {
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2017-04-11 16:39:45 +03:00
|
|
|
let dateString = moment(date).format('YYYY-MM-DD');
|
Scheduler UI
refs TryGhost/Ghost#6413 and TryGhost/Ghost#6870
needs TryGhost/Ghost#6861
- **Post Settings Menu (PSM)**:'Publish Date' input accepts a date from now, min. 2 minutes to allow scheduler processing on the server. Also, there will always be some delay between typing the date and clicking on the 'Schedule Post' button. If the user types a future date for an already published post, the date will be reseted and he sees the message, that the post needs to be unpublished first. Once, the date is accepted, the label will change to 'Scheduled Date'.
- adds a CP 'timeScheduled' to post model, which will return `true` if the publish time is currently in the future.
- **Changes to the button flow in editor**:
- if the the CP `timeScheduled` returns true, a different drop-down-menu will be shown: 'Schedule Post' replaces 'Publish Now' and 'Unschedule' replaces 'Unpublish'.
- Covering the _edge cases_, especially when a scheduled post is about to be published, while the user is in the editor.
- First, a new CP `scheduleCountdown` will return the remaining time, when the estimated publish time is 15 minutes from now. A notification with this live-ticker is shown next to the save button. Once, we reach a 2 minutes limit, another CP `statusFreeze` will return true and causes the save button to only show `Unschedule` in a red state, until we reach the publish time
- Once the publish time is reached, a CP `scheduledWillPublish` causes the buttons and the existing code to pretend we're already dealing with a publish post. At the moment, there's no way to make a background-fetch of the now serverside-scheduled post model from the server, so Ember doesn't know about the changed state at that time.
- Changes in the editor, which are done during this 'status freeze'-process will be saved back correctly, once the user hits 'Update Post' after the buttons changed back. A click on 'Unpublish' will change the status back to a draft.
- The user will get a regular 'toaster' notification that the post has been published.
- adds CP `isScheduled` for scheduled posts
- adds CP `offset` to component `gh-posts-list-item` and helper `gh-format-time-scheduled` to show schedule date in content overview.
- sets timeout in `gh-spin-button` to 10ms for `Ember.testing`
- changes error message in `gh-editor-base-controller` to be in one line, seperated with a `:`
TODOs:
- [x] new sort order for posts (1. scheduled, 2. draft, 3. published) (refs TryGhost/Ghost#6932)
- [ ] Move posts sorting from posts controller to model and refactor to use `Ember.comparable` mixin
- [x] Flows for draft -> scheduled -> published like described in TryGhost/Ghost#6870 incl. edge cases and button behaviour
- [x] Tests
- [x] new PSM behaviour for time/date in future
- [x] display publishedAt date with timezone offset on posts overview
2016-02-02 10:04:40 +03:00
|
|
|
|
2017-04-11 16:39:45 +03:00
|
|
|
post.get('errors').remove('publishedAtBlogDate');
|
2014-06-08 10:02:21 +04:00
|
|
|
|
2017-04-11 16:39:45 +03:00
|
|
|
if (post.get('isNew') || date === post.get('publishedAtBlogDate')) {
|
|
|
|
post.validate({property: 'publishedAtBlog'});
|
|
|
|
} else {
|
|
|
|
post.set('publishedAtBlogDate', dateString);
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2017-03-17 20:16:21 +03:00
|
|
|
}
|
2017-04-11 16:39:45 +03:00
|
|
|
},
|
2014-06-08 10:02:21 +04:00
|
|
|
|
2017-04-11 16:39:45 +03:00
|
|
|
setPublishedAtBlogTime(time) {
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2014-07-01 16:18:47 +04:00
|
|
|
|
2017-04-11 16:39:45 +03:00
|
|
|
post.get('errors').remove('publishedAtBlogDate');
|
2014-06-08 10:02:21 +04:00
|
|
|
|
2017-04-11 16:39:45 +03:00
|
|
|
if (post.get('isNew') || time === post.get('publishedAtBlogTime')) {
|
|
|
|
post.validate({property: 'publishedAtBlog'});
|
|
|
|
} else {
|
|
|
|
post.set('publishedAtBlogTime', time);
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2017-03-17 20:16:21 +03:00
|
|
|
}
|
2014-09-16 02:46:40 +04:00
|
|
|
},
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2017-08-01 11:24:46 +03:00
|
|
|
setCustomExcerpt(excerpt) {
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentExcerpt = post.get('customExcerpt');
|
2017-08-01 11:24:46 +03:00
|
|
|
|
|
|
|
if (excerpt === currentExcerpt) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('customExcerpt', excerpt);
|
2017-08-01 11:24:46 +03:00
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return post.validate({property: 'customExcerpt'}).then(() => this.savePost.perform());
|
2017-08-02 12:32:51 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
setHeaderInjection(code) {
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentCode = post.get('codeinjectionHead');
|
2017-08-02 12:32:51 +03:00
|
|
|
|
|
|
|
if (code === currentCode) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('codeinjectionHead', code);
|
2017-08-02 12:32:51 +03:00
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return post.validate({property: 'codeinjectionHead'}).then(() => this.savePost.perform());
|
2017-08-02 12:32:51 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
setFooterInjection(code) {
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentCode = post.get('codeinjectionFoot');
|
2017-08-02 12:32:51 +03:00
|
|
|
|
|
|
|
if (code === currentCode) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('codeinjectionFoot', code);
|
2017-08-02 12:32:51 +03:00
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return post.validate({property: 'codeinjectionFoot'}).then(() => this.savePost.perform());
|
2017-08-01 11:24:46 +03:00
|
|
|
},
|
|
|
|
|
2015-10-28 14:36:45 +03:00
|
|
|
setMetaTitle(metaTitle) {
|
2018-01-11 01:57:43 +03:00
|
|
|
// Grab the post and current stored meta title
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentTitle = post.get('metaTitle');
|
2014-09-23 13:37:08 +04:00
|
|
|
|
2016-08-07 06:52:46 +03:00
|
|
|
// If the title entered matches the stored meta title, do nothing
|
2014-09-23 13:37:08 +04:00
|
|
|
if (currentTitle === metaTitle) {
|
|
|
|
return;
|
|
|
|
}
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2016-08-07 06:52:46 +03:00
|
|
|
// If the title entered is different, set it as the new meta title
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('metaTitle', metaTitle);
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
// 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')) {
|
2016-08-07 06:52:46 +03:00
|
|
|
return;
|
|
|
|
}
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2016-08-07 06:52:46 +03:00
|
|
|
});
|
2014-09-19 03:42:07 +04:00
|
|
|
},
|
|
|
|
|
2015-10-28 14:36:45 +03:00
|
|
|
setMetaDescription(metaDescription) {
|
2018-01-11 01:57:43 +03:00
|
|
|
// Grab the post and current stored meta description
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentDescription = post.get('metaDescription');
|
2014-09-23 13:37:08 +04:00
|
|
|
|
2016-08-07 06:52:46 +03:00
|
|
|
// If the title entered matches the stored meta title, do nothing
|
2014-09-23 13:37:08 +04:00
|
|
|
if (currentDescription === metaDescription) {
|
|
|
|
return;
|
|
|
|
}
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2016-08-07 06:52:46 +03:00
|
|
|
// If the title entered is different, set it as the new meta title
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('metaDescription', metaDescription);
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
// 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')) {
|
2016-08-07 06:52:46 +03:00
|
|
|
return;
|
|
|
|
}
|
2014-09-19 03:42:07 +04:00
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2016-08-07 06:52:46 +03:00
|
|
|
});
|
2014-09-19 03:42:07 +04:00
|
|
|
},
|
2014-09-16 02:46:40 +04:00
|
|
|
|
2019-03-12 13:40:07 +03:00
|
|
|
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.savePost.perform();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-08-03 14:45:14 +03:00
|
|
|
setOgTitle(ogTitle) {
|
2018-01-11 01:57:43 +03:00
|
|
|
// Grab the post and current stored facebook title
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentTitle = post.get('ogTitle');
|
2017-08-03 14:45:14 +03:00
|
|
|
|
|
|
|
// 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
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('ogTitle', ogTitle);
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
// 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')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
setOgDescription(ogDescription) {
|
2018-01-11 01:57:43 +03:00
|
|
|
// Grab the post and current stored facebook description
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentDescription = post.get('ogDescription');
|
2017-08-03 14:45:14 +03:00
|
|
|
|
|
|
|
// 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
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('ogDescription', ogDescription);
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
// 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')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
setTwitterTitle(twitterTitle) {
|
2018-01-11 01:57:43 +03:00
|
|
|
// Grab the post and current stored twitter title
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentTitle = post.get('twitterTitle');
|
2017-08-03 14:45:14 +03:00
|
|
|
|
|
|
|
// 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
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('twitterTitle', twitterTitle);
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
// 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')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
setTwitterDescription(twitterDescription) {
|
2018-01-11 01:57:43 +03:00
|
|
|
// Grab the post and current stored twitter description
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2018-01-11 01:57:43 +03:00
|
|
|
let currentDescription = post.get('twitterDescription');
|
2017-08-03 14:45:14 +03:00
|
|
|
|
|
|
|
// 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
|
2018-01-11 01:57:43 +03:00
|
|
|
post.set('twitterDescription', twitterDescription);
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
// 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')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
return this.savePost.perform();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
2019-11-05 14:00:07 +03:00
|
|
|
|
2015-10-28 14:36:45 +03:00
|
|
|
setCoverImage(image) {
|
2018-01-11 01:57:43 +03:00
|
|
|
this.set('post.featureImage', image);
|
2014-09-16 02:46:40 +04:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
if (this.get('post.isNew')) {
|
2014-09-16 02:46:40 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2016-07-19 02:23:43 +03:00
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2014-09-16 02:46:40 +04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2015-10-28 14:36:45 +03:00
|
|
|
clearCoverImage() {
|
2018-01-11 01:57:43 +03:00
|
|
|
this.set('post.featureImage', '');
|
2014-09-16 02:46:40 +04:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
if (this.get('post.isNew')) {
|
2014-09-16 02:46:40 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2016-07-19 02:23:43 +03:00
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2014-06-21 01:36:44 +04:00
|
|
|
});
|
2014-09-15 04:40:24 +04:00
|
|
|
},
|
|
|
|
|
2017-08-03 14:45:14 +03:00
|
|
|
setOgImage(image) {
|
2018-01-11 01:57:43 +03:00
|
|
|
this.set('post.ogImage', image);
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
if (this.get('post.isNew')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2017-08-03 14:45:14 +03:00
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
clearOgImage() {
|
2018-01-11 01:57:43 +03:00
|
|
|
this.set('post.ogImage', '');
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
if (this.get('post.isNew')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2017-08-03 14:45:14 +03:00
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
setTwitterImage(image) {
|
2018-01-11 01:57:43 +03:00
|
|
|
this.set('post.twitterImage', image);
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
if (this.get('post.isNew')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2017-08-03 14:45:14 +03:00
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
clearTwitterImage() {
|
2018-01-11 01:57:43 +03:00
|
|
|
this.set('post.twitterImage', '');
|
2017-08-03 14:45:14 +03:00
|
|
|
|
2018-01-11 01:57:43 +03:00
|
|
|
if (this.get('post.isNew')) {
|
2017-08-03 14:45:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2017-08-03 14:45:14 +03:00
|
|
|
this.showError(error);
|
2019-03-06 16:53:54 +03:00
|
|
|
this.post.rollbackAttributes();
|
2017-08-03 14:45:14 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2018-03-13 14:17:29 +03:00
|
|
|
changeAuthors(newAuthors) {
|
2019-03-06 16:53:54 +03:00
|
|
|
let post = this.post;
|
2015-06-13 17:34:09 +03:00
|
|
|
|
|
|
|
// return if nothing changed
|
2018-03-13 14:17:29 +03:00
|
|
|
if (newAuthors.mapBy('id').join() === post.get('authors').mapBy('id').join()) {
|
2015-06-13 17:34:09 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-13 14:17:29 +03:00
|
|
|
post.set('authors', newAuthors);
|
|
|
|
post.validate({property: 'authors'});
|
2015-06-13 17:34:09 +03:00
|
|
|
|
|
|
|
// if this is a new post (never been saved before), don't try to save it
|
2018-03-13 14:17:29 +03:00
|
|
|
if (post.get('isNew')) {
|
2015-06-13 17:34:09 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:53:54 +03:00
|
|
|
this.savePost.perform().catch((error) => {
|
2016-07-19 02:23:43 +03:00
|
|
|
this.showError(error);
|
2018-01-11 01:57:43 +03:00
|
|
|
post.rollbackAttributes();
|
2015-06-13 17:34:09 +03:00
|
|
|
});
|
2015-08-19 12:16:32 +03:00
|
|
|
},
|
|
|
|
|
2017-04-19 12:46:42 +03:00
|
|
|
deletePost() {
|
2019-03-06 16:53:54 +03:00
|
|
|
if (this.deletePost) {
|
|
|
|
this.deletePost();
|
2017-04-19 12:46:42 +03:00
|
|
|
}
|
2014-06-08 10:02:21 +04:00
|
|
|
}
|
2018-01-11 20:43:23 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
showThrobbers: task(function* () {
|
|
|
|
yield timeout(PSM_ANIMATION_LENGTH);
|
|
|
|
this.set('_showThrobbers', true);
|
|
|
|
}).restartable(),
|
|
|
|
|
|
|
|
showError(error) {
|
|
|
|
// TODO: remove null check once ValidationEngine has been removed
|
|
|
|
if (error) {
|
2019-03-06 16:53:54 +03:00
|
|
|
this.notifications.showAPIError(error);
|
2018-01-11 20:43:23 +03:00
|
|
|
}
|
2014-06-08 10:02:21 +04:00
|
|
|
}
|
|
|
|
});
|