1
0
Fork 0
mirror of https://github.com/TryGhost/Ghost-Admin.git synced 2023-12-14 02:33:04 +01:00

Backbone template cleanup

- Ghost.View now extends Ghost.TemplateView giving all views access to subviews and templates
- Views which implemented templates no longer need to
- Some views needed to re-override render which is a bit annoying
- Settings screen now has sub-templates for each pane and for the sidebar
- Additional Casper tests for settings screen
This commit is contained in:
Hannah Wolfe 2013-08-01 23:33:06 +01:00
parent 86fad70ad4
commit 67b517fbbd
12 changed files with 515 additions and 89 deletions

View file

@ -0,0 +1,11 @@
<section id="appearance" class="settings-content">
<header>
<h2 class="title">Appearance</h2>
</header>
<section class="content">
<h6 class="sub">Raw json be here</h6>
<p>Active theme: {{json settings.activeTheme}}</p>
<p>Available themes: {{json availableThemes}}</p>
<p>Available plugins: {{json availablePlugins}}</p>
</section>
</section>

69
tpl/settings/content.hbs Normal file
View file

@ -0,0 +1,69 @@
<header>
<h2 class="title">Content</h2>
<section class="page-actions">
<button class="button-save">Save</button>
</section>
</header>
<section class="content">
<form id="settings-content">
<fieldset>
<div class="form-group">
<label for="typography"><strong>Typography</strong></label>
<select id="typography" name="content[typography]">
<option value="post-name">Lato (Light)</option>
</select>
<p>Sexy sans-serif font that will make your toes tickle.</p>
<label class="checkbox">
<input type="checkbox" value="1" name="content[type-load-google]"/> Load fonts directly from Google
</label>
</div>
<div class="form-group">
<label><strong>Post Options</strong></label>
<label class="checkbox">
<input type="checkbox" name="content[display-post-meta]" value="1" /> Display Post Meta
</label>
<p>Post Author / Date / Views</p>
<label class="checkbox">
<input type="checkbox" name="content[show-author]" value="1" /> Show Author Box After Post
</label>
<label class="checkbox">
<input type="checkbox" name="content[comments]" value="1" /> Enable Comments
</label>
</div>
</fieldset>
<hr />
<fieldset>
<div class="form-group">
<label for="seo-title"><strong>SEO Title Pattern</strong></label>
<input id="seo-title" name="content[seo-title]" type="text" value="[Post Name] - [Site Title]" />
<p>The pattern used to display your title tags</p>
</div>
<div class="form-group">
<label for="seo-description"><strong>SEO Description Pattern</strong></label>
<input id="seo-description" name="content[seo-description]" type="text" value="Auto" />
<p>The pattern used to display your meta descriptions</p>
</div>
<div class="form-group">
<label><strong>Google+</strong></label>
<label class="checkbox">
<input type="checkbox" name="content[google-profile]" value="1" /> Connect to author profile on Google
</label>
</div>
<div class="form-group">
<label for="blog-description"><strong>Home Page Description</strong></label>
<textarea id="blog-description">{{description}}</textarea>
</div>
</fieldset>
</form>
</section>

60
tpl/settings/general.hbs Normal file
View file

@ -0,0 +1,60 @@
<header>
<h2 class="title">General</h2>
<section class="page-actions">
<button class="button-save">Save</button>
</section>
</header>
<section class="content">
<form id="settings-general">
<fieldset>
<div class="form-group">
<label><strong>Blog Title</strong></label>
<input id="blog-title" name="general[title]" type="text" value="{{title}}" />
<p>How your blog name appears on the site</p>
</div>
<div class="form-group">
<label><strong>Blog Logo</strong></label>
<img src="/public/img/logo.png" alt="logo" height="38" width="381"/>
<p>Display a logo on your site in place of blog title</p>
</div>
<div class="form-group">
<label><strong>Blog Icon</strong></label>
<img src="/public/img/test-icon.png" alt="logo" height="38" width="38"/>
<p>The icon for your blog, used in your browser tab and elsewhere</p>
</div>
<div class="form-group">
<label for="email-address"><strong>Email Address</strong></label>
<input id="email-address" name="general[email-address]" type="text" value="{{email}}" />
<p>Address to use for <a href="#">admin notifications</a></p>
<label class="checkbox">
<input type="checkbox" value="1" name="general[public-email]" /> Show my email address on my public profile
</label>
</div>
<div class="form-group">
<label for="url-structure"><strong>URL Structure</strong></label>
<select id="url-structure" name="general[urlstructure]">
<option value="post-name">Simple Post Name</option>
<option value="date-based">Date Based</option>
<option value="number based">Number Based</option>
<option value="custom">Custom...</option>
</select>
</div>
</fieldset>
<hr />
<fieldset>
<div class="form-group">
<label for="timezone"><strong>Time Zone</strong></label>
<select id="timezone" name="general[timezone]">
<option value="1">Vienna (UTC+1)</option>
</select>
</div>
</fieldset>
</form>
</section>

