tylerrick-bcms_blog 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.markdown +63 -0
  2. data/app/controllers/application_controller.rb +10 -0
  3. data/app/controllers/cms/blog_comments_controller.rb +3 -0
  4. data/app/controllers/cms/blog_posts_controller.rb +35 -0
  5. data/app/controllers/cms/blogs_controller.rb +11 -0
  6. data/app/helpers/application_helper.rb +3 -0
  7. data/app/helpers/cms/blog_helper.rb +11 -0
  8. data/app/models/blog.rb +143 -0
  9. data/app/models/blog_comment.rb +28 -0
  10. data/app/models/blog_group_membership.rb +4 -0
  11. data/app/models/blog_post.rb +101 -0
  12. data/app/portlets/blog_post_portlet.rb +38 -0
  13. data/app/views/cms/blog_comments/_form.html.erb +5 -0
  14. data/app/views/cms/blog_comments/render.html.erb +2 -0
  15. data/app/views/cms/blog_posts/_form.html.erb +11 -0
  16. data/app/views/cms/blog_posts/no_access.html.erb +9 -0
  17. data/app/views/cms/blog_posts/render.html.erb +1 -0
  18. data/app/views/cms/blogs/_form.html.erb +23 -0
  19. data/app/views/cms/blogs/admin_only.html.erb +9 -0
  20. data/app/views/cms/blogs/render.html.erb +2 -0
  21. data/app/views/partials/_blog_post.html.erb +106 -0
  22. data/app/views/partials/_blog_post.html.haml +91 -0
  23. data/app/views/portlets/blog_post/_form.html.erb +3 -0
  24. data/app/views/portlets/blog_post/render.html.erb +33 -0
  25. data/db/migrate/20090415000000_create_blogs.rb +45 -0
  26. data/db/migrate/20090415000001_create_blog_posts.rb +25 -0
  27. data/db/migrate/20090415000002_create_blog_comments.rb +19 -0
  28. data/db/migrate/20090415000003_add_attachment_to_blog_posts.rb +23 -0
  29. data/doc/README_FOR_APP +2 -0
  30. data/doc/migrate_to_20100427.rb +68 -0
  31. data/lib/bcms_blog/routes.rb +9 -0
  32. data/lib/bcms_blog.rb +1 -0
  33. data/rails/init.rb +4 -0
  34. data/test/factories.rb +31 -0
  35. data/test/functional/blog_post_test.rb +41 -0
  36. data/test/functional/blog_test.rb +69 -0
  37. data/test/functional/cms/blog_posts_controller_test.rb +43 -0
  38. data/test/functional/cms/blogs_controller_test.rb +12 -0
  39. data/test/performance/browsing_test.rb +9 -0
  40. data/test/test_helper.rb +104 -0
  41. data/test/test_logging.rb +64 -0
  42. data/test/unit/blog_post_test.rb +16 -0
  43. data/test/unit/blog_test.rb +23 -0
  44. metadata +96 -0
