rails_blog_engine 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/BOOTSTRAP-LICENSE.txt +13 -0
- data/MIT-LICENSE +20 -0
- data/PYGMENTS-LICENSE.txt +28 -0
- data/RAILS-LICENSE.txt +22 -0
- data/README.md +165 -0
- data/Rakefile +79 -0
- data/app/assets/javascripts/rails_blog_engine/comments.js +2 -0
- data/app/assets/javascripts/rails_blog_engine/posts.js +3 -0
- data/app/assets/javascripts/rails_blog_engine.js +3 -0
- data/app/assets/stylesheets/rails_blog_engine/bootstrap_extracts.css.scss +252 -0
- data/app/assets/stylesheets/rails_blog_engine/code.css.scss +71 -0
- data/app/assets/stylesheets/rails_blog_engine/comments.css.scss +29 -0
- data/app/assets/stylesheets/rails_blog_engine/posts.css.scss +46 -0
- data/app/assets/stylesheets/rails_blog_engine/simple_form.css.scss +70 -0
- data/app/assets/stylesheets/rails_blog_engine.css +6 -0
- data/app/controllers/rails_blog_engine/application_controller.rb +26 -0
- data/app/controllers/rails_blog_engine/comments_controller.rb +47 -0
- data/app/controllers/rails_blog_engine/posts_controller.rb +67 -0
- data/app/helpers/rails_blog_engine/application_helper.rb +52 -0
- data/app/helpers/rails_blog_engine/comments_helper.rb +4 -0
- data/app/helpers/rails_blog_engine/posts_helper.rb +13 -0
- data/app/models/rails_blog_engine/comment.rb +74 -0
- data/app/models/rails_blog_engine/post.rb +73 -0
- data/app/views/rails_blog_engine/comments/_comment.html.haml +10 -0
- data/app/views/rails_blog_engine/comments/_form.html.haml +6 -0
- data/app/views/rails_blog_engine/comments/_tools.html.haml +10 -0
- data/app/views/rails_blog_engine/comments/new.html.haml +6 -0
- data/app/views/rails_blog_engine/posts/_comments_section.html.haml +11 -0
- data/app/views/rails_blog_engine/posts/_form.html.haml +7 -0
- data/app/views/rails_blog_engine/posts/_post.html.haml +20 -0
- data/app/views/rails_blog_engine/posts/_tools.html.haml +2 -0
- data/app/views/rails_blog_engine/posts/edit.html.haml +5 -0
- data/app/views/rails_blog_engine/posts/index.atom.builder +14 -0
- data/app/views/rails_blog_engine/posts/index.html.haml +15 -0
- data/app/views/rails_blog_engine/posts/new.html.haml +5 -0
- data/app/views/rails_blog_engine/posts/show.html.haml +8 -0
- data/config/locales/rails_blog_engine.en.yml +15 -0
- data/config/locales/simple_form.en.yml +24 -0
- data/config/routes.rb +24 -0
- data/db/migrate/20110912153527_create_rails_blog_engine_posts.rb +10 -0
- data/db/migrate/20110913190319_add_fields_to_rails_blog_engine_post.rb +12 -0
- data/db/migrate/20111125111958_create_rails_blog_engine_comments.rb +21 -0
- data/lib/generators/rails_blog_engine/install/USAGE +11 -0
- data/lib/generators/rails_blog_engine/install/install_generator.rb +51 -0
- data/lib/generators/rails_blog_engine/install/templates/rails_blog_engine.rb +13 -0
- data/lib/rails_blog_engine/ability.rb +16 -0
- data/lib/rails_blog_engine/engine.rb +5 -0
- data/lib/rails_blog_engine/filters/base.rb +17 -0
- data/lib/rails_blog_engine/filters/code.rb +21 -0
- data/lib/rails_blog_engine/filters.rb +53 -0
- data/lib/rails_blog_engine/version.rb +3 -0
- data/lib/rails_blog_engine.rb +18 -0
- data/lib/tasks/rails_blog_engine_tasks.rake +4 -0
- metadata +384 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
.rails_blog_engine_comment.show {
|
2
|
+
border: 1px solid lightgrey;
|
3
|
+
padding: 10px 10px 0 10px;
|
4
|
+
margin-bottom: 20px;
|
5
|
+
max-width: 600px;
|
6
|
+
|
7
|
+
&.spam {
|
8
|
+
background: lighten(#ffb6c1, 10%);
|
9
|
+
border-color: lighten(#ffb6c1, 5%);
|
10
|
+
color: darkgrey;
|
11
|
+
}
|
12
|
+
|
13
|
+
>.byline {
|
14
|
+
margin-top: 0;
|
15
|
+
margin-bottom: 10px;
|
16
|
+
font-weight: normal;
|
17
|
+
|
18
|
+
a.comment-link {
|
19
|
+
color: inherit;
|
20
|
+
&:link, &:visited { text-decoration: none; }
|
21
|
+
&:hover, &:active { text-decoration: underline; }
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
>.comment-tools {
|
26
|
+
float: right;
|
27
|
+
margin: 0 0 10px 10px;
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
// Place all the styles for posts and lists of posts here. We assume a
|
2
|
+
// light background color.
|
3
|
+
|
4
|
+
.rails_blog_engine_posts {
|
5
|
+
.new_post.btn, nav {
|
6
|
+
margin-bottom: 20px;
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
.rails_blog_engine_post {
|
11
|
+
color: black;
|
12
|
+
margin-bottom: 20px;
|
13
|
+
|
14
|
+
// Clear top margins. We'll use the bottom margin for spacing.
|
15
|
+
>h1, >p.byline, >.body {
|
16
|
+
margin-top: 0;
|
17
|
+
}
|
18
|
+
|
19
|
+
>h1 {
|
20
|
+
margin-bottom: 0px;
|
21
|
+
.btn {
|
22
|
+
vertical-align: text-bottom;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
>p.byline {
|
27
|
+
margin-bottom: 10px;
|
28
|
+
color: grey;
|
29
|
+
}
|
30
|
+
|
31
|
+
// This works at both the top level and in nested comments.
|
32
|
+
.body {
|
33
|
+
>blockquote, >dl, >embed, >h1, >h2, >h3, >h4, >h5, >h6, >hr, >object, >ol,
|
34
|
+
>p, >pre, >table, >ul, >aside, >figure, >header, >hgroup, >section {
|
35
|
+
margin-bottom: 10px;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
// We use this for moderation warnings.
|
40
|
+
>.flash.notice {
|
41
|
+
border: 1px solid #049cdb;
|
42
|
+
background: #c7eefe;
|
43
|
+
padding: 10px;
|
44
|
+
max-width: 600px;
|
45
|
+
}
|
46
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
.rails_blog_engine_post.simple_form, .rails_blog_engine_post .simple_form {
|
2
|
+
|
3
|
+
// Copied from
|
4
|
+
// https://github.com/plataformatec/simple_form/wiki/CSS-for-simple_form,
|
5
|
+
// tweaked to remove .simple_form, and nested inside our namespace.
|
6
|
+
div.input {
|
7
|
+
margin-bottom: 10px;
|
8
|
+
}
|
9
|
+
|
10
|
+
label {
|
11
|
+
float: left;
|
12
|
+
width: 100px;
|
13
|
+
text-align: right;
|
14
|
+
margin: 2px 10px;
|
15
|
+
}
|
16
|
+
|
17
|
+
div.boolean, input[type='submit'] {
|
18
|
+
margin-left: 120px;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.boolean label, label.collection_radio {
|
22
|
+
float: none;
|
23
|
+
margin: 0;
|
24
|
+
}
|
25
|
+
|
26
|
+
label.collection_radio {
|
27
|
+
margin-right: 10px;
|
28
|
+
vertical-align: -2px;
|
29
|
+
margin-left: 2px;
|
30
|
+
}
|
31
|
+
|
32
|
+
.field_with_errors {
|
33
|
+
background-color: #ff3333;
|
34
|
+
}
|
35
|
+
|
36
|
+
.error {
|
37
|
+
clear: left;
|
38
|
+
color: black;
|
39
|
+
display: block;
|
40
|
+
margin-left: 120px;
|
41
|
+
font-size: 12px;
|
42
|
+
}
|
43
|
+
|
44
|
+
.hint {
|
45
|
+
clear: left;
|
46
|
+
margin-left: 120px;
|
47
|
+
font-size: 12px;
|
48
|
+
color: #555;
|
49
|
+
display: block;
|
50
|
+
font-style: italic;
|
51
|
+
}
|
52
|
+
|
53
|
+
input.radio {
|
54
|
+
margin-right: 5px;
|
55
|
+
vertical-align: -3px;
|
56
|
+
}
|
57
|
+
|
58
|
+
input.check_boxes {
|
59
|
+
margin-left: 3px;
|
60
|
+
vertical-align: -3px;
|
61
|
+
}
|
62
|
+
|
63
|
+
label.collection_check_boxes {
|
64
|
+
float: none;
|
65
|
+
margin: 0;
|
66
|
+
vertical-align: -2px;
|
67
|
+
margin-left: 2px;
|
68
|
+
}
|
69
|
+
|
70
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RailsBlogEngine
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
# Use our parent application's layout, so that we "auto-blend" into
|
4
|
+
# the existing look-and-feel of the site.
|
5
|
+
layout 'application'
|
6
|
+
|
7
|
+
helper_method :post_permalink_url
|
8
|
+
helper_method :post_permalink_path
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def post_permalink_local_path(post)
|
13
|
+
date = post.published_at.utc
|
14
|
+
sprintf('%04d/%02d/%02d/%s', date.year, date.month,
|
15
|
+
date.day, post.permalink)
|
16
|
+
end
|
17
|
+
|
18
|
+
def post_permalink_path(post)
|
19
|
+
root_path + post_permalink_local_path(post)
|
20
|
+
end
|
21
|
+
|
22
|
+
def post_permalink_url(post)
|
23
|
+
root_url + post_permalink_local_path(post)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RailsBlogEngine
|
2
|
+
class CommentsController < ApplicationController
|
3
|
+
before_filter :load_post
|
4
|
+
|
5
|
+
load_and_authorize_resource :class => "RailsBlogEngine::Comment"
|
6
|
+
skip_load_resource :create
|
7
|
+
|
8
|
+
def create
|
9
|
+
@comment = @post.comments.create(params[:comment]) do |c|
|
10
|
+
# Record some extra information from our environment. Most of this
|
11
|
+
# is used by the spam filter.
|
12
|
+
c.author_ip = request.remote_ip
|
13
|
+
c.author_user_agent = request.env['HTTP_USER_AGENT']
|
14
|
+
c.author_can_post = can?(:create, RailsBlogEngine::Post)
|
15
|
+
c.referrer = request.env['HTTP_REFERER']
|
16
|
+
end
|
17
|
+
|
18
|
+
if @comment.valid?
|
19
|
+
@comment.run_spam_filter
|
20
|
+
if @comment.filtered_as_spam?
|
21
|
+
flash[:comment_notice] = "Your comment has been held for moderation."
|
22
|
+
redirect_to(post_permalink_path(@post) + '#comment-flash')
|
23
|
+
else
|
24
|
+
redirect_to(post_permalink_path(@post) + "#comment-#{@comment.id}")
|
25
|
+
end
|
26
|
+
else
|
27
|
+
render "new"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def mark_as_spam
|
32
|
+
@comment.mark_as_spam!
|
33
|
+
redirect_to(post_permalink_path(@post) + "#comment-#{@comment.id}")
|
34
|
+
end
|
35
|
+
|
36
|
+
def mark_as_ham
|
37
|
+
@comment.mark_as_ham!
|
38
|
+
redirect_to(post_permalink_path(@post) + "#comment-#{@comment.id}")
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def load_post
|
44
|
+
@post = Post.find(params[:post_id])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module RailsBlogEngine
|
2
|
+
class PostsController < ApplicationController
|
3
|
+
before_filter :load_recently_published, :only => :index
|
4
|
+
before_filter :load_by_permalink, :only => :show
|
5
|
+
|
6
|
+
load_and_authorize_resource :class => "RailsBlogEngine::Post"
|
7
|
+
|
8
|
+
def index
|
9
|
+
respond_to do |format|
|
10
|
+
format.html { @posts = @posts.page(params[:page]).per(5) }
|
11
|
+
format.atom { @posts = @posts.limit(15) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def new
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
@post.author = current_user
|
20
|
+
@post.publish
|
21
|
+
if @post.save
|
22
|
+
redirect_to(post_permalink_path(@post),
|
23
|
+
:notice => "Post was successfully created.")
|
24
|
+
else
|
25
|
+
render :action => :new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def show
|
30
|
+
@comments = comments_to_display.order(:created_at)
|
31
|
+
@comment = Comment.new {|c| c.post = @post }
|
32
|
+
end
|
33
|
+
|
34
|
+
def edit
|
35
|
+
end
|
36
|
+
|
37
|
+
def update
|
38
|
+
@post.update_attributes(params[:post])
|
39
|
+
if @post.save
|
40
|
+
redirect_to(post_permalink_path(@post),
|
41
|
+
:notice => "Post was successfully updated.")
|
42
|
+
else
|
43
|
+
render :action => :edit
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def load_recently_published
|
50
|
+
@posts = Post.recently_published
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_by_permalink
|
54
|
+
date = Time.utc(params[:year], params[:month], params[:day])
|
55
|
+
@post = Post.where(:published_at => (date..date.end_of_day),
|
56
|
+
:permalink => params[:permalink]).first!
|
57
|
+
end
|
58
|
+
|
59
|
+
def comments_to_display
|
60
|
+
if can?(:update, RailsBlogEngine::Comment)
|
61
|
+
@post.comments
|
62
|
+
else
|
63
|
+
@post.comments.visible
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module RailsBlogEngine
|
2
|
+
module ApplicationHelper
|
3
|
+
# Process a block of text as Markdown, using our filters, and sanitize
|
4
|
+
# any usafe HTML. You can pass <code>:trusted? => true</code> to allow
|
5
|
+
# images and links without nofollow.
|
6
|
+
def markdown(md_text, options={})
|
7
|
+
config = sanitize_config(options[:trusted?] || false)
|
8
|
+
filtered = Filters.apply_all_to(md_text)
|
9
|
+
Sanitize.clean(RDiscount.new(filtered, :smart).to_html, config).html_safe
|
10
|
+
end
|
11
|
+
|
12
|
+
# The URL of our Atom feed. Rails refuses to generate this in any simple
|
13
|
+
# fashion, so we do it manually.
|
14
|
+
def feed_url
|
15
|
+
root_url + "posts.atom"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get extra HTML classes for the specified comment.
|
19
|
+
def comment_classes(comment)
|
20
|
+
comment.state.sub(/\A(filtered|marked)_as_/, '')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Generate HTML describing the author of a comment.
|
24
|
+
def comment_author_html(comment)
|
25
|
+
if comment.author_url && !comment.author_url.blank?
|
26
|
+
link_to comment.author_byline, comment.author_url, :rel => "nofollow"
|
27
|
+
else
|
28
|
+
comment.author_byline
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
# Choose a configuration for the Sanitizer gem.
|
35
|
+
def sanitize_config(trusted)
|
36
|
+
if trusted then CUSTOM_RELAXED_CONFIG else Sanitize::Config::BASIC end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Allow a few extra tags, mostly for use by our source-code highlighting
|
40
|
+
# filter.
|
41
|
+
def self.customize_sanitize_config(sanitize_config)
|
42
|
+
new_config = {}
|
43
|
+
sanitize_config.each {|k,v| new_config[k] = v.dup }
|
44
|
+
new_config[:elements] += ['div', 'span']
|
45
|
+
new_config[:attributes].merge!('div' => ['class'], 'span' => ['class'])
|
46
|
+
new_config
|
47
|
+
end
|
48
|
+
|
49
|
+
# The Sanitize configuration used for trusted posters.
|
50
|
+
CUSTOM_RELAXED_CONFIG = customize_sanitize_config(Sanitize::Config::RELAXED)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module RailsBlogEngine
|
2
|
+
module PostsHelper
|
3
|
+
# Link to the comments section of a post.
|
4
|
+
def link_to_comments_section(post)
|
5
|
+
if post.comments.visible.empty?
|
6
|
+
link_to("Comment", post_permalink_path(post) + "#comments")
|
7
|
+
else
|
8
|
+
link_to(pluralize(post.comments.visible.count, 'comment'),
|
9
|
+
post_permalink_path(post) + "#comments")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module RailsBlogEngine
|
2
|
+
class Comment < ActiveRecord::Base
|
3
|
+
# Define the functions spam?, spam!, and ham!.
|
4
|
+
include Rakismet::Model
|
5
|
+
|
6
|
+
belongs_to :post, :class_name => 'RailsBlogEngine::Post'
|
7
|
+
|
8
|
+
validates :author_byline, :presence => true
|
9
|
+
validates :body, :presence => true
|
10
|
+
|
11
|
+
# Comments that are visible to the public.
|
12
|
+
scope(:visible,
|
13
|
+
where(:state => ['unfiltered', 'filtered_as_ham', 'marked_as_ham']))
|
14
|
+
|
15
|
+
# These fields are directly settable by the user.
|
16
|
+
attr_accessible :author_byline, :author_email, :author_url, :body
|
17
|
+
|
18
|
+
# Tell rakismet where to find the fields it needs for the spam filter.
|
19
|
+
# We don't need to specify fields which already have the right name.
|
20
|
+
#
|
21
|
+
# TODO: Include article permalink.
|
22
|
+
rakismet_attrs(:author => :author_byline, :content => :body,
|
23
|
+
:user_ip => :author_ip, :user_agent => :author_user_agent)
|
24
|
+
|
25
|
+
# A state machine which keeps track of our spam filter status.
|
26
|
+
state_machine :state, :initial => :unfiltered do
|
27
|
+
state :unfiltered
|
28
|
+
state :filtered_as_ham
|
29
|
+
state :filtered_as_spam
|
30
|
+
state :marked_as_ham
|
31
|
+
state :marked_as_spam
|
32
|
+
|
33
|
+
event :filter_as_ham do
|
34
|
+
transition :unfiltered => :filtered_as_ham
|
35
|
+
end
|
36
|
+
|
37
|
+
event :filter_as_spam do
|
38
|
+
transition :unfiltered => :filtered_as_spam
|
39
|
+
end
|
40
|
+
|
41
|
+
event :mark_as_ham do
|
42
|
+
transition [:filtered_as_spam, :marked_as_spam] => :marked_as_ham
|
43
|
+
end
|
44
|
+
|
45
|
+
event :mark_as_spam do
|
46
|
+
transition :unfiltered => :marked_as_spam
|
47
|
+
transition [:filtered_as_ham, :marked_as_ham] => :marked_as_spam
|
48
|
+
end
|
49
|
+
|
50
|
+
after_transition any => :marked_as_ham, :do => :train_as_ham
|
51
|
+
after_transition any => :marked_as_spam, :do => :train_as_spam
|
52
|
+
end
|
53
|
+
|
54
|
+
# Run the spam filter on this comment and update it appropriately.
|
55
|
+
def run_spam_filter
|
56
|
+
return unless Rakismet.key
|
57
|
+
if spam?
|
58
|
+
filter_as_spam!
|
59
|
+
else
|
60
|
+
filter_as_ham!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Train our spam filter to treat messages like this as ham.
|
65
|
+
def train_as_ham
|
66
|
+
ham! if Rakismet.key
|
67
|
+
end
|
68
|
+
|
69
|
+
# Train our spam filter to treat messages like this as spam.
|
70
|
+
def train_as_spam
|
71
|
+
spam! if Rakismet.key
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module RailsBlogEngine
|
2
|
+
class Post < ActiveRecord::Base
|
3
|
+
belongs_to :author, :polymorphic => true
|
4
|
+
has_many :comments, :class_name => 'RailsBlogEngine::Comment'
|
5
|
+
|
6
|
+
validates :title, :presence => true
|
7
|
+
validates :body, :presence => true
|
8
|
+
validates(:state, :presence => true,
|
9
|
+
:inclusion => { :in => %w(unpublished published) })
|
10
|
+
validates :permalink, :presence => true, :uniqueness => true
|
11
|
+
validates :author, :presence => true
|
12
|
+
validates :author_byline, :presence => true
|
13
|
+
validates :published_at, :presence => true, :if => :published?
|
14
|
+
|
15
|
+
attr_accessible :title, :body, :permalink, :author
|
16
|
+
|
17
|
+
# Recently published posts. Use this with +limit+.
|
18
|
+
scope :recently_published,
|
19
|
+
where(:state => 'published').order('published_at DESC')
|
20
|
+
|
21
|
+
# We use a state machine to represent our publication state. This is
|
22
|
+
# mostly because I visualize a UI with a great big "Publish" button,
|
23
|
+
# and not a "Published" checkbox in a form.
|
24
|
+
#
|
25
|
+
# If you'd like to upgrade your blog into a content-management system
|
26
|
+
# with some kind of pre-publication review, just adjust the states and
|
27
|
+
# transitions.
|
28
|
+
state_machine :state, :initial => :unpublished do
|
29
|
+
state :unpublished
|
30
|
+
state :published
|
31
|
+
|
32
|
+
event :publish do
|
33
|
+
transition :unpublished => :published
|
34
|
+
end
|
35
|
+
|
36
|
+
event :unpublish do
|
37
|
+
transition :published => :unpublished
|
38
|
+
end
|
39
|
+
|
40
|
+
before_transition any => :published do |post, transition|
|
41
|
+
post.published_at ||= Time.now
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
before_validation :record_author_byline
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
# Since the byline is computed from a polymorphic author association in
|
50
|
+
# a complicated fashion, we want to cache it in this object where it's
|
51
|
+
# available all the time.
|
52
|
+
def record_author_byline
|
53
|
+
byline = self.class.author_byline(author)
|
54
|
+
self.author_byline = byline unless self.author_byline == byline
|
55
|
+
end
|
56
|
+
|
57
|
+
class << self
|
58
|
+
# Try to generate a reasonable byline for an author. We use a
|
59
|
+
# +author.byline+ method if present, and default to +author.email+
|
60
|
+
# stripped of its domain.
|
61
|
+
def author_byline(author)
|
62
|
+
case
|
63
|
+
when author.respond_to?(:byline) && author.byline
|
64
|
+
author.byline
|
65
|
+
when author.respond_to?(:email) && author.email
|
66
|
+
author.email.sub(/@.*\z/, '')
|
67
|
+
else
|
68
|
+
'unknown'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
.rails_blog_engine_comment.show{:class => comment_classes(comment)}
|
2
|
+
= render(:partial => 'rails_blog_engine/comments/tools',
|
3
|
+
:locals => { :comment => comment })
|
4
|
+
%h4.byline
|
5
|
+
%a{:name => "comment-#{comment.id}"}
|
6
|
+
= comment_author_html(comment)
|
7
|
+
said
|
8
|
+
%a{:class => "comment-link", :href => "#comment-#{comment.id}"}= distance_of_time_in_words_to_now(comment.created_at)
|
9
|
+
ago:
|
10
|
+
%div.body~ markdown(comment.body, :trusted? => comment.author_can_post?)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
- if can?(:update, comment)
|
2
|
+
.comment-tools
|
3
|
+
- if can?(:mark_as_ham, comment) && comment.can_mark_as_ham?
|
4
|
+
= link_to("Not Spam",
|
5
|
+
mark_as_ham_post_comment_path(comment.post, comment),
|
6
|
+
:method => :post, :class => "btn")
|
7
|
+
- if can?(:mark_as_spam, comment) && comment.can_mark_as_spam?
|
8
|
+
= link_to("Spam",
|
9
|
+
mark_as_spam_post_comment_path(comment.post, comment),
|
10
|
+
:method => :post, :class => "btn")
|
@@ -0,0 +1,11 @@
|
|
1
|
+
%h3.comments
|
2
|
+
%a(name="comments") Comments
|
3
|
+
|
4
|
+
= render @comments
|
5
|
+
|
6
|
+
- if flash[:comment_notice]
|
7
|
+
%p.flash.notice
|
8
|
+
%a(name="comment-flash")= flash[:comment_notice]
|
9
|
+
|
10
|
+
= render(:partial => 'rails_blog_engine/comments/form',
|
11
|
+
:locals => { :comment => @comment })
|
@@ -0,0 +1,20 @@
|
|
1
|
+
.rails_blog_engine_post
|
2
|
+
%h1
|
3
|
+
= link_to_unless_current(post.title, post_permalink_path(post))
|
4
|
+
= render(:partial => 'rails_blog_engine/posts/tools',
|
5
|
+
:locals => { :post => post })
|
6
|
+
%p.byline
|
7
|
+
Posted
|
8
|
+
= distance_of_time_in_words_to_now(post.published_at)
|
9
|
+
ago by
|
10
|
+
= post.author_byline
|
11
|
+
|
12
|
+
%div.body~ markdown(post.body, :trusted? => true)
|
13
|
+
|
14
|
+
- if current_page?(post_permalink_path(post))
|
15
|
+
= render(:partial => 'rails_blog_engine/posts/comments_section',
|
16
|
+
:locals => { :post => post, :comments => @comments,
|
17
|
+
:comment => @comment })
|
18
|
+
- else
|
19
|
+
%p.links
|
20
|
+
= link_to_comments_section(post)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
atom_feed(:root_url => root_url, :url => feed_url) do |feed|
|
2
|
+
feed.title t('rails_blog_engine.blog.title')
|
3
|
+
feed.updated @posts.map(&:updated_at).sort.reverse.first
|
4
|
+
@posts.each do |post|
|
5
|
+
feed.entry(post, :published => post.published_at,
|
6
|
+
:url => post_permalink_url(post)) do |entry|
|
7
|
+
entry.title post.title
|
8
|
+
entry.content markdown(post.body), :type => 'html'
|
9
|
+
entry.author do |author|
|
10
|
+
author.name post.author_byline
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
- content_for :title do
|
2
|
+
= t('rails_blog_engine.blog.title')
|
3
|
+
- content_for :head do
|
4
|
+
= auto_discovery_link_tag :atom, feed_url
|
5
|
+
- if params[:page]
|
6
|
+
-# Don't index pages after the first, but still follow links.
|
7
|
+
- content_for :head do
|
8
|
+
%meta(name="robots" content="noindex, follow")
|
9
|
+
|
10
|
+
.rails_blog_engine_posts
|
11
|
+
- if can?(:create, RailsBlogEngine::Post)
|
12
|
+
= link_to "New Post", new_post_path, :class => "new_post btn large primary"
|
13
|
+
|
14
|
+
= render @posts
|
15
|
+
= paginate @posts
|
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
rails_blog_engine:
|
3
|
+
blog:
|
4
|
+
title: "Blog"
|
5
|
+
activerecord:
|
6
|
+
attributes:
|
7
|
+
rails_blog_engine/comment:
|
8
|
+
author_byline: "Your name"
|
9
|
+
author_email: "Your email"
|
10
|
+
author_url: "Your website"
|
11
|
+
body: "Comment"
|
12
|
+
helpers:
|
13
|
+
submit:
|
14
|
+
comment:
|
15
|
+
create: "Post Comment"
|