241
tpl/settings/plugins.hbs Normal file
View file

@ -0,0 +1,241 @@
<!-- id should be plugins-->
<header>
<h2 class="title">Plugins</h2>
<section class="page-actions">
<button class="button-add">Add Plugin</button>
</section>
</header>
<section class="content">
<section class="plugin-section">
<header class="plugin-section-header">
<h3>Updates</h3>
</header>
<table class="plugin-section-table">
<tbody>
<tr class="plugin-section-item">
<td>
<figure class="plugin-icon">
</figure>
<section class="plugin-meta">
<span class="plugin-title plugin-info">Ghost SEO</span>
<span class="plugin-download-progress" data-complete="45">
<span style="width: 45%"></span>
</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">Yoast</span>
<span class="plugin-sub-info">yoast.com</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">v 0.1.13</span>
<span class="plugin-sub-info">3 weeks ago</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info rating">
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span></span>
</span>
<span class="plugin-sub-info">48,200 users</span>
</section>
</td>
<td>
<section class="plugin-meta">
<button class="button-delete button-cancel">Cancel</button>
</section>
</td>
</tr>
<tr class="plugin-section-item">
<td>
<figure class="plugin-icon">
</figure>
<section class="plugin-meta">
<span class="plugin-title plugin-info">Ghost SEO</span>
<span class="plugin-sub-info">The #1 content marketing plugin for Ghost.</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">Yoast</span>
<span class="plugin-sub-info">yoast.com</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">v 0.1.13</span>
<span class="plugin-sub-info">3 weeks ago</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info rating">
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span></span>
</span>
<span class="plugin-sub-info">48,200 users</span>
</section>
</td>
<td>
<section class="plugin-meta">
<button class="button-save">Update</button>
</section>
</td>
</tr>
</tbody>
</table>
<footer class="plugin-section-footer">
<button class="button-alt button-update-all">Update All</button>
</footer>
</section>
<section class="plugin-section">
<header class="plugin-section-header">
<h3>Active Plugins</h3>
</header>
<table class="plugin-section-table">
<tbody>
<tr class="plugin-section-item">
<td>
<figure class="plugin-icon">
</figure>
<section class="plugin-meta">
<span class="plugin-title plugin-info">Ghost SEO</span>
<span class="plugin-sub-info">The #1 content marketing plugin for Ghost.</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">Yoast</span>
<span class="plugin-sub-info">yoast.com</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">v 0.1.13</span>
<span class="plugin-sub-info">3 weeks ago</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info rating">
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span></span>
</span>
<span class="plugin-sub-info">48,200 users</span>
</section>
</td>
<td>
<section class="plugin-meta">
<a href="#" class="plugin-settings-icon"></a>
</section>
</td>
</tr>
<tr class="plugin-section-item">
<td>
<figure class="plugin-icon">
</figure>
<section class="plugin-meta">
<span class="plugin-title plugin-info">Ghost SEO</span>
<span class="plugin-sub-info">The #1 content marketing plugin for Ghost.</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">Yoast</span>
<span class="plugin-sub-info">yoast.com</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">v 0.1.13</span>
<span class="plugin-sub-info">3 weeks ago</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info rating">
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span></span>
</span>
<span class="plugin-sub-info">48,200 users</span>
</section>
</td>
<td>
<section class="plugin-meta">
<a href="#" class="plugin-settings-icon"></a>
</section>
</td>
</tr>
</tbody>
</table>
</section>
<section class="plugin-section">
<header class="plugin-section-header">
<h3>Inactive Plugins</h3>
</header>
<table class="plugin-section-table">
<tbody>
<tr class="plugin-section-item inactive">
<td>
<figure class="plugin-icon">
</figure>
<section class="plugin-meta">
<span class="plugin-title plugin-info">Ghost SEO</span>
<span class="plugin-sub-info">The #1 content marketing plugin for Ghost.</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">Yoast</span>
<span class="plugin-sub-info">yoast.com</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info">v 0.1.13</span>
<span class="plugin-sub-info">3 weeks ago</span>
</section>
</td>
<td>
<section class="plugin-meta">
<span class="plugin-info rating">
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span class="active"></span>
<span></span>
</span>
<span class="plugin-sub-info">48,200 users</span>
</section>
</td>
<td>
<section class="plugin-meta">
<button class="button-add">Activate</button>
</section>
</td>
</tr>
</tbody>
</table>
</section>
</section>

