New Post UX behaviour.

refs #1351
- Make generateSlug a static method on base model
- Change client behaviour (unfinished)
- Add new getSlug API method
This commit is contained in:
Fabian Becker 2013-12-20 14:36:00 +01:00 committed by Harry Wolff
parent 80eac65e9b
commit 11c8d234f7
7 changed files with 96 additions and 79 deletions

View File

@ -396,6 +396,9 @@
if (rawTitle !== trimmedTitle) {
$title.val(trimmedTitle);
}
// Trigger title change for post-settings.js
this.model.set('title', trimmedTitle);
},
renderTitle: function () {

View File

@ -21,6 +21,7 @@
this.listenTo(this.model, 'change:status', this.render);
this.listenTo(this.model, 'change:published_at', this.render);
this.listenTo(this.model, 'change:page', this.render);
this.listenTo(this.model, 'change:title', this.updateSlugPlaceholder);
}
},
@ -49,6 +50,19 @@
$pubDateEl.val(pubDate);
},
// Requests a new slug when the title was changed
updateSlugPlaceholder: function () {
var title = this.model.get('title');
$.ajax({
url: Ghost.paths.apiRoot + '/posts/getSlug/' + encodeURIComponent(title),
success: function (result){
// ToDo: Find better selector
$('.post-setting-slug')[0].placeholder = result;
}
});
},
selectSlug: function (e) {
e.currentTarget.select();
},
@ -60,8 +74,8 @@
slugEl = e.currentTarget,
newSlug = slugEl.value;
// Ignore empty or unchanged slugs
if (newSlug.length === 0 || slug === newSlug) {
// Ignore unchanged slugs
if (slug === newSlug) {
slugEl.value = slug === undefined ? '' : slug;
return;
}
@ -102,11 +116,6 @@
pubDateMoment,
newPubDateMoment;
// Ignore empty or unchanged dates
if (!newPubDate) {
return;
}
// Check for missing time stamp on new data
// If no time specified, add a 12:00
if (newPubDate && !newPubDate.slice(-5).match(/\d+:\d\d/)) {

View File

@ -47,6 +47,15 @@ posts = {
});
},
getSlug: function getSlug(args) {
return dataProvider.Base.Model.generateSlug(dataProvider.Post, args.title, {status: 'all'}).then(function (slug) {
if (slug) {
return slug;
}
return when.reject({errorCode: 500, message: 'Could not generate slug'});
})
},
// #### Edit
// **takes:** a json object with all the properties which should be updated

View File

