tylerrick-bcms_blog 1.0.5

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.
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>