9
tpl/settings/sidebar.hbs Normal file
View file

@ -0,0 +1,9 @@
<header>
<h1 class="title">Settings</h1>
</header>
<nav class="settings-menu">
<ul>
<li class="general"><a href="#general">General</a></li>
<li class="publishing"><a href="#content">Content</a></li>
</ul>
</nav>

57
tpl/settings/users.hbs Normal file
View file

@ -0,0 +1,57 @@
<section id="users" class="settings-content">
<header>
<h2 class="title">Users</h2>
<section class="page-actions">
<button class="button-add">New User</button>
</section>
</header>
<section class="content">
<section id="users-pending" class="user-group">
<header class="user-group-header"><h3>Invited Users</h3></header>
<ul class="users">
<li class="user">
<figure class="user-image invite"></figure>
<section class="user-meta">
<h4 class="user-name">Some Name</h4>
<span class="user-last-seen">Invitation Sent: 7 hours ago</span>
</section>
</li>
</ul>
</section>
<section id="users-active" class="user-group">
<header class="user-group-header">
<h3>Active Users</h3>
<form class="user-search">
<label>
<i class="search-icon"></i>
<input class="user-search-input" type="text"/>
</label>
</form>
</header>
<ul class="users">
<li class="user">
<figure class="user-image">
<img src="/public/img/user.jpg" alt="user"/>
</figure>
<section class="user-meta">
<h4 class="user-name">Some Name</h4>
<span class="user-last-seen">Last Seen: 7 hours ago</span>
</section>
<span class="user-role admin">Admin</span>
</li>
<li class="user">
<figure class="user-image">
<img src="/public/img/user.jpg" alt="user"/>
</figure>
<section class="user-meta">
<h4 class="user-name">Some Name</h4>
<span class="user-last-seen">Last Seen: 2 days ago</span>
</section>
<span class="user-role editor">Editor</span>
</li>
</ul>
</section>
</section>
</section>

View file

