Publish button amendments

Fixes #667

- Removed superfluous as-of-yet-unused options in the publish menu.
- Adjusted display names of publish buttons according to differing
states the publish menu can be in (new post, saved draft, published
post).
- Added red highlight style to "important" status change options in the
publish menu (draft => published, published => unpublished).
- Added suite of functional tests around new labels and classes.
This commit is contained in:
William Dibbern 2013-09-15 13:14:36 -05:00
parent c49df1af3c
commit ff086142d8
3 changed files with 74 additions and 56 deletions

View File

@ -420,9 +420,11 @@ body.zen {
box-shadow: rgba(255,255,255,0.4) 0 1px 0 inset; box-shadow: rgba(255,255,255,0.4) 0 1px 0 inset;
} }
.splitbutton-save{ .splitbutton-save,
.button-save{ .splitbutton-delete{
@include transition(width 0.25s ease); .button-save,
.button-delete{
@include transition(width 0.25s ease, background-color 0.3s linear);
} }
.editor-options{ .editor-options{

View File

@ -315,6 +315,7 @@ input[type="reset"] {
@include transition-duration(0.3); @include transition-duration(0.3);
@include transition-timing-function(ease); @include transition-timing-function(ease);
}; };
@include transition(background-color 0.3s linear);
// Keep the arrow spun when the associated menu is open // Keep the arrow spun when the associated menu is open
&.active:before { &.active:before {

View File

@ -54,23 +54,24 @@
events: { events: {
'click [data-set-status]': 'handleStatus', 'click [data-set-status]': 'handleStatus',
'click .js-post-button': 'handlePostButton' 'click .js-publish-button': 'handlePostButton'
}, },
statusMap: { statusMap: null,
createStatusMap: {
'draft': 'Save Draft', 'draft': 'Save Draft',
'published': 'Publish Now', 'published': 'Publish Now'
'scheduled': 'Save Schedued Post', },
'queue': 'Add to Queue',
'publish-on': 'Publish on...' updateStatusMap: {
'draft': 'Unpublish',
'published': 'Update Post'
}, },
notificationMap: { notificationMap: {
'draft': 'has been saved as a draft', 'draft': 'saved as a draft',
'published': 'has been published', 'published': 'published'
'scheduled': 'has been scheduled',
'queue': 'has been added to the queue',
'publish-on': 'will be published'
}, },
initialize: function () { initialize: function () {
@ -94,66 +95,72 @@
toggleStatus: function () { toggleStatus: function () {
var self = this, var self = this,
keys = Object.keys(this.statusMap), keys = Object.keys(this.statusMap),
model = this.model, model = self.model,
prevStatus = this.model.get('status'), prevStatus = model.get('status'),
currentIndex = keys.indexOf(prevStatus), currentIndex = keys.indexOf(prevStatus),
newIndex; newIndex;
newIndex = currentIndex + 1 > keys.length - 1 ? 0 : currentIndex + 1;
if (keys[currentIndex + 1] === 'scheduled') { // TODO: Remove once scheduled posts work this.setActiveStatus(keys[newIndex], this.statusMap[keys[newIndex]], prevStatus);
newIndex = currentIndex + 2 > keys.length - 1 ? 0 : currentIndex + 1;
} else {
newIndex = currentIndex + 1 > keys.length - 1 ? 0 : currentIndex + 1;
}
this.savePost({ this.savePost({
status: keys[newIndex] status: keys[newIndex]
}).then(function () { }).then(function () {
Ghost.notifications.addItem({ Ghost.notifications.addItem({
type: 'success', type: 'success',
message: 'Your post ' + this.notificationMap[newIndex] + '.', message: 'Your post has been ' + self.notificationMap[newIndex] + '.',
status: 'passive' status: 'passive'
}); });
}, function (xhr) { }, function (xhr) {
var status = keys[newIndex]; var status = keys[newIndex];
// Show a notification about the error // Show a notification about the error
self.reportSaveError(xhr, model, status); self.reportSaveError(xhr, model, status);
// Set the button text back to previous
model.set({ status: prevStatus });
}); });
}, },
setActiveStatus: function (status, displayText) { setActiveStatus: function (newStatus, displayText, currentStatus) {
// Set the publish button's action var isPublishing = (newStatus === 'published' && currentStatus !== 'published'),
$('.js-post-button') isUnpublishing = (newStatus === 'draft' && currentStatus === 'published'),
.attr('data-status', status) // Controls when background of button has the splitbutton-delete/button-delete classes applied
.text(displayText); 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 // Remove the animated popup arrow
$('.splitbutton-save > a') $('.js-publish-splitbutton > a')
.removeClass('active'); .removeClass('active');
// Set the active action in the popup // Set the active action in the popup
$('.splitbutton-save .editor-options li') $('.js-publish-splitbutton .editor-options li')
.removeClass('active') .removeClass('active')
.filter(['li[data-set-status="', status, '"]'].join('')) .filter(['li[data-set-status="', newStatus, '"]'].join(''))
.addClass('active'); .addClass('active');
}, },
handleStatus: function (e) { handleStatus: function (e) {
if (e) { e.preventDefault(); } if (e) { e.preventDefault(); }
var status = $(e.currentTarget).attr('data-set-status'); var status = $(e.currentTarget).attr('data-set-status'),
currentStatus = this.model.get('status');
this.setActiveStatus(status, this.statusMap[status]); this.setActiveStatus(status, this.statusMap[status], currentStatus);
// Dismiss the popup menu // Dismiss the popup menu
$('body').find('.overlay:visible').fadeOut(); $('body').find('.overlay:visible').fadeOut();
}, },
handlePostButton: function (e) { handlePostButton: function (e) {
e.preventDefault(); if (e) { e.preventDefault(); }
var status = $(e.currentTarget).attr('data-status');
var status = $(e.currentTarget).attr("data-status");
this.updatePost(status); this.updatePost(status);
}, },
@ -167,32 +174,23 @@
// Default to same status if not passed in // Default to same status if not passed in
status = status || prevStatus; status = status || prevStatus;
if (status === 'publish-on') { model.trigger('willSave');
return Ghost.notifications.addItem({
type: 'alert',
message: 'Scheduled publishing not supported yet.',
status: 'passive'
});
}
if (status === 'queue') {
return Ghost.notifications.addItem({
type: 'alert',
message: 'Scheduled publishing not supported yet.',
status: 'passive'
});
}
this.model.trigger('willSave');
this.savePost({ this.savePost({
status: status status: status
}).then(function () { }).then(function () {
Ghost.notifications.addItem({ Ghost.notifications.addItem({
type: 'success', type: 'success',
message: ['Your post ', notificationMap[status], '.'].join(''), message: ['Your post has been ', notificationMap[status], '.'].join(''),
status: 'passive' status: 'passive'
}); });
// Refresh publish button and all relevant controls with updated status.
self.render();
}, function (xhr) { }, 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 // Show a notification about the error
self.reportSaveError(xhr, model, status); self.reportSaveError(xhr, model, status);
}); });
@ -219,7 +217,8 @@
reportSaveError: function (response, model, status) { reportSaveError: function (response, model, status) {
var title = model.get('title') || '[Untitled]', var title = model.get('title') || '[Untitled]',
message = 'Your post: ' + title + ' has not been ' + status; notificationStatus = this.notificationMap[status],
message = 'Your post: ' + title + ' has not been ' + notificationStatus;
if (response) { if (response) {
// Get message from response // Get message from response
@ -236,11 +235,27 @@
}); });
}, },
setStatusLabels: function (statusMap) {
_.each(statusMap, function (label, status) {
$('li[data-set-status="' + status + '"] > a').text(label);
});
},
render: function () { render: function () {
var status = this.model.get('status'); 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. // Default the selected publish option to the current status of the post.
this.setActiveStatus(status, this.statusMap[status]); this.setActiveStatus(status, this.statusMap[status], status);
} }
}); });