rails_blog_engine 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|