mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Merge pull request #2357 from ErisDS/ember-with-proto
[Ember.js] merging prototype
This commit is contained in:
commit
106ee21cbf
43 changed files with 652 additions and 24 deletions
23
Gruntfile.js
23
Gruntfile.js
|
@ -450,6 +450,9 @@ var path = require('path'),
|
|||
// ### Config for grunt-contrib-clean
|
||||
// Clean up files as part of other tasks
|
||||
clean: {
|
||||
built: {
|
||||
src: ['core/built/**']
|
||||
},
|
||||
release: {
|
||||
src: ['<%= paths.releaseBuild %>/**']
|
||||
},
|
||||
|
@ -517,7 +520,7 @@ var path = require('path'),
|
|||
|
||||
'bower_components/lodash/dist/lodash.underscore.js',
|
||||
'bower_components/backbone/backbone.js',
|
||||
'bower_components/handlebars.js/dist/handlebars.runtime.js',
|
||||
'bower_components/handlebars/handlebars.runtime.js',
|
||||
'bower_components/moment/moment.js',
|
||||
'bower_components/jquery-file-upload/js/jquery.fileupload.js',
|
||||
'bower_components/codemirror/lib/codemirror.js',
|
||||
|
@ -568,9 +571,21 @@ var path = require('path'),
|
|||
'core/built/scripts/vendor-ember.js': [
|
||||
'core/client/assets/vendor/loader.js',
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
'bower_components/handlebars.js/dist/handlebars.js',
|
||||
'bower_components/handlebars/handlebars.js',
|
||||
'bower_components/ember/ember.js',
|
||||
'bower_components/ember-resolver/dist/ember-resolver.js'
|
||||
'bower_components/ember-resolver/dist/ember-resolver.js',
|
||||
'bower_components/ic-ajax/dist/globals/main.js',
|
||||
|
||||
'bower_components/codemirror/lib/codemirror.js',
|
||||
'bower_components/codemirror/addon/mode/overlay.js',
|
||||
'bower_components/codemirror/mode/markdown/markdown.js',
|
||||
'bower_components/codemirror/mode/gfm/gfm.js',
|
||||
'bower_components/showdown/src/showdown.js',
|
||||
'core/clientold/assets/lib/showdown/extensions/ghostdown.js',
|
||||
'core/shared/lib/showdown/extensions/typography.js',
|
||||
'core/shared/lib/showdown/extensions/github.js',
|
||||
|
||||
'bower_components/moment/moment.js'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -584,7 +599,7 @@ var path = require('path'),
|
|||
|
||||
'bower_components/lodash/dist/lodash.underscore.js',
|
||||
'bower_components/backbone/backbone.js',
|
||||
'bower_components/handlebars.js/dist/handlebars.runtime.js',
|
||||
'bower_components/handlebars/handlebars.runtime.js',
|
||||
'bower_components/moment/moment.js',
|
||||
'bower_components/jquery-file-upload/js/jquery.fileupload.js',
|
||||
'bower_components/codemirror/lib/codemirror.js',
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"ember-resolver": "git://github.com/stefanpenner/ember-jj-abrams-resolver.git#9805033c178e7f857f801359664adb599444b430",
|
||||
"fastclick": "1.0.0",
|
||||
"handlebars": "~1.1.2",
|
||||
"ic-ajax": "1.0.1",
|
||||
"iCheck": "1.0.1",
|
||||
"jquery": "1.11.0",
|
||||
"jquery-file-upload": "9.5.6",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/*global Ember */
|
||||
|
||||
import Resolver from 'ember/resolver';
|
||||
import initFixtures from 'ghost/fixtures/init';
|
||||
|
||||
var App = Ember.Application.extend({
|
||||
/**
|
||||
|
@ -11,8 +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();
|
||||
|
||||
export default App;
|
||||
|
|
44
core/client/components/-codemirror.js
Normal file
44
core/client/components/-codemirror.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* global CodeMirror*/
|
||||
|
||||
var onChangeHandler = function (cm) {
|
||||
cm.component.set('value', cm.getDoc().getValue());
|
||||
};
|
||||
|
||||
var onScrollHandler = function (cm) {
|
||||
var scrollInfo = cm.getScrollInfo(),
|
||||
percentage = scrollInfo.top / scrollInfo.height,
|
||||
component = cm.component;
|
||||
|
||||
// throttle scroll updates
|
||||
component.throttle = Ember.run.throttle(component, function () {
|
||||
this.set('scrollPosition', percentage);
|
||||
}, 50);
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
// on scroll update scrollPosition property
|
||||
this.codemirror.on('scroll', onScrollHandler);
|
||||
}.on('didInsertElement'),
|
||||
|
||||
removeThrottle: function () {
|
||||
Ember.run.cancel(this.throttle);
|
||||
}.on('willDestroyElement'),
|
||||
|
||||
removeCodemirrorHandlers: function () {
|
||||
// not sure if this is needed.
|
||||
this.codemirror.off('change', onChangeHandler);
|
||||
this.codemirror.off('scroll', onScrollHandler);
|
||||
}.on('willDestroyElement')
|
||||
});
|
||||
|
||||
export default Codemirror;
|
11
core/client/components/-markdown.js
Normal file
11
core/client/components/-markdown.js
Normal 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;
|
|
@ -1,5 +0,0 @@
|
|||
export default Ember.Component.extend({
|
||||
time: function () {
|
||||
return new Date();
|
||||
}.property()
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
export default Ember.Controller.extend({
|
||||
message: 'its a new beginning.'
|
||||
});
|
8
core/client/controllers/posts/post.js
Normal file
8
core/client/controllers/posts/post.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
var equal = Ember.computed.equal;
|
||||
|
||||
var PostController = Ember.ObjectController.extend({
|
||||
isPublished: equal('status', 'published'),
|
||||
isDraft: equal('status', 'draft')
|
||||
});
|
||||
|
||||
export default PostController;
|
32
core/client/fixtures/init.js
Normal file
32
core/client/fixtures/init.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*global ic */
|
||||
import postFixtures from 'ghost/fixtures/posts';
|
||||
|
||||
var post = function (id) {
|
||||
return {
|
||||
response: postFixtures.findBy('id', id),
|
||||
jqXHR: {},
|
||||
textStatus: 'success'
|
||||
};
|
||||
};
|
||||
|
||||
var posts = function () {
|
||||
return {
|
||||
response: {
|
||||
'posts': postFixtures,
|
||||
'page': 1,
|
||||
'limit': 15,
|
||||
'pages': 1,
|
||||
'total': 2
|
||||
},
|
||||
jqXHR: {},
|
||||
textStatus: 'success'
|
||||
};
|
||||
};
|
||||
|
||||
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;
|
143
core/client/fixtures/posts.js
Normal file
143
core/client/fixtures/posts.js
Normal file
|
@ -0,0 +1,143 @@
|
|||
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,
|
||||
"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\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><your blog URL>\/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><code><\/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,
|
||||
"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;
|
7
core/client/helpers/count-words.js
Normal file
7
core/client/helpers/count-words.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import count from 'ghost/utils/word-count';
|
||||
|
||||
var countWords = Ember.Handlebars.makeBoundHelper(function (markdown) {
|
||||
return count(markdown);
|
||||
});
|
||||
|
||||
export default countWords;
|
8
core/client/helpers/format-markdown.js
Normal file
8
core/client/helpers/format-markdown.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* global Showdown, Handlebars */
|
||||
var showdown = new Showdown.converter();
|
||||
|
||||
var formatMarkdown = Ember.Handlebars.makeBoundHelper(function (markdown) {
|
||||
return new Handlebars.SafeString(showdown.makeHtml(markdown));
|
||||
});
|
||||
|
||||
export default formatMarkdown;
|
9
core/client/helpers/format-timeago.js
Normal file
9
core/client/helpers/format-timeago.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* global moment */
|
||||
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;
|
27
core/client/mixins/style-body.js
Normal file
27
core/client/mixins/style-body.js
Normal 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;
|
5
core/client/models/post.js
Normal file
5
core/client/models/post.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
var PostModel = Ember.Object.extend({
|
||||
|
||||
});
|
||||
|
||||
export default PostModel;
|
|
@ -3,8 +3,17 @@
|
|||
// ensure we don't share routes between all Router instances
|
||||
var Router = Ember.Router.extend();
|
||||
|
||||
Router.reopen({
|
||||
//location: 'history', // use HTML5 History API instead of hash-tag based URLs
|
||||
rootURL: '/ghost/ember/' // admin interface lives under sub-directory /ghost
|
||||
});
|
||||
|
||||
Router.map(function () {
|
||||
'use strict';
|
||||
this.resource('posts', { path: '/' }, function () {
|
||||
this.route('post', { path: ':post_id' });
|
||||
});
|
||||
this.resource('editor', { path: '/editor/:post_id' });
|
||||
this.route('new', { path: '/editor' });
|
||||
});
|
||||
|
||||
export default Router;
|
||||
|
|
12
core/client/routes/editor.js
Normal file
12
core/client/routes/editor.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import ajax from 'ghost/utils/ajax';
|
||||
import styleBody from 'ghost/mixins/style-body';
|
||||
|
||||
var EditorRoute = Ember.Route.extend(styleBody, {
|
||||
classNames: ['editor'],
|
||||
|
||||
model: function (params) {
|
||||
return ajax('/ghost/api/v0.1/posts/' + params.post_id);
|
||||
}
|
||||
});
|
||||
|
||||
export default EditorRoute;
|
20
core/client/routes/posts.js
Normal file
20
core/client/routes/posts.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import ajax from 'ghost/utils/ajax';
|
||||
import styleBody from 'ghost/mixins/style-body';
|
||||
|
||||
var PostsRoute = Ember.Route.extend(styleBody, {
|
||||
classNames: ['manage'],
|
||||
|
||||
model: function () {
|
||||
return ajax('/ghost/api/v0.1/posts').then(function (response) {
|
||||
return response.posts;
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
openEditor: function (post) {
|
||||
this.transitionTo('editor', post);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default PostsRoute;
|
12
core/client/routes/posts/index.js
Normal file
12
core/client/routes/posts/index.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
var PostsIndexRoute = Ember.Route.extend({
|
||||
// redirect to first post subroute
|
||||
redirect: function () {
|
||||
var firstPost = (this.modelFor('posts') || []).get('firstObject');
|
||||
|
||||
if (firstPost) {
|
||||
this.transitionTo('posts.post', firstPost);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default PostsIndexRoute;
|
8
core/client/routes/posts/post.js
Normal file
8
core/client/routes/posts/post.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*global ajax */
|
||||
var PostsPostRoute = Ember.Route.extend({
|
||||
model: function (params) {
|
||||
return ajax('/ghost/api/v0.1/posts/' + params.post_id);
|
||||
}
|
||||
});
|
||||
|
||||
export default PostsPostRoute;
|
51
core/client/templates/-floating-header.hbs
Normal file
51
core/client/templates/-floating-header.hbs
Normal file
|
@ -0,0 +1,51 @@
|
|||
<header class="floatingheader">
|
||||
<button class="button-back" href="#">Back</button>
|
||||
<a class="unfeatured" href="#" title="Feature this post">
|
||||
<span class="hidden">Star</span>
|
||||
</a>
|
||||
<small>
|
||||
<span class="status">Written</span>
|
||||
<span class="normal">by</span>
|
||||
<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}}
|
||||
<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">
|
||||
<td class="post-setting-label">
|
||||
<label for="url">URL</label>
|
||||
</td>
|
||||
<td class="post-setting-field">
|
||||
<input id="url" class="post-setting-slug" type="text" value="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="post-setting">
|
||||
<td class="post-setting-label">
|
||||
<label for="pub-date">Pub Date</label>
|
||||
</td>
|
||||
<td class="post-setting-field">
|
||||
<input id="pub-date" class="post-setting-date" type="text" value="" placeholder="17 Feb 14 @ 02:35"><!--<span class="post-setting-calendar"></span>-->
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="post-setting">
|
||||
<td class="post-setting-label">
|
||||
<span class="label">Static Page</span>
|
||||
</td>
|
||||
<td class="post-setting-item">
|
||||
<input id="static-page" class="post-setting-static-page" type="checkbox" value="">
|
||||
<label class="checkbox" for="static-page"></label>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
<a class="delete" href="#">Delete This Post</a>
|
||||
</div>
|
||||
</section>
|
||||
</header>
|
8
core/client/templates/-navbar.hbs
Normal file
8
core/client/templates/-navbar.hbs
Normal file
|
@ -0,0 +1,8 @@
|
|||
<header id="global-header" class="navbar">
|
||||
<nav id="global-nav" role="navigation">
|
||||
<ul id="main-menu" >
|
||||
<li class="content">{{#link-to "posts"}}Content{{/link-to}}</li>
|
||||
<li class="editor">{{#link-to "new"}}New post{{/link-to}}</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
58
core/client/templates/-publish-bar.hbs
Normal file
58
core/client/templates/-publish-bar.hbs
Normal file
|
@ -0,0 +1,58 @@
|
|||
<footer id="publish-bar">
|
||||
<nav>
|
||||
<section id="entry-tags" href="#" class="left">
|
||||
<label class="tag-label" for="tags" title="Tags"><span class="hidden">Tags</span></label>
|
||||
<div class="tags">Nothing implemented</div>
|
||||
<input type="hidden" class="tags-holder" id="tags-holder">
|
||||
<input class="tag-input" id="tags" type="text" data-input-behaviour="tag" />
|
||||
<ul class="suggestions overlay"></ul>
|
||||
</section>
|
||||
<div class="right">
|
||||
|
||||
<section id="entry-controls">
|
||||
<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-right overlay">
|
||||
<form>
|
||||
<table class="plain">
|
||||
<tr class="post-setting">
|
||||
<td class="post-setting-label">
|
||||
<label for="url">URL</label>
|
||||
</td>
|
||||
<td class="post-setting-field">
|
||||
<input id="url" class="post-setting-slug" type="text" placeholder="" value="" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="post-setting">
|
||||
<td class="post-setting-label">
|
||||
<label for="pub-date">Pub Date</label>
|
||||
</td>
|
||||
<td class="post-setting-field">
|
||||
<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">
|
||||
<td class="post-setting-label">
|
||||
<span class="label">Static Page</span>
|
||||
</td>
|
||||
<td class="post-setting-item">
|
||||
<input id="static-page" class="post-setting-static-page" type="checkbox" value="">
|
||||
<label class="checkbox" for="static-page"></label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<a class="delete" href="#">Delete This Post</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="entry-actions" class="js-publish-splitbutton splitbutton-save">
|
||||
<button type="button" class="js-publish-button button-save"></button>
|
||||
<a class="options up" data-toggle="ul" href="#" title="Post Settings"><span class="hidden">Post Settings</span></a>
|
||||
<ul class="editor-options overlay" style="display:none">
|
||||
<li data-set-status="published"><a href="#"></a></li>
|
||||
<li data-set-status="draft"><a href="#"></a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</nav>
|
||||
</footer>
|
8
core/client/templates/application.hbs
Executable file → Normal file
8
core/client/templates/application.hbs
Executable file → Normal file
|
@ -1,5 +1,5 @@
|
|||
<h2 id='title'>Welcome to Ghost on Ember.js</h2>
|
||||
{{partial "navbar"}}
|
||||
|
||||
{{message}}
|
||||
|
||||
{{outlet}}
|
||||
<main role="main" id="main">
|
||||
{{outlet}}
|
||||
</main>
|
||||
|
|
5
core/client/templates/components/-markdown.hbs
Normal file
5
core/client/templates/components/-markdown.hbs
Normal file
|
@ -0,0 +1,5 @@
|
|||
<section class="entry-preview-content">
|
||||
<div class="rendered-markdown">
|
||||
{{format-markdown markdown}}
|
||||
</div>
|
||||
</section>
|
|
@ -1 +0,0 @@
|
|||
Time is now {{time}}
|
66
core/client/templates/editor.hbs
Normal file
66
core/client/templates/editor.hbs
Normal file
|
@ -0,0 +1,66 @@
|
|||
<style>
|
||||
/* Put your CSS here */
|
||||
/*
|
||||
@keyframes domChanged { from { background: yellow; } }
|
||||
@-webkit-keyframes domChanged { from { background: yellow; } }
|
||||
.ember-view { animation: domChanged 1s; -webkit-animation: domChanged 1s; }
|
||||
*/
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
.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">
|
||||
{{input type="text" id="entry-title" placeholder="Your Post Title" value=title tabindex="1"}}
|
||||
</section>
|
||||
</header>
|
||||
|
||||
<section class="entry-markdown active">
|
||||
<header class="floatingheader">
|
||||
<small>Markdown</small>
|
||||
<a class="markdown-help" href="#"><span class="hidden">What is Markdown?</span></a>
|
||||
</header>
|
||||
<section id="entry-markdown-content" class="entry-markdown-content">
|
||||
{{-codemirror value=markdown scrollPosition=view.scrollPosition}}
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="entry-preview">
|
||||
<header class="floatingheader">
|
||||
<small>Preview <span class="entry-word-count js-entry-word-count">{{count-words markdown}} words</span></small>
|
||||
</header>
|
||||
{{-markdown markdown=markdown scrollPosition=view.scrollPosition}}
|
||||
</section>
|
||||
</section>
|
||||
|
||||
{{partial 'publish-bar'}}
|
5
core/client/templates/error.hbs
Normal file
5
core/client/templates/error.hbs
Normal file
|
@ -0,0 +1,5 @@
|
|||
<h1>Sorry, Something went wrong</h1>
|
||||
{{message}}
|
||||
<pre>
|
||||
{{stack}}
|
||||
</pre>
|
|
@ -1,3 +0,0 @@
|
|||
<em>This is the index route</em>
|
||||
|
||||
{{time-now}}
|
1
core/client/templates/loading.hbs
Normal file
1
core/client/templates/loading.hbs
Normal file
|
@ -0,0 +1 @@
|
|||
<h1>Loading...</h1>
|
1
core/client/templates/new.hbs
Normal file
1
core/client/templates/new.hbs
Normal file
|
@ -0,0 +1 @@
|
|||
TODO
|
36
core/client/templates/posts.hbs
Normal file
36
core/client/templates/posts.hbs
Normal file
|
@ -0,0 +1,36 @@
|
|||
<section class="content-view-container">
|
||||
<section class="content-list js-content-list">
|
||||
<header class="floatingheader">
|
||||
<section class="content-filter">
|
||||
<small>All Posts</small>
|
||||
</section>
|
||||
{{#link-to "new" class="button button-add" title="New Post"}}New Post{{/link-to}}
|
||||
</header>
|
||||
<section class="content-list-content">
|
||||
<ol class="posts-list">
|
||||
{{#each itemController="posts/post"}}
|
||||
{{#view "post-item-view" tagName="li" post=this}} <!-- needed because of "active" class on li item -->
|
||||
{{#link-to 'posts.post' this class="permalink" title="Edit this post"}}
|
||||
<h3 class="entry-title">{{title}}</h3>
|
||||
<section class="entry-meta">
|
||||
<span class="status">
|
||||
{{#if isDraft}}
|
||||
<span class="draft">Draft</span>
|
||||
{{/if}}
|
||||
{{#if isPublished}}
|
||||
<time datetime="{{unbound published_at}}" class="date published">
|
||||
Published {{format-timeago published_at}}
|
||||
</time>
|
||||
{{/if}}
|
||||
</span>
|
||||
</section>
|
||||
{{/link-to}}
|
||||
{{/view}}
|
||||
{{/each}}
|
||||
</ol>
|
||||
</section>
|
||||
</section>
|
||||
<section class="content-preview js-content-preview">
|
||||
{{outlet}}
|
||||
</section>
|
||||
</section>
|
8
core/client/templates/posts/post.hbs
Normal file
8
core/client/templates/posts/post.hbs
Normal file
|
@ -0,0 +1,8 @@
|
|||
{{partial "floating-header"}}
|
||||
|
||||
<section class="content-preview-content">
|
||||
<div class="wrapper">
|
||||
<h1>{{title}}</h1>
|
||||
{{format-markdown markdown}}
|
||||
</div>
|
||||
</section>
|
4
core/client/utils/ajax.js
Normal file
4
core/client/utils/ajax.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
/* global ic */
|
||||
export default window.ajax = function () {
|
||||
return ic.ajax.request.apply(null, arguments);
|
||||
};
|
6
core/client/utils/word-count.js
Normal file
6
core/client/utils/word-count.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default function (s) {
|
||||
s = s.replace(/(^\s*)|(\s*$)/gi, ""); // exclude start and end white-space
|
||||
s = s.replace(/[ ]{2,}/gi, " "); // 2 or more space to 1
|
||||
s = s.replace(/\n /, "\n"); // exclude newline with a start spacing
|
||||
return s.split(' ').length;
|
||||
}
|
3
core/client/views/editor.js
Normal file
3
core/client/views/editor.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export default Ember.View.extend({
|
||||
scrollPosition: 0 // percentage of scroll position
|
||||
});
|
7
core/client/views/item-view.js
Normal file
7
core/client/views/item-view.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
export default Ember.View.extend({
|
||||
classNameBindings: ['active'],
|
||||
|
||||
active: function () {
|
||||
return this.get('childViews.firstObject.active');
|
||||
}.property('childViews.firstObject.active')
|
||||
});
|
9
core/client/views/post-item-view.js
Normal file
9
core/client/views/post-item-view.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import itemView from 'ghost/views/item-view';
|
||||
|
||||
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;
|
Loading…
Add table
Reference in a new issue