mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-04 04:10:33 +03:00
c746a88b2e
Conflicts: Gruntfile.js core/client/assets/lib/showdown/extensions/ghostdown.js core/client/views/editor.js core/clientold/assets/lib/showdown/extensions/ghostdown.js core/shared/lib/showdown/extensions/ghostimagepreview.js core/test/unit/showdown_client_integrated_spec.js core/test/unit/showdown_ghostimagepreview_spec.js
255 lines
8.9 KiB
JavaScript
255 lines
8.9 KiB
JavaScript
// The Save / Publish button
|
|
|
|
/*global $, _, Ghost, shortcut */
|
|
|
|
(function () {
|
|
'use strict';
|
|
|
|
// The Publish, Queue, Publish Now buttons
|
|
// ----------------------------------------
|
|
Ghost.View.EditorActionsWidget = Ghost.View.extend({
|
|
|
|
events: {
|
|
'click [data-set-status]': 'handleStatus',
|
|
'click .js-publish-button': 'handlePostButton'
|
|
},
|
|
|
|
statusMap: null,
|
|
|
|
createStatusMap: {
|
|
'draft': 'Save Draft',
|
|
'published': 'Publish Now'
|
|
},
|
|
|
|
updateStatusMap: {
|
|
'draft': 'Unpublish',
|
|
'published': 'Update Post'
|
|
},
|
|
|
|
//TODO: This has to be moved to the I18n localization file.
|
|
//This structure is supposed to be close to the i18n-localization which will be used soon.
|
|
messageMap: {
|
|
errors: {
|
|
post: {
|
|
published: {
|
|
'published': 'Your post could not be updated.',
|
|
'draft': 'Your post could not be saved as a draft.'
|
|
},
|
|
draft: {
|
|
'published': 'Your post could not be published.',
|
|
'draft': 'Your post could not be saved as a draft.'
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
success: {
|
|
post: {
|
|
published: {
|
|
'published': 'Your post has been updated.',
|
|
'draft': 'Your post has been saved as a draft.'
|
|
},
|
|
draft: {
|
|
'published': 'Your post has been published.',
|
|
'draft': 'Your post has been saved as a draft.'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
initialize: function () {
|
|
var self = this;
|
|
|
|
// Toggle publish
|
|
shortcut.add('Ctrl+Alt+P', function () {
|
|
self.toggleStatus();
|
|
});
|
|
shortcut.add('Ctrl+S', function () {
|
|
self.updatePost();
|
|
});
|
|
shortcut.add('Meta+S', function () {
|
|
self.updatePost();
|
|
});
|
|
this.listenTo(this.model, 'change:status', this.render);
|
|
},
|
|
|
|
toggleStatus: function () {
|
|
var self = this,
|
|
keys = Object.keys(this.statusMap),
|
|
model = self.model,
|
|
prevStatus = model.get('status'),
|
|
currentIndex = keys.indexOf(prevStatus),
|
|
newIndex,
|
|
status;
|
|
|
|
newIndex = currentIndex + 1 > keys.length - 1 ? 0 : currentIndex + 1;
|
|
status = keys[newIndex];
|
|
|
|
this.setActiveStatus(keys[newIndex], this.statusMap[status], prevStatus);
|
|
|
|
this.savePost({
|
|
status: keys[newIndex]
|
|
}).then(function () {
|
|
self.reportSaveSuccess(status, prevStatus);
|
|
}, function (xhr) {
|
|
// Show a notification about the error
|
|
self.reportSaveError(xhr, model, status, prevStatus);
|
|
});
|
|
},
|
|
|
|
setActiveStatus: function (newStatus, displayText, currentStatus) {
|
|
var isPublishing = (newStatus === 'published' && currentStatus !== 'published'),
|
|
isUnpublishing = (newStatus === 'draft' && currentStatus === 'published'),
|
|
// Controls when background of button has the splitbutton-delete/button-delete classes applied
|
|
isImportantStatus = (isPublishing || isUnpublishing);
|
|
|
|
$('.js-publish-splitbutton')
|
|
.removeClass(isImportantStatus ? 'splitbutton-save' : 'splitbutton-delete')
|
|
.addClass(isImportantStatus ? 'splitbutton-delete' : 'splitbutton-save');
|
|
|
|
// Set the publish button's action and proper coloring
|
|
$('.js-publish-button')
|
|
.attr('data-status', newStatus)
|
|
.text(displayText)
|
|
.removeClass(isImportantStatus ? 'button-save' : 'button-delete')
|
|
.addClass(isImportantStatus ? 'button-delete' : 'button-save');
|
|
|
|
// Remove the animated popup arrow
|
|
$('.js-publish-splitbutton > a')
|
|
.removeClass('active');
|
|
|
|
// Set the active action in the popup
|
|
$('.js-publish-splitbutton .editor-options li')
|
|
.removeClass('active')
|
|
.filter(['li[data-set-status="', newStatus, '"]'].join(''))
|
|
.addClass('active');
|
|
},
|
|
|
|
handleStatus: function (e) {
|
|
if (e) { e.preventDefault(); }
|
|
var status = $(e.currentTarget).attr('data-set-status'),
|
|
currentStatus = this.model.get('status');
|
|
|
|
this.setActiveStatus(status, this.statusMap[status], currentStatus);
|
|
|
|
// Dismiss the popup menu
|
|
$('body').find('.overlay:visible').fadeOut();
|
|
},
|
|
|
|
handlePostButton: function (e) {
|
|
if (e) { e.preventDefault(); }
|
|
var status = $(e.currentTarget).attr('data-status');
|
|
|
|
this.updatePost(status);
|
|
},
|
|
|
|
updatePost: function (status) {
|
|
var self = this,
|
|
model = this.model,
|
|
prevStatus = model.get('status');
|
|
|
|
// Default to same status if not passed in
|
|
status = status || prevStatus;
|
|
|
|
model.trigger('willSave');
|
|
|
|
this.savePost({
|
|
status: status
|
|
}).then(function () {
|
|
self.reportSaveSuccess(status, prevStatus);
|
|
// Refresh publish button and all relevant controls with updated status.
|
|
self.render();
|
|
}, function (xhr) {
|
|
// Set the model status back to previous
|
|
model.set({ status: prevStatus });
|
|
// Set appropriate button status
|
|
self.setActiveStatus(status, self.statusMap[status], prevStatus);
|
|
// Show a notification about the error
|
|
self.reportSaveError(xhr, model, status, prevStatus);
|
|
});
|
|
},
|
|
|
|
savePost: function (data) {
|
|
var publishButton = $('.js-publish-button'),
|
|
saved,
|
|
enablePublish = function (deferred) {
|
|
deferred.always(function () {
|
|
publishButton.prop('disabled', false);
|
|
});
|
|
return deferred;
|
|
};
|
|
|
|
publishButton.prop('disabled', true);
|
|
|
|
_.each(this.model.blacklist, function (item) {
|
|
this.model.unset(item);
|
|
}, this);
|
|
|
|
saved = this.model.save(_.extend({
|
|
title: this.options.$title.val(),
|
|
markdown: this.options.editor.value()
|
|
}, data));
|
|
|
|
// TODO: Take this out if #2489 gets merged in Backbone. Or patch Backbone
|
|
// ourselves for more consistent promises.
|
|
if (saved) {
|
|
return enablePublish(saved);
|
|
}
|
|
|
|
return enablePublish($.Deferred().reject());
|
|
},
|
|
|
|
reportSaveSuccess: function (status, prevStatus) {
|
|
Ghost.notifications.clearEverything();
|
|
Ghost.notifications.addItem({
|
|
type: 'success',
|
|
message: this.messageMap.success.post[prevStatus][status],
|
|
status: 'passive'
|
|
});
|
|
this.options.editor.setDirty(false);
|
|
},
|
|
|
|
reportSaveError: function (response, model, status, prevStatus) {
|
|
var message = this.messageMap.errors.post[prevStatus][status];
|
|
|
|
if (response) {
|
|
// Get message from response
|
|
message += ' ' + Ghost.Views.Utils.getRequestErrorMessage(response);
|
|
} else if (model.validationError) {
|
|
// Grab a validation error
|
|
message += ' ' + model.validationError;
|
|
}
|
|
|
|
Ghost.notifications.clearEverything();
|
|
Ghost.notifications.addItem({
|
|
type: 'error',
|
|
message: message,
|
|
status: 'passive'
|
|
});
|
|
},
|
|
|
|
setStatusLabels: function (statusMap) {
|
|
_.each(statusMap, function (label, status) {
|
|
$('li[data-set-status="' + status + '"] > a').text(label);
|
|
});
|
|
},
|
|
|
|
render: function () {
|
|
var status = this.model.get('status');
|
|
|
|
// Assume that we're creating a new post
|
|
if (status !== 'published') {
|
|
this.statusMap = this.createStatusMap;
|
|
} else {
|
|
this.statusMap = this.updateStatusMap;
|
|
}
|
|
|
|
// Populate the publish menu with the appropriate verbiage
|
|
this.setStatusLabels(this.statusMap);
|
|
|
|
// Default the selected publish option to the current status of the post.
|
|
this.setActiveStatus(status, this.statusMap[status], status);
|
|
}
|
|
|
|
});
|
|
}()); |