blogelator 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +86 -0
- data/Rakefile +29 -0
- data/app/assets/images/blogelator/blogelator-logo.svg +15 -0
- data/app/assets/javascripts/blogelator/admin.js +19 -0
- data/app/assets/javascripts/blogelator/application.js +2 -0
- data/app/assets/javascripts/blogelator/components/markdown_editor_component.js +187 -0
- data/app/assets/javascripts/blogelator/components/save_button_component.js +76 -0
- data/app/assets/javascripts/blogelator/config/marked.js +10 -0
- data/app/assets/javascripts/blogelator/config/router.js +9 -0
- data/app/assets/javascripts/blogelator/config/routes.js +13 -0
- data/app/assets/javascripts/blogelator/config/serializer.js +10 -0
- data/app/assets/javascripts/blogelator/config/store.js +10 -0
- data/app/assets/javascripts/blogelator/controllers/application_controller.js +11 -0
- data/app/assets/javascripts/blogelator/controllers/posts/posts_edit_controller.js +97 -0
- data/app/assets/javascripts/blogelator/controllers/posts/posts_index_controller.js +9 -0
- data/app/assets/javascripts/blogelator/controllers/posts/posts_new_controller.js +6 -0
- data/app/assets/javascripts/blogelator/controllers/posts/posts_show_controller.js +37 -0
- data/app/assets/javascripts/blogelator/models/post.js +34 -0
- data/app/assets/javascripts/blogelator/routes/index_route.js +10 -0
- data/app/assets/javascripts/blogelator/routes/posts_edit_route.js +36 -0
- data/app/assets/javascripts/blogelator/routes/posts_index_route.js +20 -0
- data/app/assets/javascripts/blogelator/routes/posts_new_route.js +53 -0
- data/app/assets/javascripts/blogelator/routes/posts_route.js +10 -0
- data/app/assets/javascripts/blogelator/routes/posts_show_route.js +14 -0
- data/app/assets/javascripts/blogelator/templates/application.handlebars +23 -0
- data/app/assets/javascripts/blogelator/templates/components/markdown-editor.handlebars +8 -0
- data/app/assets/javascripts/blogelator/templates/components/save-button.handlebars +8 -0
- data/app/assets/javascripts/blogelator/templates/posts/_footer.handlebars +0 -0
- data/app/assets/javascripts/blogelator/templates/posts/_form.handlebars +6 -0
- data/app/assets/javascripts/blogelator/templates/posts/_form_action_bar.handlebars +22 -0
- data/app/assets/javascripts/blogelator/templates/posts/_show_action_bar.handlebars +20 -0
- data/app/assets/javascripts/blogelator/templates/posts/edit.handlebars +1 -0
- data/app/assets/javascripts/blogelator/templates/posts/index.handlebars +30 -0
- data/app/assets/javascripts/blogelator/templates/posts/new.handlebars +1 -0
- data/app/assets/javascripts/blogelator/templates/posts/show.handlebars +22 -0
- data/app/assets/stylesheets/blogelator/admin/all.scss +7 -0
- data/app/assets/stylesheets/blogelator/admin/components/markdown_editor.scss +142 -0
- data/app/assets/stylesheets/blogelator/admin/components/save_button.scss +121 -0
- data/app/assets/stylesheets/blogelator/admin/layout.scss +94 -0
- data/app/assets/stylesheets/blogelator/admin/posts/_form.scss +12 -0
- data/app/assets/stylesheets/blogelator/admin/posts/_form_action_bar.scss +84 -0
- data/app/assets/stylesheets/blogelator/admin/posts/_posts_list.scss +43 -0
- data/app/assets/stylesheets/blogelator/admin/posts/edit.scss +7 -0
- data/app/assets/stylesheets/blogelator/admin/posts/index.scss +14 -0
- data/app/assets/stylesheets/blogelator/admin/posts/new.scss +16 -0
- data/app/assets/stylesheets/blogelator/admin/posts/show.scss +17 -0
- data/app/assets/stylesheets/blogelator/application/all.scss +19 -0
- data/app/assets/stylesheets/blogelator/application/layout.scss +49 -0
- data/app/assets/stylesheets/blogelator/application/posts/index.scss +50 -0
- data/app/assets/stylesheets/blogelator/application/posts/show.scss +64 -0
- data/app/assets/stylesheets/blogelator/mixins/blogelator_button.scss +57 -0
- data/app/assets/stylesheets/blogelator/mixins/blogelator_logo.scss +12 -0
- data/app/assets/stylesheets/blogelator/shared/post.scss +161 -0
- data/app/assets/stylesheets/blogelator/shared/typography/code_highlighting.scss +111 -0
- data/app/assets/stylesheets/blogelator/shared/typography/forms.scss +94 -0
- data/app/assets/stylesheets/blogelator/shared/typography/headings.scss +22 -0
- data/app/assets/stylesheets/blogelator/shared/typography/lists.scss +25 -0
- data/app/controllers/blogelator/admin/application_controller.rb +15 -0
- data/app/controllers/blogelator/admin/images_controller.rb +40 -0
- data/app/controllers/blogelator/admin/posts_controller.rb +67 -0
- data/app/controllers/blogelator/application_controller.rb +5 -0
- data/app/controllers/blogelator/posts_controller.rb +37 -0
- data/app/controllers/concerns/blogelator/admin/auth.rb +23 -0
- data/app/helpers/blogelator/admin/posts_helper.rb +7 -0
- data/app/helpers/blogelator/posts_helper.rb +28 -0
- data/app/models/blogelator/ability.rb +11 -0
- data/app/models/blogelator/html_renderer.rb +10 -0
- data/app/models/blogelator/post.rb +63 -0
- data/app/models/blogelator/tag.rb +5 -0
- data/app/serializers/blogelator/post_serializer.rb +6 -0
- data/app/views/blogelator/admin/posts/index.html.erb +0 -0
- data/app/views/blogelator/posts/_post.html.erb +14 -0
- data/app/views/blogelator/posts/index.html.erb +39 -0
- data/app/views/blogelator/posts/show.html.erb +27 -0
- data/app/views/layouts/blogelator/_footer.html.erb +3 -0
- data/app/views/layouts/blogelator/_head.html.erb +7 -0
- data/app/views/layouts/blogelator/_header.html.erb +7 -0
- data/app/views/layouts/blogelator/admin.html.erb +14 -0
- data/app/views/layouts/blogelator/application.html.erb +14 -0
- data/config/jshint.json +43 -0
- data/config/routes.rb +15 -0
- data/db/migrate/20140221192000_create_blogelator_posts.rb +12 -0
- data/db/migrate/20140221204230_add_slug_and_change_user_to_author.rb +6 -0
- data/db/migrate/20140221212026_create_blogelator_tags.rb +10 -0
- data/db/migrate/20140224024607_change_posts_properties_to_have_defaults.rb +14 -0
- data/db/migrate/20140224175024_add_slugs_to_existing_posts.rb +16 -0
- data/db/migrate/20140224192058_add_published_at_to_posts.rb +13 -0
- data/db/migrate/20140303015004_add_summary_to_posts.rb +9 -0
- data/lib/assets/stylesheets/blogelator/_variables_sample.scss +38 -0
- data/lib/blogelator.rb +27 -0
- data/lib/blogelator/engine.rb +35 -0
- data/lib/blogelator/version.rb +3 -0
- data/lib/generators/blogelator/install_generator.rb +94 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +1 -0
- data/spec/dummy/app/assets/javascripts/features/user_visits_admin_page_spec.js +12 -0
- data/spec/dummy/app/assets/javascripts/features/user_visits_post_page_spec.js +12 -0
- data/spec/dummy/app/assets/javascripts/fixtures/post.js +17 -0
- data/spec/dummy/app/assets/javascripts/test_helper.js +12 -0
- data/spec/dummy/app/assets/stylesheets/application.css +12 -0
- data/spec/dummy/app/assets/stylesheets/blogelator/_variables.scss +38 -0
- data/spec/dummy/app/assets/stylesheets/blogelator/admin.css.scss +4 -0
- data/spec/dummy/app/assets/stylesheets/blogelator/application.css.scss +4 -0
- data/spec/dummy/app/assets/stylesheets/test_helper.css +21 -0
- data/spec/dummy/app/controllers/application_controller.rb +9 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/blogelator/ability.rb +9 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/q_unit/rails/test/index.html.erb +17 -0
- data/spec/dummy/app/views/qunit/rails/test/index.html.erb +17 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +24 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +32 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/blogelator.rb +6 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20140221215439_create_blogelator_posts.blogelator.rb +13 -0
- data/spec/dummy/db/migrate/20140221215440_add_slug_and_change_user_to_author.blogelator.rb +7 -0
- data/spec/dummy/db/migrate/20140224024931_create_blogelator_tags.blogelator.rb +11 -0
- data/spec/dummy/db/migrate/20140224025218_change_posts_properties_to_have_defaults.blogelator.rb +15 -0
- data/spec/dummy/db/migrate/20140224205646_add_slugs_to_existing_posts.blogelator.rb +17 -0
- data/spec/dummy/db/migrate/20140224205647_add_published_at_to_posts.blogelator.rb +14 -0
- data/spec/dummy/db/migrate/20140303015133_add_summary_to_posts.blogelator.rb +6 -0
- data/spec/dummy/db/production.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +37 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +50393 -0
- data/spec/dummy/log/production.log +76 -0
- data/spec/dummy/log/test.log +11750 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/index.html.erb +14 -0
- data/spec/dummy/tmp/ember-rails/ember-data.js +11132 -0
- data/spec/dummy/tmp/ember-rails/ember.js +42882 -0
- data/spec/factories/post.rb +11 -0
- data/spec/features/user_visits_blog_post_spec.rb +44 -0
- data/spec/features/user_visits_blog_spec.rb +85 -0
- data/spec/models/blogelator/post_spec.rb +95 -0
- data/spec/qunit_runner.js +148 -0
- data/spec/spec_helper.rb +34 -0
- metadata +764 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.Router.map(function() {
|
5
|
+
this.route('index', { path: '/' });
|
6
|
+
this.resource('posts', { path: '/posts' }, function() {
|
7
|
+
this.route('edit', { path: '/:post_id/edit' });
|
8
|
+
this.route('new');
|
9
|
+
this.route('show', { path: '/:post_id' });
|
10
|
+
});
|
11
|
+
});
|
12
|
+
|
13
|
+
})();
|
@@ -0,0 +1,11 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.ApplicationController = Ember.ObjectController.extend({
|
5
|
+
currentPathDidChange: function() {
|
6
|
+
var bodyClass = 'ember-application blogelator admin ' + this.get('currentPath').split('.').join(' ');
|
7
|
+
$('body').attr('class', bodyClass);
|
8
|
+
}.observes('currentPath')
|
9
|
+
});
|
10
|
+
|
11
|
+
})();
|
@@ -0,0 +1,97 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.PostsEditController = Ember.ObjectController.extend({
|
5
|
+
needs: ['posts'],
|
6
|
+
secondsPassed: 0,
|
7
|
+
|
8
|
+
actions: {
|
9
|
+
destroy: function(defer) {
|
10
|
+
var post = this.get('content'),
|
11
|
+
controller = this.get('controllers.posts');
|
12
|
+
|
13
|
+
if (Ember.isNone(defer)) {
|
14
|
+
post.destroyRecord();
|
15
|
+
return post;
|
16
|
+
}
|
17
|
+
|
18
|
+
post.destroyRecord().then(function() {
|
19
|
+
defer.resolve();
|
20
|
+
Ember.run.later(function() {
|
21
|
+
controller.transitionToRoute('posts.index');
|
22
|
+
}, 900);
|
23
|
+
}, function() {
|
24
|
+
defer.reject();
|
25
|
+
});
|
26
|
+
|
27
|
+
return post;
|
28
|
+
},
|
29
|
+
|
30
|
+
save: function(defer) {
|
31
|
+
var post = this.get('content');
|
32
|
+
|
33
|
+
if (Ember.isNone(defer)) {
|
34
|
+
post.save();
|
35
|
+
return post;
|
36
|
+
}
|
37
|
+
|
38
|
+
if (!post.get('isDirty')) {
|
39
|
+
defer.resolve();
|
40
|
+
} else {
|
41
|
+
post.save().then(function() {
|
42
|
+
defer.resolve();
|
43
|
+
}, function() {
|
44
|
+
defer.reject();
|
45
|
+
});
|
46
|
+
}
|
47
|
+
|
48
|
+
return post;
|
49
|
+
},
|
50
|
+
|
51
|
+
togglePublished: function(defer) {
|
52
|
+
var post = this.get('content');
|
53
|
+
|
54
|
+
if (Ember.isNone(post.get('publishedAt'))) {
|
55
|
+
post.set('publishedAt', new Date());
|
56
|
+
} else {
|
57
|
+
post.set('publishedAt', null);
|
58
|
+
}
|
59
|
+
|
60
|
+
if (Ember.isNone(defer)) {
|
61
|
+
post.save();
|
62
|
+
return post;
|
63
|
+
}
|
64
|
+
|
65
|
+
if (!post.get('isDirty')) {
|
66
|
+
defer.resolve();
|
67
|
+
} else {
|
68
|
+
post.save().then(function() {
|
69
|
+
defer.resolve();
|
70
|
+
}, function() {
|
71
|
+
defer.reject();
|
72
|
+
});
|
73
|
+
}
|
74
|
+
|
75
|
+
return post;
|
76
|
+
}
|
77
|
+
},
|
78
|
+
|
79
|
+
init: function() {
|
80
|
+
this._super();
|
81
|
+
this.updateSecondsPassed();
|
82
|
+
},
|
83
|
+
|
84
|
+
isClean: function() {
|
85
|
+
return !this.get('isDirty');
|
86
|
+
}.property('isDirty'),
|
87
|
+
|
88
|
+
updateSecondsPassed: function() {
|
89
|
+
var self = this;
|
90
|
+
this.incrementProperty('secondsPassed', 1);
|
91
|
+
Ember.run.later(function() {
|
92
|
+
self.updateSecondsPassed();
|
93
|
+
}, 1000);
|
94
|
+
}
|
95
|
+
});
|
96
|
+
|
97
|
+
})();
|
@@ -0,0 +1,37 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.PostsShowController = Ember.ObjectController.extend({
|
5
|
+
needs: ['posts'],
|
6
|
+
|
7
|
+
actions: {
|
8
|
+
togglePublished: function(defer) {
|
9
|
+
var post = this.get('content');
|
10
|
+
|
11
|
+
if (Ember.isNone(post.get('publishedAt'))) {
|
12
|
+
post.set('publishedAt', new Date());
|
13
|
+
} else {
|
14
|
+
post.set('publishedAt', null);
|
15
|
+
}
|
16
|
+
|
17
|
+
if (Ember.isNone(defer)) {
|
18
|
+
post.save();
|
19
|
+
return post;
|
20
|
+
}
|
21
|
+
|
22
|
+
if (!post.get('isDirty')) {
|
23
|
+
defer.resolve();
|
24
|
+
} else {
|
25
|
+
post.save().then(function() {
|
26
|
+
defer.resolve();
|
27
|
+
}, function() {
|
28
|
+
defer.reject();
|
29
|
+
});
|
30
|
+
}
|
31
|
+
|
32
|
+
return post;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
});
|
36
|
+
|
37
|
+
})();
|
@@ -0,0 +1,34 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.Post = DS.Model.extend({
|
5
|
+
bodyHtml: DS.attr('string', { defaultValue: '' }),
|
6
|
+
bodyMarkdown: DS.attr('string', { defaultValue: '' }),
|
7
|
+
createdAt: DS.attr('date'),
|
8
|
+
publishedAt: DS.attr('date'),
|
9
|
+
summary: DS.attr('string'),
|
10
|
+
title: DS.attr('string'),
|
11
|
+
updatedAt: DS.attr('date'),
|
12
|
+
|
13
|
+
publishedAtFormatted: function() {
|
14
|
+
var publishedAt = this.get('publishedAt');
|
15
|
+
|
16
|
+
if (Ember.isNone(publishedAt)) {
|
17
|
+
return "Unpublished";
|
18
|
+
} else {
|
19
|
+
return moment(publishedAt).format('MMMM D, YYYY');
|
20
|
+
}
|
21
|
+
}.property('publishedAt'),
|
22
|
+
|
23
|
+
updatedAtFormatted: function() {
|
24
|
+
var updatedAt = this.get('updatedAt');
|
25
|
+
|
26
|
+
if (Ember.isNone(updatedAt)) {
|
27
|
+
return "Never";
|
28
|
+
} else {
|
29
|
+
return moment(updatedAt).fromNow();
|
30
|
+
}
|
31
|
+
}.property('secondsPassed', 'updatedAt')
|
32
|
+
});
|
33
|
+
|
34
|
+
})();
|
@@ -0,0 +1,36 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.PostsEditRoute = Ember.Route.extend({
|
5
|
+
actions: {
|
6
|
+
willTransition: function(transition) {
|
7
|
+
var record = this.get('controller.content');
|
8
|
+
|
9
|
+
// Confirm transition if there are unsaved changes
|
10
|
+
if (record.get('isDirty')) {
|
11
|
+
if (confirm("Are you sure you want to lose unsaved changes?")) {
|
12
|
+
record.rollback();
|
13
|
+
return true;
|
14
|
+
} else {
|
15
|
+
transition.abort();
|
16
|
+
}
|
17
|
+
} else {
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
},
|
22
|
+
|
23
|
+
model: function(params) {
|
24
|
+
return this.store.find('post', params.post_id);
|
25
|
+
},
|
26
|
+
|
27
|
+
renderTemplate: function() {
|
28
|
+
this.render();
|
29
|
+
this.render('posts/_form_action_bar', {
|
30
|
+
into: 'application',
|
31
|
+
outlet: 'footer'
|
32
|
+
});
|
33
|
+
}
|
34
|
+
});
|
35
|
+
|
36
|
+
})();
|
@@ -0,0 +1,20 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.PostsIndexRoute = Ember.Route.extend({
|
5
|
+
afterModel: function(posts) {
|
6
|
+
if (posts.get('length') > 0) {
|
7
|
+
this.transitionTo('posts.show', posts.objectAt(0));
|
8
|
+
}
|
9
|
+
},
|
10
|
+
|
11
|
+
renderTemplate: function() {
|
12
|
+
this.render();
|
13
|
+
this.render('posts/_footer', {
|
14
|
+
into: 'application',
|
15
|
+
outlet: 'footer'
|
16
|
+
});
|
17
|
+
}
|
18
|
+
});
|
19
|
+
|
20
|
+
})();
|
@@ -0,0 +1,53 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
App.PostsNewRoute = Ember.Route.extend({
|
5
|
+
actions: {
|
6
|
+
willTransition: function(transition) {
|
7
|
+
var record = this.get('controller.content');
|
8
|
+
|
9
|
+
// Allow transition if nothing is entered
|
10
|
+
if (Ember.isEmpty(record.get('title')) &&
|
11
|
+
Ember.isEmpty(record.get('bodyMarkdown'))
|
12
|
+
) {
|
13
|
+
record.destroyRecord();
|
14
|
+
return true;
|
15
|
+
}
|
16
|
+
|
17
|
+
// Confirm transition if there are unsaved changes
|
18
|
+
if (record.get('isNew')) {
|
19
|
+
if (confirm("Are you sure you want to lose unsaved changes?")) {
|
20
|
+
record.destroyRecord();
|
21
|
+
return true;
|
22
|
+
} else {
|
23
|
+
transition.abort();
|
24
|
+
}
|
25
|
+
} else {
|
26
|
+
if (record.get('isDirty')) {
|
27
|
+
if (confirm("Are you sure you want to lose unsaved changes?")) {
|
28
|
+
record.rollback();
|
29
|
+
return true;
|
30
|
+
} else {
|
31
|
+
transition.abort();
|
32
|
+
}
|
33
|
+
} else {
|
34
|
+
return true;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
},
|
39
|
+
|
40
|
+
model: function() {
|
41
|
+
return this.store.createRecord('post');
|
42
|
+
},
|
43
|
+
|
44
|
+
renderTemplate: function() {
|
45
|
+
this.render();
|
46
|
+
this.render('posts/_form_action_bar', {
|
47
|
+
into: 'application',
|
48
|
+
outlet: 'footer'
|
49
|
+
});
|
50
|
+
}
|
51
|
+
});
|
52
|
+
|
53
|
+
})();
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<header>
|
2
|
+
<ul>
|
3
|
+
<li>
|
4
|
+
<a {{bind-attr href="App.blogelatorPath"}}>Blog</a>
|
5
|
+
</li>
|
6
|
+
<li>
|
7
|
+
{{#link-to "posts" class="posts-index-link"}}
|
8
|
+
Content
|
9
|
+
{{/link-to}}
|
10
|
+
</li>
|
11
|
+
<li>
|
12
|
+
{{#link-to "posts.new"}}
|
13
|
+
New Post
|
14
|
+
{{/link-to}}
|
15
|
+
</li>
|
16
|
+
</ul>
|
17
|
+
</header>
|
18
|
+
<main>
|
19
|
+
{{outlet}}
|
20
|
+
</main>
|
21
|
+
<footer>
|
22
|
+
{{outlet "footer"}}
|
23
|
+
</footer>
|