Ember settings/general

- Settings fixture that doesn't seem to work
- SettingsGeneralRoute with model function calling api
- SettingsGeneralModel with save method stubbed
- SettingsGeneralController with actions for save, uploadLogo and uploadCover
- Let ApplicationRoute handleValidationErrors
- Fix actions hash in controller and use bind-attr
- Refactor to use single SettingsModel
- Implement description word count
- Fix broken ajax reference by actually importing ajax method
- Refactor to use count-words helper
- Refactor isDatedPermalinks into controller
- Refactor the isDatedPermalinks to use a custom setter
- Remove isDatedPermalinks code from the model
This commit is contained in:
Jacob Gable 2014-03-20 21:55:32 -05:00
parent c6b1fea758
commit a548430a31
8 changed files with 175 additions and 7 deletions

View File

@ -0,0 +1,59 @@
var elementLookup = {
title: '#blog-title',
description: '#blog-description',
email: '#email-address',
postsPerPage: '#postsPerPage'
};
var SettingsGeneralController = Ember.ObjectController.extend({
isDatedPermalinks: function (key, value) {
// setter
if (arguments.length > 1) {
this.set('permalinks', value ? '/:year/:month/:day/:slug/' : '/:slug/');
}
// getter
var slugForm = this.get('permalinks');
return slugForm !== '/:slug/';
}.property('permalinks'),
actions: {
'save': function () {
// Validate and save settings
var model = this.get('model'),
// @TODO: Don't know how to scope this to this controllers view because this.view is null
errs = model.validate();
if (errs.length > 0) {
// Set the actual element from this view based on the error
errs.forEach(function (err) {
// @TODO: Probably should still be scoped to this controllers root element.
err.el = $(elementLookup[err.el]);
});
// Let the applicationRoute handle validation errors
this.send('handleValidationErrors', errs);
} else {
model.save().then(function () {
// @TODO: Notification of success
window.alert('Saved data!');
}, function () {
// @TODO: Notification of error
window.alert('Error saving data');
});
}
},
'uploadLogo': function () {
// @TODO: Integrate with Modal component
},
'uploadCover': function () {
// @TODO: Integrate with Modal component
}
}
});
export default SettingsGeneralController;

View File