data/README.markdown ADDED
@@ -0,0 +1,63 @@
1
+ # Blog Module for BrowserCMS
2
+
3
+ A simple blog module that lets you create one or more blogs. It features:
4
+
5
+ * Blog posts can be tagged and categorized
6
+ * The ability for users to leave comments on a blog post (stores the user name, email, url and comment)
7
+ * Support for multiple blogs
8
+ * Blog block can be added to any container in any page
9
+
10
+ ## Installation
11
+ To install this module, do the following:
12
+
13
+ ### A. Build and install the gem from source
14
+ This assumes you have the latest copy of the code from github on your machine.
15
+
16
+ gem build bcms_blog.gemspec
17
+ sudo gem install bcms_blog-1.x.x.gem
18
+
19
+ At this point, the Page Comments gem should be installed as a gem on your system, and can be added to your projects.
20
+
21
+ ### B. Adding the Page Comments to your project
22
+ In your BrowserCMS application, do the following steps.
23
+
24
+ #### 1. Edit the confing/environment.rb file
25
+
26
+ config.gem 'browsercms'
27
+
28
+ # Add this next line after the browsercms gem
29
+ config.gem "bcms_page_comments"
30
+
31
+ #### 2. Edit the routes.rb file
32
+
33
+ # Add this route. It must be before the core browser_cms route.
34
+ map.routes_for_bcms_page_comments
35
+ map.routes_for_browser_cms
36
+
37
+ #### 3. Install the new module code
38
+ From the root directory of your cms project, run:
39
+
40
+ script/generate browser_cms
41
+
42
+ This will copy all the necessary views and migrations from the gems into your local project. You should messages checking to see if files already exist or were created.
43
+
44
+ #### 4. Run migrations and start the server
45
+ Modules will often add new data types, like content blocks, so you need to run the migrations to add them to your project.
46
+
47
+ rake db:migrate
48
+ script/server
49
+
50
+ #### 5. Create a Comments portlet and embed into your templates
51
+ * Open your browser to localhost:3000/cms/portlets and login
52
+ * Click 'Add New Content', and select 'Page Comments Portlet'
53
+ * Set the name to 'Page Comments' and click save.
54
+ * Now go to Administration -> Page Templates -> Sub Page -> Edit
55
+ * Add the following line to your template, somewhere in the body (preferably after your main content area)
56
+
57
+ <%= render_portlet "Page Comments" %>
58
+
59
+ This will render embed the portlet named "Page Comments" into any page which uses the Sub Page template.
60
+
61
+ * Now add a new page using the "Sub Page" template and you should see the comments form. Adding a new comment will display on that page.
62
+
63
+
@@ -0,0 +1,10 @@
1
+ # Filters added to this controller apply to all controllers in the application.
2
+ # Likewise, all the methods added will be available for all controllers.
3
+
4
+ class ApplicationController < ActionController::Base
5
+ helper :all # include all helpers, all the time
6
+ protect_from_forgery # See ActionController::RequestForgeryProtection for details
7
+
8
+ # Scrub sensitive parameters from your log
9
+ # filter_parameter_logging :password
10
+ end
@@ -0,0 +1,3 @@
1
+ class Cms::BlogCommentsController < Cms::ContentBlockController
2
+
3
+ end
@@ -0,0 +1,35 @@
1
+ class Cms::BlogPostsController < Cms::ContentBlockController
2
+ before_filter :show_no_access_if_none_editable
3
+
4
+ def build_block
5
+ super
6
+ ensure_blog_editable
7
+ @block.author = current_user
8
+ end
9
+
10
+ def load_block
11
+ super
12
+ ensure_blog_editable
13
+ end
14
+
15
+ def load_blocks
16
+ super
17
+ @blocks.delete_if { |b| !b.editable_by?(current_user) }
18
+ end
19
+
20
+ private
21
+
22
+ # If the current user is not able to edit any blog, just show them a page saying so
23
+ def show_no_access_if_none_editable
24
+ if Blog.editable_by(current_user).empty?
25
+ render :action => "no_access"
26
+ end
27
+ end
28
+
29
+ # Ensure the current user can actually edit the blog this blog post is associated with
30
+ def ensure_blog_editable
31
+ if @block.blog
32
+ raise Cms::Errors::AccessDenied unless @block.blog.editable_by?(current_user)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ class Cms::BlogsController < Cms::ContentBlockController
2
+ check_permissions :administrate, :except => :index
3
+
4
+ def index
5
+ if current_user.able_to?(:administrate)
6
+ super
7
+ else
8
+ render :action => "admin_only"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ # Methods added to this helper will be available to all templates in the application.
2
+ module ApplicationHelper
3
+ end
@@ -0,0 +1,11 @@
1
+ module Cms::BlogHelper
2
+ # We can't call it 'blog_path' because that would conflict with the actual named route method if there's a blog named "Blog".
3
+ def _blog_path(blog, route_name, route_params)
4
+ send("#{blog.name_for_path}_#{route_name}_path", route_params)
5
+ end
6
+
7
+ def _blog_post_path(blog_post)
8
+ send("#{blog_post.route_name}_path", blog_post.route_params)
9
+ end
10
+ end
11
+
@@ -0,0 +1,143 @@
1
+ class Blog < ActiveRecord::Base
2
+ acts_as_content_block
3
+ has_many :posts, :class_name => "BlogPost", :conditions => { :published => true }, :order => "published_at desc"
4
+
5
+ has_many :blog_group_memberships
6
+ has_many :groups, :through => :blog_group_memberships
7
+
8
+ validates_presence_of :name
9
+ validates_uniqueness_of :name
10
+
11
+ named_scope :editable_by, lambda { |user|
12
+ if user.able_to?(:administrate)
13
+ { }
14
+ else
15
+ { :include => :groups, :conditions => ["groups.id IN (?)", user.group_ids.join(",")] }
16
+ end
17
+ }
18
+
19
+ def self.default_template
20
+ template_file = ActionController::Base.view_paths.map do |vp|
21
+ path = vp.to_s.first == "/" ? vp.to_s : File.join(Rails.root, vp.to_s)
22
+ File.join(path, "cms/blogs/render.html.erb")
23
+ end.detect{|f| File.exists? f }
24
+ template_file ? open(template_file){|f| f.read } : ""
25
+ end
26
+
27
+ def render
28
+ @blog = self
29
+ finder = @blog.posts.published
30
+
31
+ if params[:category]
32
+ @category_type = CategoryType.named("Blog Post").first
33
+ @category = @category_type.categories.named(params[:category]).first
34
+ finder = finder.in_category(@category)
35
+ @page_title = "Posts in category #{params[:category]}"
36
+ elsif params[:tag]
37
+ finder = finder.tagged_with(params[:tag])
38
+ @page_title = "Posts tagged with #{params[:tag]}"
39
+ elsif params[:year] && params[:month] && params[:day]
40
+ @date = Date.new(params[:year].to_i, params[:month].to_i, params[:day].to_i)
41
+ finder = posts.published_between(@date, @date + 1.day)
42
+ @page_title = "Blog posts from #{@date.to_s(:long)}"
43
+ elsif params[:year] && params[:month]
44
+ @date = Date.new(params[:year].to_i, params[:month].to_i)
45
+ finder = posts.published_between(@date, @date + 1.month)
46
+ @page_title = "Blog posts from #{Date::MONTHNAMES[@date.month]} #{@date.year}"
47
+ elsif params[:year]
48
+ @date = Date.new(params[:year].to_i)
49
+ finder = posts.published_between(@date, @date + 1.year)
50
+ @page_title = "Blog posts from #{@date.year}"
51
+ end
52
+
53
+ @blog_posts = finder.all(:limit => 25, :order => "published_at desc")
54
+ raise ActiveRecord::RecordNotFound.new("No posts found") if @blog_posts.empty?
55
+ end
56
+
57
+ def inline_options
58
+ {:inline => self.template}
59
+ end
60
+
61
+ def self.default_order
62
+ "name"
63
+ end
64
+
65
+ def editable_by?(user)
66
+ user.able_to?(:administrate) || !(group_ids & user.group_ids).empty?
67
+ end
68
+
69
+ def potential_authors
70
+ groups.map(&:users).flatten.uniq
71
+ end
72
+
73
+
74
+ #-------------------------------------------------------------------------------------------------
75
+
76
+ def name_for_path
77
+ name.to_slug.gsub('-', '_')
78
+ end
79
+
80
+ protected
81
+ def after_create
82
+ section = Section.find_by_name(name) || (
83
+ section = Section.create!(
84
+ :name => name,
85
+ :path => "/#{name_for_path}",
86
+ :parent_id => 1
87
+ )
88
+ section.groups << Group.find_by_code("cms-admin")
89
+ section.groups << Group.find_by_code("guest")
90
+ section.groups << Group.find_by_code("content-editor")
91
+ section.save!
92
+ section
93
+ )
94
+
95
+ page = Page.find_by_name(name) || Page.create!(
96
+ :name => name,
97
+ :path => "/#{name_for_path}",
98
+ :section => section,
99
+ :template_file_name => "default.html.erb",
100
+ :hidden => true
101
+ )
102
+ page.create_connector(self, 'main')
103
+ create_route(page, "#{name}: Posts In Day", "/#{name_for_path}/:year/:month/:day")
104
+ create_route(page, "#{name}: Posts In Month", "/#{name_for_path}/:year/:month")
105
+ create_route(page, "#{name}: Posts In Year", "/#{name_for_path}/:year")
106
+ create_route(page, "#{name}: Posts With Tag", "/#{name_for_path}/tag/:tag")
107
+ create_route(page, "#{name}: Posts In Category", "/#{name_for_path}/category/:category")
108
+
109
+ page = Page.find_by_name(portlet_name = "#{name}: Post") || Page.create!(
110
+ :name => portlet_name,
111
+ :path => "/#{name_for_path}/post",
112
+ :section => section,
113
+ :template_file_name => "default.html.erb",
114
+ :hidden => true)
115
+ page.publish
116
+ create_route( page, portlet_name, "/#{name_for_path}/:year/:month/:day/:slug")
117
+ create_portlet(page, portlet_name, BlogPostPortlet)
118
+
119
+ # FIXME: This takes about 5 seconds to run, which is probably too long.
120
+ # Solution: Disable PageRoute's after_save :reload_routes and add this to the end here:
121
+ # ActionController::Routing::Routes.load!
122
+ end
123
+
124
+ def create_route(page, name, pattern)
125
+ route = page.page_routes.build(:name => name, :pattern => pattern, :code => "")
126
+ route.add_condition(:method, "get")
127
+ route.add_requirement(:year, '\d{4,}') if pattern.include?(":year")
128
+ route.add_requirement(:month, '\d{2,}') if pattern.include?(":month")
129
+ route.add_requirement(:day, '\d{2,}') if pattern.include?(":day")
130
+ route.save!
131
+ end
132
+
133
+ def create_portlet(page, name, portlet_class)
134
+ portlet_class.create!(
135
+ :name => "#{name} Portlet",
136
+ :blog_id => self.id,
137
+ :template => portlet_class.default_template,
138
+ :connect_to_page_id => page.id,
139
+ :connect_to_container => "main",
140
+ :publish_on_save => true)
141
+ end
142
+
143
+ end
@@ -0,0 +1,28 @@
1
+ class BlogComment < ActiveRecord::Base
2
+ acts_as_content_block :is_searachable => "body"
3
+ belongs_to :post, :class_name => "BlogPost", :counter_cache => "comments_count"
4
+
5
+ validates_presence_of :post_id, :author, :body
6
+
7
+ def self.default_order
8
+ "blog_comments.created_at desc"
9
+ end
10
+
11
+ def self.default_order_for_search
12
+ default_order
13
+ end
14
+
15
+ def self.columns_for_index
16
+ [ {:label => "Comment", :method => :name, :order => "blog_comments.body" },
17
+ {:label => "Created At", :method => :formatted_created_at, :order => "blog_comments.created_at"} ]
18
+ end
19
+
20
+ def name
21
+ body ? body[0..50] : ""
22
+ end
23
+
24
+ def formatted_created_at
25
+ created_at.to_s(:date)
26
+ end
27
+
28
+ end
@@ -0,0 +1,4 @@
1
+ class BlogGroupMembership < ActiveRecord::Base
2
+ belongs_to :blog
3
+ belongs_to :group
4
+ end
@@ -0,0 +1,101 @@
1
+ class BlogPost < ActiveRecord::Base
2
+ acts_as_content_block :taggable => true
3
+
4
+ belongs_to_attachment
5
+ def set_attachment_file_path
6
+ # The default behavior is use /attachments/file.txt for the attachment path,
7
+ # assuming file.txt was the name of the file the user uploaded
8
+ # You should override this with your own strategy for setting the attachment path
9
+ super
10
+ end
11
+
12
+ def set_attachment_section
13
+ # The default behavior is to put all attachments in the root section
14
+ # Override this method if you would like to change that
15
+ super
16
+ end
17
+
18
+
19
+ before_save :set_published_at
20
+
21
+ belongs_to :blog
22
+ belongs_to_category
23
+ belongs_to :author, :class_name => "User"
24
+ has_many :comments, :class_name => "BlogComment", :foreign_key => "post_id"
25
+
26
+ before_validation :set_slug
27
+ validates_presence_of :name, :slug, :blog_id, :author_id
28
+
29
+ named_scope :published_between, lambda { |start, finish|
30
+ { :conditions => [
31
+ "blog_posts.published_at >= ? AND blog_posts.published_at < ?",
32
+ start, finish ] }
33
+ }
34
+
35
+ INCORRECT_PARAMETERS = "Incorrect parameters. This is probably because you are trying to view the " +
36
+ "portlet through the CMS interface, and so we have no way of knowing what " +
37
+ "post(s) to show"
38
+
39
+ delegate :editable_by?, :to => :blog
40
+
41
+ def set_published_at
42
+ if !published_at && publish_on_save
43
+ self.published_at = Time.now
44
+ end
45
+ end
46
+
47
+ # This is necessary because, oddly, the publish! method in the Publishing behaviour sends an update
48
+ # query directly to the database, bypassing callbacks, so published_at does not get set by our
49
+ # set_published_at callback.
50
+ def after_publish_with_set_published_at
51
+ if published_at.nil?
52
+ self.published_at = Time.now
53
+ self.save!
54
+ end
55
+ after_publish_without_set_published_at if respond_to? :after_publish_without_set_published_at
56
+ end
57
+ if instance_methods.map(&:to_s).include? 'after_publish'
58
+ alias_method_chain :after_publish, :set_published_at
59
+ else
60
+ alias_method :after_publish, :after_publish_with_set_published_at
61
+ end
62
+
63
+ def self.default_order
64
+ "created_at desc"
65
+ end
66
+
67
+ def self.columns_for_index
68
+ [ {:label => "Name", :method => :name, :order => "name" },
69
+ {:label => "Published", :method => :published_label, :order => "published" } ]
70
+ end
71
+
72
+ def published_label
73
+ published_at ? published_at.to_s(:date) : nil
74
+ end
75
+
76
+ def set_slug
77
+ self.slug = name.to_slug
78
+ end
79
+
80
+ def path
81
+ send("#{blog.name_for_path}_post_path", route_params)
82
+ end
83
+ def route_name
84
+ "#{blog.name_for_path}_post"
85
+ end
86
+ def route_params
87
+ {:year => year, :month => month, :day => day, :slug => slug}
88
+ end
89
+
90
+ def year
91
+ published_at.strftime("%Y") unless published_at.blank?
92
+ end
93
+
94
+ def month
95
+ published_at.strftime("%m") unless published_at.blank?
96
+ end
97
+
98
+ def day
99
+ published_at.strftime("%d") unless published_at.blank?
100
+ end
101
+ end
@@ -0,0 +1,38 @@
1
+ class BlogPostPortlet < Portlet
2
+ render_inline false
3
+ enable_template_editor false
4
+
5
+ def render
6
+ scope = Blog.find(self.blog_id).posts
7
+ if params[:blog_post_id]
8
+ @blog_post = scope.find(params[:blog_post_id])
9
+ elsif params[:slug]
10
+ if params[:year]
11
+ date = Date.new(params[:year].to_i, params[:month].to_i, params[:day].to_i)
12
+ scope = scope.published_between(date, date + 1.day)
13
+ end
14
+ @blog_post = scope.find_by_slug!(params[:slug])
15
+ else
16
+ raise BlogPost::INCORRECT_PARAMETERS
17
+ end
18
+
19
+ pmap = flash[instance_name] || params
20
+ pmap[:blog_comment] ||= {}
21
+
22
+ @blog_comment = @blog_post.comments.build pmap[:blog_comment]
23
+ @blog_comment.errors.add_from_hash flash["#{instance_name}_errors"]
24
+ end
25
+
26
+ def create_comment
27
+ params[:blog_comment].merge! :ip => request.remote_ip
28
+ blog_comment = BlogComment.new(params[:blog_comment])
29
+ if blog_comment.valid? && blog_comment.save
30
+ url_for_success
31
+ else
32
+ store_params_in_flash
33
+ store_errors_in_flash(blog_comment.errors)
34
+ url_for_failure
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,5 @@
1
+ <%= f.cms_drop_down :post_id, BlogPost.all(:order => "name").map{|p| [p.name, p.id]} %>
2
+ <%= f.cms_text_field :author %>
3
+ <%= f.cms_text_field :email %>
4
+ <%= f.cms_text_field :url %>
5
+ <%= f.cms_text_area :body %>
@@ -0,0 +1,2 @@
1
+ <%= link_to h(@content_block.post.name), cms_blog_post_path(@content_block.post) %>
2
+ <p><%=h @content_block.body %></p>
@@ -0,0 +1,11 @@
1
+ <%= f.cms_drop_down :blog_id, Blog.editable_by(current_user).map{|b| [b.name, b.id]} %>
2
+ <% unless @block.new_record? %>
3
+ <%= f.cms_drop_down :author_id, @block.blog.potential_authors.map { |u| ["#{u.full_name} (#{u.login})", u.id] } %>
4
+ <% end %>
5
+ <%= f.cms_drop_down :category_id, categories_for('Blog Post').map{|c| [c.path, c.id]}, :include_blank => true %>
6
+ <%= f.cms_text_field :name, :label => 'Title' %>
7
+ <%= f.cms_tag_list %>
8
+ <%= f.cms_datetime_select :published_at, :label => "Date" %>
9
+ <%= f.cms_text_area :summary, :style => "height: 200px", :instructions => 'This will be displayed on the list page with a Read More link if present' %>
10
+ <%= f.cms_text_editor :body %>
11
+ <%= f.cms_file_field :attachment_file, :label => "Image" %>
@@ -0,0 +1,9 @@
1
+ <% content_for(:html_head) do %>
2
+ <%= stylesheet_link_tag "cms/content_library" %>
3
+ <% end %>
4
+ <% page_title "Content Library / List #{content_type.display_name_plural}" %>
5
+ <% @toolbar_title = "List #{content_type.display_name_plural}" %>
6
+
7
+ <div class="roundedcorners">
8
+ <p>Sorry, you don't have the permissions to write blog posts.</p>
9
+ </div>
@@ -0,0 +1 @@
1
+ <%= render :partial => "partials/blog_post", :object => @content_block %>
@@ -0,0 +1,23 @@
1
+ <%= f.cms_text_field :name %>
2
+
3
+ <div class="checkbox_group fields" style="float: left; width: 100%">
4
+ <label>Permissions</label>
5
+ <%= hidden_field_tag "blog[group_ids][]", "", :id => nil %>
6
+ <div class="checkboxes">
7
+ <% for group in Group.cms_access.all(:order => "groups.name") %>
8
+ <div class="checkbox_fields">
9
+ <%= check_box_tag "blog[group_ids][]", group.id,
10
+ @block.groups.include?(group), :class => "cms_group_ids", :id => "cms_group_ids_#{group.id}", :tabindex => next_tabindex %>
11
+ <label for="cms_group_ids_<%= group.id %>"><%= group.name %></label>
12
+ </div>
13
+ <% end %>
14
+ <div class="instructions">Which &ldquo;CMS&rdquo; groups can edit and publish the blog?</div>
15
+ <div class="check_uncheck">
16
+ <%= link_to_check_all 'input.cms_group_ids' %>,
17
+ <%= link_to_uncheck_all 'input.cms_group_ids' %>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ <br clear="all" />
22
+
23
+ <%= f.cms_text_area :template, :default_value => Blog.default_template %>
@@ -0,0 +1,9 @@
1
+ <% content_for(:html_head) do %>
2
+ <%= stylesheet_link_tag "cms/content_library" %>
3
+ <% end %>
4
+ <% page_title "Content Library / List #{content_type.display_name_plural}" %>
5
+ <% @toolbar_title = "List #{content_type.display_name_plural}" %>
6
+
7
+ <div class="roundedcorners">
8
+ <p>Sorry, this section is restricted to administrators.</p>
9
+ </div>
@@ -0,0 +1,2 @@
1
+ <% page_title @page_title || @blog.name %>
2
+ <%= render :partial => "partials/blog_post", :collection => @blog_posts %>
@@ -0,0 +1,106 @@
1
+ <style>
2
+ .blog_post {
3
+ border-bottom: 1px solid #ccc;
4
+ margin-bottom: 20px;
5
+ }
6
+
7
+ .blog_post h2 {
8
+ margin-bottom: 0
9
+ }
10
+
11
+ .blog_post h2,
12
+ .blog_post h2 a {
13
+ font: normal 30px/28px 'arial black', arial, sans-serif !important;
14
+ text-decoration: none !important;
15
+ }
16
+ .blog_post h2 a:hover {
17
+ text-decoration: underline !important;
18
+ }
19
+
20
+ .blog_post .image {
21
+ float: left;
22
+ border: 1px solid #ccc;
23
+ margin: 10px;
24
+ margin-top: 0;
25
+ }
26
+ .blog_post .date {
27
+ color: #666;
28
+ }
29
+ .blog_post .read_more {
30
+ font-weight: bold;
31
+ }
32
+
33
+ .blog_post .comment + .comment {
34
+ border-top: 1px dashed #ccc;
35
+ }
36
+
37
+ .clear {
38
+ clear: both;
39
+ }
40
+ </style>
41
+
42
+ <%
43
+ # _counter is defined only if we pass :collection to the partial
44
+ if defined?(blog_post_counter)
45
+ showing_individual_post = false
46
+ else
47
+ showing_individual_post = true
48
+ blog_post_counter = 0
49
+ end
50
+ %>
51
+
52
+ <div id="blog_post_<%= blog_post.id %>" class="blog_post clear">
53
+ <% if blog_post.attachment %>
54
+ <div class="image">
55
+ <%# image_tag_with_max_size blog_post.attachment.file_path, blog_post.attachment.full_file_location, :width => max_width %>
56
+ <%= image_tag blog_post.attachment.file_path %>
57
+ </div>
58
+ <% end %>
59
+
60
+ <h2><%= link_to h(blog_post.name), href = _blog_post_path(blog_post) %></h2>
61
+
62
+ <div class="date"><%= blog_post.published_at.to_s(:long) %></div>
63
+
64
+ <div class="body">
65
+ <% if showing_individual_post or blog_post.summary.blank? %>
66
+ <%= blog_post.body %>
67
+ <% else %>
68
+ <%= blog_post.summary %>
69
+ <p class="read_more">
70
+ <%= link_to 'Read More »', href %>
71
+ </p>
72
+ <% end %>
73
+ </div>
74
+
75
+ <div class="meta">
76
+ <% unless blog_post.category_id.blank? %>
77
+ Posted in <%= link_to h(blog_post.category_name), _blog_path(blog_post.blog, 'posts_in_category', :category => blog_post.category_name) %>
78
+ <strong>|</strong>
79
+ <% end %>
80
+
81
+ <% if blog_post.tags.any? %>
82
+ Tags:
83
+ <span class="tags">
84
+ <%= blog_post.tags.map{|t| link_to(h(t.name), _blog_path(blog_post.blog, 'posts_with_tag', :tag => t.name)) }.join(", ") %>
85
+ </span>
86
+ <strong>|</strong>
87
+ <% end %>
88
+
89
+ <%= link_to h(pluralize(blog_post.comments_count, "Comment")), "#{_blog_post_path(blog_post)}#comments" %>
90
+ </div>
91
+ <br class="clear" />
92
+
93
+
94
+ <% comments = blog_post.comments.reject(&:new_record?) %>
95
+ <% if showing_individual_post and comments.any? -%>
96
+ <h2>Comments</h2>
97
+ <% comments.each_with_index do |comment, i| %>
98
+ <div class="comment <%= 'first' if i == 0 %>">
99
+ <%= h comment.body %>
100
+ <p>&mdash;<%= comment.url.present? ? link_to(h(comment.author), comment.url) : h(comment.author) %></p>
101
+ </div>
102
+ <% end %>
103
+ <% end %>
104
+
105
+
106
+ </div>