@ -2,7 +2,41 @@
(function () {
"use strict";
Ghost.View = Backbone.View.extend({
Ghost.TemplateView = Backbone.View.extend({
templateName: "widget",
template: function (data) {
return JST[this.templateName](data);
},
templateData: function () {
if (this.model) {
return this.model.toJSON();
}
if (this.collection) {
return this.collection.toJSON();
}
return {};
},
render: function () {
if (_.isFunction(this.beforeRender)) {
this.beforeRender();
}
this.$el.html(this.template(this.templateData()));
if (_.isFunction(this.afterRender)) {
this.afterRender();
}
return this;
}
});
Ghost.View = Ghost.TemplateView.extend({
// Adds a subview to the current view, which will
// ensure its removal when this view is removed,
@ -42,36 +76,6 @@
});
Ghost.TemplateView = Ghost.View.extend({
templateName: "widget",
template: function (data) {
return JST[this.templateName](data);
},
templateData: function () {
if (this.model) {
return this.model.toJSON();
}
if (this.collection) {
return this.collection.toJSON();
}
return {};
},
render: function () {
this.$el.html(this.template(this.templateData()));
if (_.isFunction(this.afterRender)) {
this.afterRender();
}
return this;
}
});
/**
* This is the view to generate the markup for the individual
* notification. Will be included into #flashbar.

View file

@ -111,15 +111,9 @@
templateName: "list-item",
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
this.$el.html(this.template(_.extend({active: this.active}, this.model.toJSON())));
return this;
templateData: function () {
return _.extend({active: this.active}, this.model.toJSON());
}
});
// Content preview
@ -182,14 +176,10 @@
templateName: "preview",
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
if (this.activeId) {
this.model = this.collection.get(this.activeId);
this.$el.html(this.template(this.model.toJSON()));
this.$el.html(this.template(this.templateData()));
}
this.$('.wrapper').on('click', 'a', function (e) {
$(e.currentTarget).attr('target', '_blank');
@ -200,4 +190,4 @@
});
}());
}());

View file

@ -137,12 +137,7 @@
templateName: "widget",
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
afterRender: function () {
if (!this.model.attributes.settings.enabled) {
this.$(".widget-content").html(this.addSubview(new WidgetContent({model: this.model})).render().el);
} else {
@ -160,11 +155,6 @@
template: function (data) {
return JST['widgets/' + this.model.attributes.content.template](data);
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});

View file

@ -41,14 +41,16 @@
initialize: function () {
this.addSubview(new TagWidget({el: this.$('#entry-categories'), model: this.model})).render();
this.addSubview(new ActionsWidget({el: this.$('#entry-actions'), model: this.model})).render();
}
},
render: function () { return this; }
});
// The Tag UI area associated with a post
// ----------------------------------------
TagWidget = Ghost.View.extend({
render: function () { return this; }
});
// The Publish, Queue, Publish Now buttons
@ -372,9 +374,9 @@
}
}
}));
}
},
render: function () { return this; }
});
}());

View file

@ -15,13 +15,8 @@
$(window).trigger('resize');
},
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
afterRender: function () {
var self = this;
this.$el.html(this.template());
$(window).on('resize', _.debounce(function (e) {
$(".js-login-container").center();
@ -78,15 +73,6 @@
this.render();
},
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
this.$el.html(this.template());
return this;
},
submitHandler: function (event) {
event.preventDefault();
var email = this.$el.find('.email').val(),

View file

@ -25,6 +25,7 @@
// ---------------
Settings.Sidebar = Ghost.View.extend({
initialize: function (options) {
this.render();
this.menu = this.$('.settings-menu');
this.showContent(options.pane || 'general');
},
@ -42,19 +43,21 @@
showContent: function (id) {
Backbone.history.navigate('/settings/' + id);
if (this.pane && '#' + id === this.pane.el) {
if (this.pane && id === this.pane.el.id) {
return;
}
_.result(this.pane, 'destroy');
this.setActive(id);
this.pane = new Settings[id]({ model: this.model });
this.pane = new Settings[id]({ el: '.settings-content', model: this.model });
this.pane.render();
},
setActive: function (id) {
this.menu.find('li').removeClass('active');
this.menu.find('a[href=#' + id + ']').parent().addClass('active');
}
},
templateName: 'settings/sidebar'
});
// Content panes
@ -65,17 +68,18 @@
this.undelegateEvents();
},
render: function () {
afterRender: function () {
this.$el.attr('id', this.id);
this.$el.addClass('active');
}
});
// TODO: render templates on the client
// TODO: use some kind of data-binding for forms
// ### General settings
Settings.general = Settings.Pane.extend({
el: '#general',
id: "general",
events: {
'click .button-save': 'saveSettings'
},
@ -107,26 +111,28 @@
});
},
render: function () {
templateName: 'settings/general',
beforeRender: function () {
var settings = this.model.toJSON();
this.$('#blog-title').val(settings.title);
this.$('#email-address').val(settings.email);
Settings.Pane.prototype.render.call(this);
}
});
// ### Content settings
Settings.content = Settings.Pane.extend({
el: '#content',
id: 'content',
events: {
'click .button-save': 'saveSettings'
},
saveSettings: function () {
var self = this;
this.model.save({
description: this.$('#blog-description').val()
}, {
success: function () {
this.addSubview(new Ghost.Views.NotificationCollection({
self.addSubview(new Ghost.Views.NotificationCollection({
model: [{
type: 'success',
message: 'Saved',
@ -136,7 +142,7 @@
},
error: function () {
this.addSubview(new Ghost.Views.NotificationCollection({
self.addSubview(new Ghost.Views.NotificationCollection({
model: [{
type: 'error',
message: 'Something went wrong, not saved :(',
@ -147,10 +153,11 @@
});
},
render: function () {
templateName: 'settings/content',
beforeRender: function () {
var settings = this.model.toJSON();
this.$('#blog-description').val(settings.description);
Settings.Pane.prototype.render.call(this);
}
});