@ -1,5 +1,6 @@
import postFixtures from 'ghost/fixtures/posts';
import userFixtures from 'ghost/fixtures/users';
import settingsFixtures from 'ghost/fixtures/settings';
var response = function (responseBody, status) {
status = status || 200;
@ -30,6 +31,10 @@ var posts = function (status) {
}, status);
};
var settings = function (status) {
return response(settingsFixtures, status);
};
var defineFixtures = function (status) {
ic.ajax.defineFixture('/ghost/api/v0.1/posts', posts(status));
ic.ajax.defineFixture('/ghost/api/v0.1/posts/1', post(1, status));
@ -45,6 +50,7 @@ var defineFixtures = function (status) {
ic.ajax.defineFixture('/ghost/api/v0.1/reset/', response({
msg: 'Password changed successfully'
}));
ic.ajax.defineFixture('/ghost/api/v0.1/settings/?type=blog,theme,app', settings(status));
};
export default defineFixtures;

24
fixtures/settings.js Normal file
View File

@ -0,0 +1,24 @@
var settings = {
"title": "Ghost",
"description": "Just a blogging platform.",
"email": "ghost@tryghost.org",
"logo": "",
"cover": "",
"defaultLang": "en_US",
"postsPerPage": "6",
"forceI18n": "true",
"permalinks": "/:slug/",
"activeTheme": "casper",
"activeApps": "[]",
"installedApps": "[]",
"availableThemes": [
{
"name": "casper",
"package": false,
"active": true
}
],
"availableApps": []
};
export default settings;

View File

@ -10,6 +10,21 @@ function ghostPaths() {
}
var BaseModel = Ember.Object.extend({
fetch: function () {
return ic.ajax.request(this.url, {
type: 'GET'
});
},
save: function () {
return ic.ajax.request(this.url, {
type: 'PUT',
dataType: 'json',
// @TODO: This is passing _oldWillDestory and _willDestroy and should not.
data: JSON.stringify(this.getProperties(Ember.keys(this)))
});
}
});
BaseModel.apiRoot = ghostPaths().apiRoot;

50
models/settings.js Normal file
View File

@ -0,0 +1,50 @@
var validator = window.validator;
import BaseModel from 'ghost/models/base';
export default BaseModel.extend({
url: BaseModel.apiRoot + '/settings/?type=blog,theme,app',
title: null,
description: null,
email: null,
logo: null,
cover: null,
defaultLang: null,
postsPerPage: null,
forceI18n: null,
permalinks: null,
activeTheme: null,
activeApps: null,
installedApps: null,
availableThemes: null,
availableApps: null,
validate: function () {
var validationErrors = [],
postsPerPage;
if (!validator.isLength(this.get('title'), 0, 150)) {
validationErrors.push({message: "Title is too long", el: 'title'});
}
if (!validator.isLength(this.get('description'), 0, 200)) {
validationErrors.push({message: "Description is too long", el: 'description'});
}
if (!validator.isEmail(this.get('email')) || !validator.isLength(this.get('email'), 0, 254)) {
validationErrors.push({message: "Please supply a valid email address", el: 'email'});
}
postsPerPage = this.get('postsPerPage');
if (!validator.isInt(postsPerPage) || postsPerPage > 1000) {
validationErrors.push({message: "Please use a number less than 1000", el: 'postsPerPage'});
}
if (!validator.isInt(postsPerPage) || postsPerPage < 0) {
validationErrors.push({message: "Please use a number greater than 0", el: 'postsPerPage'});
}
return validationErrors;
}
});

View File

@ -0,0 +1,13 @@
import ajax from 'ghost/utils/ajax';
import AuthenticatedRoute from 'ghost/routes/authenticated';
import SettingsModel from 'ghost/models/settings';
var SettingsGeneralRoute = AuthenticatedRoute.extend({
model: function () {
return ajax('/ghost/api/v0.1/settings/?type=blog,theme,app').then(function (resp) {
return SettingsModel.create(resp);
});
}
});
export default SettingsGeneralRoute;

View File

@ -1,4 +1,6 @@
var SettingsIndexRoute = Ember.Route.extend({
import AuthenticatedRoute from 'ghost/routes/authenticated';
var SettingsIndexRoute = AuthenticatedRoute.extend({
// redirect to general tab
redirect: function () {
this.transitionTo('settings.general');

View File

@ -2,7 +2,7 @@
<button class="button-back">Back</button>
<h2 class="title">General</h2>
<section class="page-actions">
<button class="button-save">Save</button>
<button class="button-save" {{action 'save'}}>Save</button>
</section>
</header>
@ -21,7 +21,7 @@
{{textarea id="blog-description" value=description}}
<p>
Describe what your blog is about
<span class="word-count">0</span>
<span class="word-count">{{count-words description}}</span>
</p>
</div>
@ -29,7 +29,7 @@
<div class="form-group">
<label for="blog-logo">Blog Logo</label>
{{#if logo}}
<a class="js-modal-logo" href="#"><img id="blog-logo" src="{{logo}}" alt="logo"></a>
<a class="js-modal-logo" href="#" {{action 'openModal' 'upload'}}><img id="blog-logo" {{bind-attr src=logo}} alt="logo"></a>
{{else}}
<a class="button-add js-modal-logo" {{action 'openModal' 'upload'}}>Upload Image</a>
{{/if}}
@ -39,7 +39,7 @@
<div class="form-group">
<label for="blog-cover">Blog Cover</label>
{{#if cover}}
<a class="js-modal-cover" href="#"><img id="blog-cover" src="{{cover}}" alt="cover photo"></a>
<a class="js-modal-cover" href="#" {{action 'openModal' 'upload'}}><img id="blog-cover" {{bind-attr src=logo}} alt="cover photo"></a>
{{else}}
<a class="button-add js-modal-cover" {{action 'openModal' 'upload'}}>Upload Image</a>
{{/if}}
@ -60,7 +60,7 @@
<div class="form-group">
<label for="permalinks">Dated Permalinks</label>
{{input id="permalinks" name="general[permalinks]" type="checkbox" value='permalink'}}
{{input id="permalinks" name="general[permalinks]" type="checkbox" checked=isDatedPermalinks}}
<label class="checkbox" for="permalinks"></label>
<p>Include the date in your post URLs</p>
</div>
@ -70,7 +70,6 @@
<select id="activeTheme" name="general[activeTheme]">
{{#each availableThemes}}
<option value="{{name}}" {{#if active}}selected{{/if}}>{{#if package}}{{package.name}} - {{package.version}}{{else}}{{name}}{{/if}}</option>
{{#unless package}}<script>console.log('Hi! The theme named "{{name}}" does not have a package.json file or it\'s malformed. This will be required in the future. For more info, see http://docs.ghost.org/themes/.');</script>{{/unless}}
{{/each}}
</select>
<p>Select a theme for your blog</p>