Amend fixtures & put body classes in styleBody mixin

- Change fixture response of posts route to actual format.
- Extracted classNames logic of routes into style-body mixin.
- Additionally replaced all double-quotes with single-quotes for style conformance.
This commit is contained in:
Manuel Mitasch 2014-03-03 21:18:10 +01:00 committed by Hannah Wolfe
parent 01b49fede8
commit 275f623278
24 changed files with 277 additions and 146 deletions

View File

@ -10,33 +10,10 @@ var App = Ember.Application.extend({
LOG_TRANSITIONS: true,
LOG_TRANSITIONS_INTERNAL: true,
LOG_VIEW_LOOKUPS: true,
modulePrefix: 'ghost', // TODO: loaded via config
modulePrefix: 'ghost',
Resolver: Resolver['default']
});
initFixtures();
// TODO move into ext/route.js
// needed to add body class depending on current route
Ember.Route.reopen({
activate: function () {
var cssClasses = this.get('classNames'),
rootElement = this.router.namespace.get('rootElement');
if (cssClasses) {
Ember.run.schedule('afterRender', null, function () {
Ember.$(rootElement).addClass(cssClasses);
});
}
},
deactivate: function () {
var cssClasses = this.get('classNames'),
rootElement = this.router.namespace.get('rootElement');
Ember.run.schedule('afterRender', null, function () {
Ember.$(rootElement).removeClass(cssClasses);
});
}
});
export default App;

View File

@ -15,30 +15,30 @@ var onScrollHandler = function (cm) {
}, 50);
};
export default Ember.TextArea.extend({
var Codemirror = Ember.TextArea.extend({
initCodemirror: function () {
// create codemirror
this.codemirror = CodeMirror.fromTextArea(this.get('element'), {
lineWrapping: true
});
this.codemirror.component = this; // save reference to this
// propagate changes to value property
this.codemirror.on("change", onChangeHandler);
this.codemirror.on('change', onChangeHandler);
// on scroll update scrollPosition property
this.codemirror.on("scroll", onScrollHandler);
}.on("didInsertElement"),
this.codemirror.on('scroll', onScrollHandler);
}.on('didInsertElement'),
removeThrottle: function () {
Ember.run.cancel(this.throttle);
}.on("willDestroyElement"),
}.on('willDestroyElement'),
removeCodemirrorHandlers: function () {
// not sure if this is needed.
this.codemirror.off("change", onChangeHandler);
this.codemirror.off("scroll", onScrollHandler);
}.on("willDestroyElement")
this.codemirror.off('change', onChangeHandler);
this.codemirror.off('scroll', onScrollHandler);
}.on('willDestroyElement')
});
});
export default Codemirror;

View File

@ -0,0 +1,11 @@
var Markdown = Ember.Component.extend({
adjustScrollPosition: function () {
var scrollWrapper = this.$('.entry-preview-content').get(0),
// calculate absolute scroll position from percentage
scrollPixel = scrollWrapper.scrollHeight * this.get('scrollPosition');
scrollWrapper.scrollTop = scrollPixel; // adjust scroll position
}.observes('scrollPosition')
});
export default Markdown;

View File

@ -1,8 +0,0 @@
export default Ember.Component.extend({
adjustScrollPosition: function () {
var scrollWrapper = this.$(".entry-preview-content").get(0),
scrollPixel = scrollWrapper.scrollHeight * this.get('scrollPosition'); // calculate absolute scroll position from percentage
scrollWrapper.scrollTop = scrollPixel; // adjust scroll position
}.observes("scrollPosition")
});

View File

@ -1,6 +1,8 @@
var equal = Ember.computed.equal;
export default Ember.ObjectController.extend({
var PostController = Ember.ObjectController.extend({
isPublished: equal('status', 'published'),
isDraft: equal('status', 'draft')
});
});
export default PostController;

View File

