mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 05:50:35 +03:00
35cf6c9829
closes https://github.com/TryGhost/Ghost/issues/8249 - replaces the old split-button publish/schedule/update button with a less confusing menu system - adds a `{{gh-date-time-picker}}` component that contains a datepicker with separate time input - replaces the date text input in the post settings menu with `{{gh-date-time-picker}}` - disabled when post is scheduled, only way to update a scheduled time is via the publish menu - validates date is in the past when draft/published so there's no confusion with scheduling - displays saving status in top-left of editor screen - refactor editor (auto)saving processes to use ember-concurrency Other minor changes: - adds `post.publishedAtBlog{TZ,Date,Time}` properties to Post model to allow working with `publishedAt` datetime in the selected blog timezone rather than UTC - adds a `beforeSave` hook to `validation-engine` that is called after successful validation and before the Ember Data save call is made - adds validation of `publishedAtBlog{Date,Time}` to post validator - prevent gh-task-button showing last task state on first render - fixes bug where clicking into and out of the published date input in the PSM without making any changes saves a published date for draft posts
111 lines
3.5 KiB
JavaScript
111 lines
3.5 KiB
JavaScript
import Component from 'ember-component';
|
|
import observer from 'ember-metal/observer';
|
|
import computed, {reads} from 'ember-computed';
|
|
import {isBlank} from 'ember-utils';
|
|
import {invokeAction} from 'ember-invoke-action';
|
|
|
|
/**
|
|
* Task Button works exactly like Spin button, but with one major difference:
|
|
*
|
|
* Instead of passing a "submitting" parameter (which is bound to the parent object),
|
|
* you pass an ember-concurrency task. All of the "submitting" behavior is handled automatically.
|
|
*
|
|
* As another bonus, there's no need to handle canceling the promises when something
|
|
* like a controller changes. Because the only task running is handled through this
|
|
* component, all running promises will automatically be cancelled when this
|
|
* component is removed from the DOM
|
|
*/
|
|
const GhTaskButton = Component.extend({
|
|
tagName: 'button',
|
|
classNameBindings: ['isRunning:appear-disabled', 'isSuccessClass', 'isFailureClass'],
|
|
attributeBindings: ['disabled', 'type', 'tabindex'],
|
|
|
|
task: null,
|
|
disabled: false,
|
|
buttonText: 'Save',
|
|
runningText: reads('buttonText'),
|
|
successText: 'Saved',
|
|
successClass: 'gh-btn-green',
|
|
failureText: 'Retry',
|
|
failureClass: 'gh-btn-red',
|
|
|
|
// hasRun is needed so that a newly rendered button does not show the last
|
|
// state of the associated task
|
|
hasRun: false,
|
|
isRunning: reads('task.last.isRunning'),
|
|
|
|
isSuccess: computed('hasRun', 'isRunning', 'task.last.value', function () {
|
|
if (!this.get('hasRun') || this.get('isRunning')) {
|
|
return false;
|
|
}
|
|
|
|
let value = this.get('task.last.value');
|
|
return !isBlank(value) && value !== false;
|
|
}),
|
|
|
|
isSuccessClass: computed('isSuccess', function () {
|
|
if (this.get('isSuccess')) {
|
|
return this.get('successClass');
|
|
}
|
|
}),
|
|
|
|
isFailure: computed('hasRun', 'isRunning', 'isSuccess', 'task.last.error', function () {
|
|
if (!this.get('hasRun') || this.get('isRunning') || this.get('isSuccess')) {
|
|
return false;
|
|
}
|
|
|
|
return this.get('task.last.error') !== undefined;
|
|
}),
|
|
|
|
isFailureClass: computed('isFailure', function () {
|
|
if (this.get('isFailure')) {
|
|
return this.get('failureClass');
|
|
}
|
|
}),
|
|
|
|
isIdle: computed('isRunning', 'isSuccess', 'isFailure', function () {
|
|
return !this.get('isRunning') && !this.get('isSuccess') && !this.get('isFailure');
|
|
}),
|
|
|
|
click() {
|
|
// do nothing if disabled externally
|
|
if (this.get('disabled')) {
|
|
return false;
|
|
}
|
|
|
|
let task = this.get('task');
|
|
let taskName = this.get('task.name');
|
|
let lastTaskName = this.get('task.last.task.name');
|
|
|
|
// task-buttons are never disabled whilst running so that clicks when a
|
|
// taskGroup is running don't get dropped BUT that means we need to check
|
|
// here to avoid spamming actions from multiple clicks
|
|
if (this.get('isRunning') && taskName === lastTaskName) {
|
|
return;
|
|
}
|
|
|
|
invokeAction(this, 'action');
|
|
task.perform();
|
|
|
|
// prevent the click from bubbling and triggering form actions
|
|
return false;
|
|
},
|
|
|
|
setSize: observer('isRunning', function () {
|
|
if (this.get('isRunning')) {
|
|
this.set('hasRun', true);
|
|
this.$().width(this.$().width());
|
|
this.$().height(this.$().height());
|
|
} else {
|
|
this.$().width('');
|
|
this.$().height('');
|
|
}
|
|
})
|
|
});
|
|
|
|
GhTaskButton.reopenClass({
|
|
positionalParams: ['buttonText']
|
|
});
|
|
|
|
export default GhTaskButton;
|