@ -93,67 +93,6 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
sanitize: function (attr) {
return sanitize(this.get(attr)).xss();
},
// #### generateSlug
// Create a string act as the permalink for an object.
generateSlug: function (Model, base, readOptions) {
var slug,
slugTryCount = 1,
// Look for a post with a matching slug, append an incrementing number if so
checkIfSlugExists = function (slugToFind) {
var args = {slug: slugToFind};
//status is needed for posts
if (readOptions && readOptions.status) {
args.status = readOptions.status;
}
return Model.findOne(args, readOptions).then(function (found) {
var trimSpace;
if (!found) {
return when.resolve(slugToFind);
}
slugTryCount += 1;
// If this is the first time through, add the hyphen
if (slugTryCount === 2) {
slugToFind += '-';
} else {
// Otherwise, trim the number off the end
trimSpace = -(String(slugTryCount - 1).length);
slugToFind = slugToFind.slice(0, trimSpace);
}
slugToFind += slugTryCount;
return checkIfSlugExists(slugToFind);
});
};
// Remove URL reserved chars: `:/?#[]@!$&'()*+,;=` as well as `\%<>|^~£"`
slug = base.trim().replace(/[:\/\?#\[\]@!$&'()*+,;=\\%<>\|\^~£"]/g, '')
// Replace dots and spaces with a dash
.replace(/(\s|\.)/g, '-')
// Convert 2 or more dashes into a single dash
.replace(/-+/g, '-')
// Make the whole thing lowercase
.toLowerCase();
// Remove trailing hyphen
slug = slug.charAt(slug.length - 1) === '-' ? slug.substr(0, slug.length - 1) : slug;
// Remove non ascii characters
slug = unidecode(slug);
// Check the filtered slug doesn't match any of the reserved keywords
slug = /^(ghost|ghost\-admin|admin|wp\-admin|wp\-login|dashboard|logout|login|signin|signup|signout|register|archive|archives|category|categories|tag|tags|page|pages|post|posts|user|users)$/g
.test(slug) ? slug + '-post' : slug;
//if slug is empty after trimming use "post"
if (!slug) {
slug = 'post';
}
// Test for duplicate slugs.
return checkIfSlugExists(slug);
}
}, {
@ -236,6 +175,67 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
'delete': function () {
return this.destroy.apply(this, arguments);
},
// #### generateSlug
// Create a string act as the permalink for an object.
generateSlug: function (Model, base, readOptions) {
var slug,
slugTryCount = 1,
// Look for a post with a matching slug, append an incrementing number if so
checkIfSlugExists = function (slugToFind) {
var args = {slug: slugToFind};
//status is needed for posts
if (readOptions && readOptions.status) {
args.status = readOptions.status;
}
return Model.findOne(args, readOptions).then(function (found) {
var trimSpace;
if (!found) {
return when.resolve(slugToFind);
}
slugTryCount += 1;
// If this is the first time through, add the hyphen
if (slugTryCount === 2) {
slugToFind += '-';
} else {
// Otherwise, trim the number off the end
trimSpace = -(String(slugTryCount - 1).length);
slugToFind = slugToFind.slice(0, trimSpace);
}
slugToFind += slugTryCount;
return checkIfSlugExists(slugToFind);
});
};
// Remove URL reserved chars: `:/?#[]@!$&'()*+,;=` as well as `\%<>|^~£"`
slug = base.trim().replace(/[:\/\?#\[\]@!$&'()*+,;=\\%<>\|\^~£"]/g, '')
// Replace dots and spaces with a dash
.replace(/(\s|\.)/g, '-')
// Convert 2 or more dashes into a single dash
.replace(/-+/g, '-')
// Make the whole thing lowercase
.toLowerCase();
// Remove trailing hyphen
slug = slug.charAt(slug.length - 1) === '-' ? slug.substr(0, slug.length - 1) : slug;
// Remove non ascii characters
slug = unidecode(slug);
// Check the filtered slug doesn't match any of the reserved keywords
slug = /^(ghost|ghost\-admin|admin|wp\-admin|wp\-login|dashboard|logout|login|signin|signup|signout|register|archive|archives|category|categories|tag|tags|page|pages|post|posts|user|users)$/g
.test(slug) ? slug + '-post' : slug;
//if slug is empty after trimming use "post"
if (!slug) {
slug = 'post';
}
// Test for duplicate slugs.
return checkIfSlugExists(slug);
}
});

View File

@ -67,7 +67,7 @@ Post = ghostBookshelf.Model.extend({
if (this.hasChanged('slug')) {
// Pass the new slug through the generator to strip illegal characters, detect duplicates
return this.generateSlug(Post, this.get('slug'), {status: 'all', transacting: options.transacting})
return ghostBookshelf.Model.generateSlug(Post, this.get('slug'), {status: 'all', transacting: options.transacting})
.then(function (slug) {
self.set({slug: slug});
});
@ -84,14 +84,6 @@ Post = ghostBookshelf.Model.extend({
}
ghostBookshelf.Model.prototype.creating.call(this);
if (!this.get('slug')) {
// Generating a slug requires a db call to look for conflicting slugs
return this.generateSlug(Post, this.get('title'), {status: 'all', transacting: options.transacting})
.then(function (slug) {
self.set({slug: slug});
});
}
},
updateTags: function (newTags, attr, options) {
@ -397,6 +389,9 @@ Post = ghostBookshelf.Model.extend({
return post.destroy(options);
});
},
getSlug: function(options) {
}
});

View File

@ -10,6 +10,7 @@ module.exports = function (server) {
server.get('/ghost/api/v0.1/posts/:id', middleware.authAPI, api.requestHandler(api.posts.read));
server.put('/ghost/api/v0.1/posts/:id', middleware.authAPI, api.requestHandler(api.posts.edit));
server.del('/ghost/api/v0.1/posts/:id', middleware.authAPI, api.requestHandler(api.posts.destroy));
server.get('/ghost/api/v0.1/posts/getSlug/:title', middleware.authAPI, api.requestHandler(api.posts.getSlug));
// #### Settings
server.get('/ghost/api/v0.1/settings/', middleware.authAPI, api.requestHandler(api.settings.browse));
server.get('/ghost/api/v0.1/settings/:key/', middleware.authAPI, api.requestHandler(api.settings.read));

View File

@ -51,7 +51,7 @@
<label for="url">URL</label>
</td>
<td class="post-setting-field">
<input id="url" class="post-setting-slug" type="text" value="" />
<input id="url" class="post-setting-slug" type="text" placeholder="your-post-title" value="" />
</td>
</tr>
<tr class="post-setting">
@ -59,7 +59,7 @@
<label for="pub-date">Pub Date</label>
</td>
<td class="post-setting-field">
<input id="pub-date" class="post-setting-date" type="text" value=""><!--<span class="post-setting-calendar"></span>-->
<input id="pub-date" class="post-setting-date" type="text" placeholder="Now" value=""><!--<span class="post-setting-calendar"></span>-->
</td>
</tr>
<tr class="post-setting">