@ -11,14 +11,22 @@ var post = function (id) {
var posts = function () {
return {
response: postFixtures,
response: {
'posts': postFixtures,
'page': 1,
'limit': 15,
'pages': 1,
'total': 2
},
jqXHR: {},
textStatus: 'success'
};
};
export default function () {
var defineFixtures = function () {
ic.ajax.defineFixture('/ghost/api/v0.1/posts', posts());
ic.ajax.defineFixture('/ghost/api/v0.1/posts/1', post(1));
ic.ajax.defineFixture('/ghost/api/v0.1/posts/2', post(2));
}
};
export default defineFixtures;

View File

@ -1,24 +1,143 @@
export default [
var posts = [
{
"id": 2,
"uuid": "4dc16b9e-bf90-44c9-97c5-40a0a81e8297",
"title": "Ghost Ember Demo Post",
"slug": "ghost-ember-demo-post",
"markdown": "Lorem **ipsum** dolor sit amet, consectetur adipiscing elit. Fusce id felis nec est suscipit scelerisque vitae eu arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam erat volutpat. Sed pellentesque metus vel velit tincidunt aliquet. Nunc condimentum tempus convallis. Sed tincidunt, leo et congue blandit, lorem tortor imperdiet sapien, et porttitor turpis nisl sed tellus. In ultrices urna sit amet mauris suscipit adipiscing.",
"html": "<p>Lorem <strong>ipsum<\/strong> dolor sit amet, consectetur adipiscing elit. Fusce id felis nec est suscipit scelerisque vitae eu arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam erat volutpat. Sed pellentesque metus vel velit tincidunt aliquet. Nunc condimentum tempus convallis. Sed tincidunt, leo et congue blandit, lorem tortor imperdiet sapien, et porttitor turpis nisl sed tellus. In ultrices urna sit amet mauris suscipit adipiscing.<\/p>",
"image": null,
"featured": 0,
"page": 0,
"status": "draft",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": "2014-02-15T23:27:08.000Z",
"created_by": 1,
"updated_at": "2014-02-15T23:27:08.000Z",
"updated_by": 1,
"published_at": null,
"published_by": null,
"author": {
"id": 1,
"name": "manuel_mitasch"
}
"uuid": "ba9c67e4-8046-4b8c-9349-0eed3cca7529",
"name": "manuel_mitasch",
"slug": "manuel_mitasch",
"email": "manuel@cms.mine.nu",
"image": null,
"cover": null,
"bio": null,
"website": null,
"location": null,
"accessibility": null,
"status": "active",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"created_at": "2014-02-15T20:02:25.000Z",
"updated_at": "2014-02-15T20:02:25.000Z"
},
"user": {
"id": 1,
"uuid": "ba9c67e4-8046-4b8c-9349-0eed3cca7529",
"name": "manuel_mitasch",
"slug": "manuel_mitasch",
"email": "manuel@cms.mine.nu",
"image": null,
"cover": null,
"bio": null,
"website": null,
"location": null,
"accessibility": null,
"status": "active",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"created_at": "2014-02-15T20:02:25.000Z",
"updated_at": "2014-02-15T20:02:25.000Z"
},
"tags": [
]
},
{
"id": 1,
"uuid": "4b96025d-050c-47ff-8bd4-047e4843b302",
"title": "Welcome to Ghost",
"slug": "welcome-to-ghost",
"markdown": "You're live! Nice. We've put together a little post to introduce you to the Ghost editor and get you started. You can manage your content by signing in to the admin area at `<your blog URL>\/ghost\/`. When you arrive, you can select this post from a list on the left and see a preview of it on the right. Click the little pencil icon at the top of the preview to edit this post and read the next section!\n\n## Getting Started\n\nGhost uses something called Markdown for writing. Essentially, it's a shorthand way to manage your post formatting as you write!\n\nWriting in Markdown is really easy. In the left hand panel of Ghost, you simply write as you normally would. Where appropriate, you can use *shortcuts* to **style** your content. For example, a list:\n\n* Item number one\n* Item number two\n * A nested item\n* A final item\n\nor with numbers!\n\n1. Remember to buy some milk\n2. Drink the milk\n3. Tweet that I remembered to buy the milk, and drank it\n\n### Links\n\nWant to link to a source? No problem. If you paste in url, like http:\/\/ghost.org - it'll automatically be linked up. But if you want to customise your anchor text, you can do that too! Here's a link to [the Ghost website](http:\/\/ghost.org). Neat.\n\n### What about Images?\n\nImages work too! Already know the URL of the image you want to include in your article? Simply paste it in like this to make it show up:\n\n![The Ghost Logo](https:\/\/ghost.org\/images\/ghost.png)\n\nNot sure which image you want to use yet? That's ok too. Leave yourself a descriptive placeholder and keep writing. Come back later and drag and drop the image in to upload:\n\n![A bowl of bananas]\n\n\n### Quoting\n\nSometimes a link isn't enough, you want to quote someone on what they've said. It was probably very wisdomous. Is wisdomous a word? Find out in a future release when we introduce spellcheck! For now - it's definitely a word.\n\n> Wisdomous - it's definitely a word.\n\n### Working with Code\n\nGot a streak of geek? We've got you covered there, too. You can write inline `<code>` blocks really easily with back ticks. Want to show off something more comprehensive? 4 spaces of indentation gets you there.\n\n .awesome-thing {\n display: block;\n width: 100%;\n }\n\n### Ready for a Break? \n\nThrow 3 or more dashes down on any new line and you've got yourself a fancy new divider. Aw yeah.\n\n---\n\n### Advanced Usage\n\nThere's one fantastic secret about Markdown. If you want, you can write plain old HTML and it'll still work! Very flexible.\n\n<input type=\"text\" placeholder=\"I'm an input field!\" \/>\n\nThat should be enough to get you started. Have fun - and let us know what you think :)",
"html": "<p>You're live! Nice. We've put together a little post to introduce you to the Ghost editor and get you started. You can manage your content by signing in to the admin area at <code>&lt;your blog URL&gt;\/ghost\/<\/code>. When you arrive, you can select this post from a list on the left and see a preview of it on the right. Click the little pencil icon at the top of the preview to edit this post and read the next section!<\/p>\n\n<h2 id=\"gettingstarted\">Getting Started<\/h2>\n\n<p>Ghost uses something called Markdown for writing. Essentially, it's a shorthand way to manage your post formatting as you write!<\/p>\n\n<p>Writing in Markdown is really easy. In the left hand panel of Ghost, you simply write as you normally would. Where appropriate, you can use <em>shortcuts<\/em> to <strong>style<\/strong> your content. For example, a list:<\/p>\n\n<ul>\n<li>Item number one<\/li>\n<li>Item number two\n<ul><li>A nested item<\/li><\/ul><\/li>\n<li>A final item<\/li>\n<\/ul>\n\n<p>or with numbers!<\/p>\n\n<ol>\n<li>Remember to buy some milk <\/li>\n<li>Drink the milk <\/li>\n<li>Tweet that I remembered to buy the milk, and drank it<\/li>\n<\/ol>\n\n<h3 id=\"links\">Links<\/h3>\n\n<p>Want to link to a source? No problem. If you paste in url, like <a href='http:\/\/ghost.org'>http:\/\/ghost.org<\/a> - it'll automatically be linked up. But if you want to customise your anchor text, you can do that too! Here's a link to <a href=\"http:\/\/ghost.org\">the Ghost website<\/a>. Neat.<\/p>\n\n<h3 id=\"whataboutimages\">What about Images?<\/h3>\n\n<p>Images work too! Already know the URL of the image you want to include in your article? Simply paste it in like this to make it show up:<\/p>\n\n<p><img src=\"https:\/\/ghost.org\/images\/ghost.png\" alt=\"The Ghost Logo\" \/><\/p>\n\n<p>Not sure which image you want to use yet? That's ok too. Leave yourself a descriptive placeholder and keep writing. Come back later and drag and drop the image in to upload:<\/p>\n\n<h3 id=\"quoting\">Quoting<\/h3>\n\n<p>Sometimes a link isn't enough, you want to quote someone on what they've said. It was probably very wisdomous. Is wisdomous a word? Find out in a future release when we introduce spellcheck! For now - it's definitely a word.<\/p>\n\n<blockquote>\n <p>Wisdomous - it's definitely a word.<\/p>\n<\/blockquote>\n\n<h3 id=\"workingwithcode\">Working with Code<\/h3>\n\n<p>Got a streak of geek? We've got you covered there, too. You can write inline <code>&lt;code&gt;<\/code> blocks really easily with back ticks. Want to show off something more comprehensive? 4 spaces of indentation gets you there.<\/p>\n\n<pre><code>.awesome-thing {\n display: block;\n width: 100%;\n}\n<\/code><\/pre>\n\n<h3 id=\"readyforabreak\">Ready for a Break?<\/h3>\n\n<p>Throw 3 or more dashes down on any new line and you've got yourself a fancy new divider. Aw yeah.<\/p>\n\n<hr \/>\n\n<h3 id=\"advancedusage\">Advanced Usage<\/h3>\n\n<p>There's one fantastic secret about Markdown. If you want, you can write plain old HTML and it'll still work! Very flexible.<\/p>\n\n<p><input type=\"text\" placeholder=\"I'm an input field!\" \/><\/p>\n\n<p>That should be enough to get you started. Have fun - and let us know what you think :)<\/p>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": "2014-02-15T20:02:01.000Z",
"created_by": 1,
"updated_at": "2014-02-15T20:02:01.000Z",
"updated_by": 1,
"published_at": "2014-02-15T20:02:01.000Z",
"published_by": 1,
"author": {
"id": 1,
"name": "manuel_mitasch"
}
"uuid": "ba9c67e4-8046-4b8c-9349-0eed3cca7529",
"name": "manuel_mitasch",
"slug": "manuel_mitasch",
"email": "manuel@cms.mine.nu",
"image": null,
"cover": null,
"bio": null,
"website": null,
"location": null,
"accessibility": null,
"status": "active",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"created_at": "2014-02-15T20:02:25.000Z",
"updated_at": "2014-02-15T20:02:25.000Z"
},
"user": {
"id": 1,
"uuid": "ba9c67e4-8046-4b8c-9349-0eed3cca7529",
"name": "manuel_mitasch",
"slug": "manuel_mitasch",
"email": "manuel@cms.mine.nu",
"image": null,
"cover": null,
"bio": null,
"website": null,
"location": null,
"accessibility": null,
"status": "active",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"created_at": "2014-02-15T20:02:25.000Z",
"updated_at": "2014-02-15T20:02:25.000Z"
},
"tags": [
{
"id": 1,
"uuid": "406edaaf-5b1c-4199-b297-2af90b1de1a7",
"name": "Getting Started",
"slug": "getting-started",
"description": null,
"parent_id": null,
"meta_title": null,
"meta_description": null,
"created_at": "2014-02-15T20:02:01.000Z",
"created_by": 1,
"updated_at": "2014-02-15T20:02:01.000Z",
"updated_by": 1
}
]
}
];
];
export default posts;

