0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Merge pull request #722 from ericterpstra/370-post-settings-permalink

Added post-settings menu with edit permalink field
This commit is contained in:
Hannah Wolfe 2013-09-13 14:31:49 -07:00
commit 486b2406b1
11 changed files with 235 additions and 58 deletions

View file

@ -521,7 +521,15 @@ body.zen {
}
#entry-settings {
#entry-controls {
@include box-sizing(border-box);
display: inline-block;
position: relative;
padding: 0;
z-index: 1;
}
.entry-settings {
@include icon($i-settings, 1.1em){vertical-align: 0;};
@include box-sizing(border-box);
display: inline-block;
@ -535,9 +543,9 @@ body.zen {
}
}
#entry-settings-menu {
.entry-settings-menu {
position: absolute;
bottom: 50px;
bottom: 40px;
right: -5px;
}

View file

@ -232,7 +232,7 @@
ul {
position: absolute;
top:15px;
right:-15px;
right:-10px;
}
}
@ -241,11 +241,6 @@
margin-right:7px;
padding: 5px;
}
.post-settings {
@include icon($i-settings, 14px);
padding: 5px;
margin-right: -5px;
}
img {
width:100%;

View file

@ -831,6 +831,59 @@ nav {
@extend %menu-right;
}
/* ==========================================================================
Post Settings
========================================================================== */
.post-setting {
min-width: 260px;
border-bottom: 1px solid #35393b;
&:first-child {
margin-top: -6px;
}
input {
width: 100%;
background: none;
border: none;
color: #e2edf2;
line-height: 1.68em;
}
}
.post-setting-label {
float: left;
width: 26%;
text-align: right;
padding: 10px 2%;
border-right: 1px solid #35393b;
}
.post-setting-field {
float: left;
width: 64%;
padding: 8px 2%;
input:focus {
outline: none;
}
}
.post-settings {
@include icon($i-settings, 14px);
padding: 5px;
/* margin-right: -5px;*/
}
.post-setting-calendar {
@include icon-after($i-calendar, 18px);
width: 18px;
height: 18px;
position: absolute;
margin-top: -25px; /* This doesn't work in FF */
right: 10px;
}
/* ==========================================================================
Notifications

View file

@ -10,6 +10,22 @@
<a class="post-edit" href="#"><span class="hidden">Edit Post</span></a>
<a class="post-settings" href="#" data-toggle=".menu-drop-right"><span class="hidden">Post Settings</span></a>
<ul class="menu-drop-right overlay">
<li class="post-setting">
<div class="post-setting-label">
<label for="url">URL</label>
</div>
<div class="post-setting-field">
<input class="post-setting-slug" type="text" value="{{{slug}}}">
</div>
</li>
<!--<li class="post-setting">
<div class="post-setting-label">
<label for="url">Pub Date</label>
</div>
<div class="post-setting-field">
<input class="post-setting-date" type="text" value=""><span class="post-setting-calendar"></span>
</div>
</li>-->
<li><a href="#" class="delete">Delete</a></li>
</ul>
</section>

View file

@ -114,7 +114,6 @@
activeId: null,
events: {
'click .post-controls .delete' : 'deletePost',
'click .post-controls .post-edit' : 'editPost'
},
@ -129,53 +128,6 @@
}
},
deletePost: function (e) {
e.preventDefault();
var self = this;
this.addSubview(new Ghost.Views.Modal({
model: {
options: {
close: false,
confirm: {
accept: {
func: function () {
self.model.destroy({
wait: true
}).then(function () {
Ghost.notifications.addItem({
type: 'success',
message: 'Your post has been deleted.',
status: 'passive'
});
}, function () {
Ghost.notifications.addItem({
type: 'error',
message: 'Your post could not be deleted. Please try again.',
status: 'passive'
});
});
},
text: "Yes"
},
reject: {
func: function () {
return true;
},
text: "No"
}
},
type: "action",
style: ["wide", "centered"],
animation: 'fade'
},
content: {
template: 'blank',
title: 'Are you sure you want to delete this post?'
}
}
}));
},
editPost: function (e) {
e.preventDefault();
// for now this will disable "open in new tab", but when we have a Router implemented
@ -194,6 +146,11 @@
this.$('.wrapper').on('click', 'a', function (e) {
$(e.currentTarget).attr('target', '_blank');
});
if (this.model !== 'undefined') {
this.addSubview(new Ghost.View.PostSettings({el: $('.post-controls'), model: this.model})).render();
}
Ghost.temporary.initToggles(this.$el);
return this;
}

View file

@ -41,6 +41,7 @@
initialize: function () {
this.addSubview(new Ghost.View.EditorTagWidget({el: this.$('#entry-tags'), model: this.model})).render();
this.addSubview(new ActionsWidget({el: this.$('#entry-actions'), model: this.model})).render();
this.addSubview(new Ghost.View.PostSettings({el: $('#entry-controls'), model: this.model})).render();
},
render: function () { return this; }

View file

@ -0,0 +1,113 @@
// The Post Settings Menu available in the content preview screen, as well as the post editor.
/*global window, document, $, _, Backbone, Ghost */
(function () {
"use strict";
Ghost.View.PostSettings = Ghost.View.extend({
events: {
'blur .post-setting-slug' : 'editSlug',
'click .post-setting-slug' : 'selectSlug',
'click .delete' : 'deletePost'
},
render: function () {
var slug = this.model ? this.model.get('slug') : '';
//var pubDate = this.model.get('published_at');
//pubDate = moment(pubDate).format('DD MMM YY');
$('.post-setting-slug').val(slug);
//$('.post-setting-date').val(pubDate);
},
selectSlug: function (e) {
e.currentTarget.select();
},
editSlug: function (e) {
e.preventDefault();
var self = this,
slug = self.model.get('slug'),
slugEl = e.currentTarget,
newSlug = slugEl.value;
// Ignore empty or unchanged slugs
if (newSlug.length === 0 || slug === newSlug) {
slugEl.value = slug === undefined ? '' : slug;
return;
}
this.model.save({
slug: newSlug
}, {
success : function (model, response, options) {
// Repopulate slug in case it changed on the server (e.g. 'new-slug-2')
slugEl.value = model.get('slug');
},
error : function (model, xhr) {
Ghost.notifications.addItem({
type: 'error',
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
status: 'passive'
});
}
});
},
deletePost: function (e) {
e.preventDefault();
var self = this;
this.addSubview(new Ghost.Views.Modal({
model: {
options: {
close: false,
confirm: {
accept: {
func: function () {
self.model.destroy({
wait: true
}).then(function () {
// Redirect to content screen if deleting post from editor.
if (window.location.pathname.indexOf('editor') > -1) {
window.location = '/ghost/content/';
}
Ghost.notifications.addItem({
type: 'success',
message: 'Your post has been deleted.',
status: 'passive'
});
}, function () {
Ghost.notifications.addItem({
type: 'error',
message: 'Your post could not be deleted. Please try again.',
status: 'passive'
});
});
},
text: "Yes"
},
reject: {
func: function () {
return true;
},
text: "No"
}
},
type: "action",
style: ["wide", "centered"],
animation: 'fade'
},
content: {
template: 'blank',
title: 'Are you sure you want to delete this post?'
}
}
}));
}
});
}());

View file

@ -47,6 +47,7 @@ Post = GhostBookshelf.Model.extend({
saving: function () {
// Deal with the related data here
var self = this;
// Remove any properties which don't belong on the post model
this.attributes = this.pick(this.permittedAttributes);
@ -55,6 +56,14 @@ Post = GhostBookshelf.Model.extend({
this.set('title', this.get('title').trim());
if (this.hasChanged('slug')) {
// Pass the new slug through the generator to strip illegal characters, detect duplicates
return this.generateSlug(this.get('slug'))
.then(function (slug) {
self.set({slug: slug});
});
}
if (this.hasChanged('status') && this.get('status') === 'published') {
this.set('published_at', new Date());
// This will need to go elsewhere in the API layer.

View file

@ -84,6 +84,7 @@
<!-- // require '/public/views/*' -->
<script src="/public/views/base.js"></script>
<script src="/public/models/uploadModal.js"></script>
<script src="/public/views/post-settings.js"></script>
<script src="/public/views/blog.js"></script>
<script src="/public/views/editor.js"></script>
<script src="/public/views/editor-tag-widget.js"></script>

View file

@ -40,6 +40,30 @@
<ul class="suggestions overlay"></ul>
</section>
<div class="right">
<section id="entry-controls">
<a class="entry-settings" href="#" data-toggle=".menu-right"><span class="hidden">Post Settings</span></a>
<ul class="entry-settings-menu menu-right overlay">
<li class="post-setting">
<div class="post-setting-label">
<label for="url">URL</label>
</div>
<div class="post-setting-field">
<input class="post-setting-slug" type="text" value="" />
</div>
</li>
<!--<li class="post-setting">
<div class="post-setting-label">
<label for="url">Pub Date</label>
</div>
<div class="post-setting-field">
<input class="post-setting-date" type="text" value=""><span class="post-setting-calendar"></span>
</div>
</li>-->
<li><a href="#" class="delete">Delete</a></li>
</ul>
</section>
<section id="entry-actions" class="splitbutton-save">
<button type="button" class="button-save js-post-button"></button>
<a class="options up" data-toggle="ul" href="#"><span class="hidden">Options</span></a>

View file

@ -100,7 +100,7 @@ describe('Admin Controller', function() {
});
it('should send correct path to image when today is in Jan 2014', function(done) {
clock = sinon.useFakeTimers(1388534400000); // Wed Jan 01 2014 00:00:00 GMT+0000 (GMT)
clock = sinon.useFakeTimers(1388707200000); // Wed Jan 03 2014 00:00:00 GMT+0000 (GMT)
sinon.stub(res, 'send', function(data) {
data.should.equal('/content/images/2014/Jan/IMAGE.jpg');
return done();