View File

@ -1,5 +1,7 @@
import count from "ghost/utils/word-counter";
import count from 'ghost/utils/word-count';
export default Ember.Handlebars.makeBoundHelper(function (markdown) {
var countWords = Ember.Handlebars.makeBoundHelper(function (markdown) {
return count(markdown);
});
});
export default countWords;

View File

@ -1,6 +1,8 @@
/* global Showdown, Handlebars */
var showdown = new Showdown.converter();
export default Ember.Handlebars.makeBoundHelper(function (markdown) {
var formatMarkdown = Ember.Handlebars.makeBoundHelper(function (markdown) {
return new Handlebars.SafeString(showdown.makeHtml(markdown));
});
});
export default formatMarkdown;

View File

@ -1,7 +1,9 @@
/* global moment */
export default Ember.Handlebars.makeBoundHelper(function (timeago) {
var formatTimeago = Ember.Handlebars.makeBoundHelper(function (timeago) {
return moment(timeago).fromNow();
// stefanpenner says cool for small number of timeagos.
// For large numbers moment sucks => single Ember.Object based clock better
// https://github.com/manuelmitasch/ghost-admin-ember-demo/commit/fba3ab0a59238290c85d4fa0d7c6ed1be2a8a82e#commitcomment-5396524
});
export default formatTimeago;

View File

@ -0,0 +1,27 @@
// mixin used for routes that need to set a css className on the body tag
var styleBody = Ember.Mixin.create({
activate: function () {
var cssClasses = this.get('classNames');
if (cssClasses) {
Ember.run.schedule('afterRender', null, function () {
cssClasses.forEach(function (curClass) {
Ember.$('body').addClass(curClass);
});
});
}
},
deactivate: function () {
var cssClasses = this.get('classNames');
Ember.run.schedule('afterRender', null, function () {
cssClasses.forEach(function (curClass) {
Ember.$('body').removeClass(curClass);
});
});
}
});
export default styleBody;

View File

@ -1,9 +1,12 @@
import ajax from "ghost/utils/ajax";
import ajax from 'ghost/utils/ajax';
import styleBody from 'ghost/mixins/style-body';
export default Ember.Route.extend({
classNames: "editor",
var EditorRoute = Ember.Route.extend(styleBody, {
classNames: ['editor'],
model: function (params) {
return ajax("/ghost/api/v0.1/posts/" + params.post_id);
return ajax('/ghost/api/v0.1/posts/' + params.post_id);
}
});
});
export default EditorRoute;

View File

@ -1,11 +0,0 @@
export default Ember.Route.extend({
model: function (params) {
var posts = this.modelFor('posts').posts,
id = parseInt(params.post_id);
return posts.findBy('id', id);
// model already loaded in parent route => no ajax call to server
// return ajax("/ghost/api/v0.1/posts/" + params.post_id);
}
});

View File

@ -1,10 +1,13 @@
import ajax from "ghost/utils/ajax";
import ajax from 'ghost/utils/ajax';
import styleBody from 'ghost/mixins/style-body';
export default Ember.Route.extend({
classNames: "manage",
var PostsRoute = Ember.Route.extend(styleBody, {
classNames: ['manage'],
model: function () {
return ajax("/ghost/api/v0.1/posts");
return ajax('/ghost/api/v0.1/posts').then(function (response) {
return response.posts;
});
},
actions: {
@ -13,3 +16,5 @@ export default Ember.Route.extend({
}
}
});
export default PostsRoute;

View File

@ -1,4 +1,4 @@
export default Ember.Route.extend({
var PostsIndexRoute = Ember.Route.extend({
// redirect to first post subroute
redirect: function () {
var firstPost = (this.modelFor('posts') || []).get('firstObject');
@ -7,4 +7,6 @@ export default Ember.Route.extend({
this.transitionTo('posts.post', firstPost);
}
}
});
});
export default PostsIndexRoute;

View File

@ -1,7 +1,8 @@
/*global ajax */
export default Ember.Route.extend({
var PostsPostRoute = Ember.Route.extend({
model: function (params) {
return ajax("/ghost/api/v0.1/posts/" + params.post_id);
return ajax('/ghost/api/v0.1/posts/' + params.post_id);
}
});
});
export default PostsPostRoute;

View File

@ -1,33 +0,0 @@
/* Put your CSS here */
/*
@keyframes domChanged { from { background: yellow; } }
@-webkit-keyframes domChanged { from { background: yellow; } }
.ember-view { animation: domChanged 1s; -webkit-animation: domChanged 1s; }
*/
/* Cosmetic changes to ghost styles */
.post-settings-menu {
display: none !important;
}
#entry-markdown, .entry-preview, .CodeMirror.cm-s-default {
height: 500px !important;
}
.editor .entry-title {
box-shadow: none !important;
background: none !important;
padding: 0 !important;
height: auto !important;
}
.editor input {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
@font-face {
font-family: "Icons";
src: url("https://testblog111.ghost.io/ghost/fonts/icons.woff") format('woff');
}

File diff suppressed because one or more lines are too long

View File

@ -9,12 +9,15 @@
<span class="author">{{author.name}}</span>
</small>
<section class="post-controls">
{{#link-to "editor" this class="post-edit" title="Edit Post"}}<span class="hidden">Edit Post</span>{{/link-to}}
{{#link-to "editor" this class="post-edit" title="Edit Post"}}
<span class="hidden">Edit Post</span>
{{/link-to}}
<a class="post-settings" href="#" data-toggle=".post-settings-menu" title="Post Settings"><span class="hidden">Post Settings</span></a>
<div class="post-settings-menu menu-drop-right overlay" style="display: none;">
<form>
<table class="plain">
<tbody><tr class="post-setting">
<tbody>
<tr class="post-setting">
<td class="post-setting-label">
<label for="url">URL</label>
</td>
@ -39,7 +42,8 @@
<label class="checkbox" for="static-page"></label>
</td>
</tr>
</tbody></table>
</tbody>
</table>
</form>
<a class="delete" href="#">Delete This Post</a>
</div>

View File

@ -1,25 +1,43 @@
<style>
/*
Cosmetic changes to ghost styles, that help during development.
The contents should be solved properly or moved into the other assets.
*/
/* Put your CSS here */
/*
@keyframes domChanged { from { background: yellow; } }
@-webkit-keyframes domChanged { from { background: yellow; } }
.ember-view { animation: domChanged 1s; -webkit-animation: domChanged 1s; }
*/
.post-settings-menu {
display: none !important;
}
@font-face {
font-family: "Icons";
src: url("https://testblog111.ghost.io/ghost/fonts/icons.woff") format('woff');
}
/*
Cosmetic changes to ghost styles, that help during development.
The contents should be solved properly or moved into the other assets.
*/
.post-settings-menu {
display: none !important;
}
#entry-markdown, .entry-preview,
.CodeMirror.cm-s-default {
height: 500px !important;
}
#entry-markdown, .entry-preview,
.CodeMirror.cm-s-default {
height: 500px !important;
}
.editor input {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.editor .entry-title {
box-shadow: none !important;
background: none !important;
padding: 0 !important;
height: auto !important;
}
.editor input {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
</style>
<section class="entry-container">
<header>
<section class="box entry-title">
@ -33,7 +51,7 @@
<a class="markdown-help" href="#"><span class="hidden">What is Markdown?</span></a>
</header>
<section id="entry-markdown-content" class="entry-markdown-content">
{{code-mirror value=markdown scrollPosition=view.scrollPosition}}
{{-codemirror value=markdown scrollPosition=view.scrollPosition}}
</section>
</section>
@ -41,7 +59,7 @@
<header class="floatingheader">
<small>Preview <span class="entry-word-count js-entry-word-count">{{count-words markdown}} words</span></small>
</header>
{{mark-down markdown=markdown scrollPosition=view.scrollPosition}}
{{-markdown markdown=markdown scrollPosition=view.scrollPosition}}
</section>
</section>

View File

@ -14,9 +14,9 @@
<h3 class="entry-title">{{title}}</h3>
<section class="entry-meta">
<span class="status">
{{#if isDraft}}
<span class="draft">Draft</span>
{{/if}}
{{#if isDraft}}
<span class="draft">Draft</span>
{{/if}}
{{#if isPublished}}
<time datetime="{{unbound published_at}}" class="date published">
Published {{format-timeago published_at}}

View File

@ -1,7 +1,9 @@
import itemView from 'ghost/views/item-view';
export default itemView.extend({
var PostItemView = itemView.extend({
openEditor: function () {
this.get('controller').send('openEditor', this.get('post')); // send action to handle transition to editor route
}.on("doubleClick")
});
});
export default PostItemView;