Commit fe596c845d2dc4bbf2b3ef355077abfec5436408

Authored by Rodrigo Souto
2 parents 42e1b8af 3e725049

Merge branch 'post-pic' into 'next'

Improve blog posts listing

A help for armengeless themes.

See merge request !543
app/helpers/blog_helper.rb
... ... @@ -17,28 +17,28 @@ module BlogHelper
17 17 _('Configure blog')
18 18 end
19 19  
20   - def list_posts(articles, format = 'full', paginate = true)
  20 + def list_posts(articles, conf = { format: 'full', paginate: true })
21 21 pagination = will_paginate(articles, {
22 22 :param_name => 'npage',
23 23 :previous_label => _('« Newer posts'),
24 24 :next_label => _('Older posts »'),
25 25 :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
26   - }) if articles.present? && paginate
  26 + }) if articles.present? && conf[:paginate]
27 27 content = []
28 28 artic_len = articles.length
29 29 articles.each_with_index{ |art,i|
30   - css_add = [ 'position-'+(i+1).to_s() ]
  30 + css_add = [ 'blog-post', 'position-'+(i+1).to_s() ]
31 31 position = (i%2 == 0) ? 'odd-post' : 'even-post'
32 32 css_add << 'first' if i == 0
33 33 css_add << 'last' if i == (artic_len-1)
34 34 css_add << 'not-published' if !art.published?
35   - css_add << position + '-inner'
36   - content << content_tag('div',
37   - content_tag('div',
38   - display_post(art, format).html_safe + '<br style="clear:both"/>'.html_safe,
39   - :class => 'blog-post ' + css_add.join(' '),
40   - :id => "post-#{art.id}"), :class => position
41   - )
  35 + css_add << position
  36 + content << (content_tag 'div', id: "post-#{art.id}", class: css_add do
  37 + content_tag 'div', class: position + '-inner blog-post-inner' do
  38 + display_post(art, conf[:format]).html_safe +
  39 + '<br style="clear:both"/>'.html_safe
  40 + end
  41 + end)
42 42 }
43 43 content.join("\n<hr class='sep-posts'/>\n") + (pagination or '')
44 44 end
... ... @@ -46,7 +46,16 @@ module BlogHelper
46 46 def display_post(article, format = 'full')
47 47 no_comments = (format == 'full') ? false : true
48 48 title = article_title(article, :no_comments => no_comments)
49   - html = send("display_#{format}_format", FilePresenter.for(article)).html_safe
  49 + method = "display_#{format.split('+')[0]}_format"
  50 + html = send(method, FilePresenter.for(article)).html_safe
  51 + if format.split('+')[1] == 'pic'
  52 + img = article.first_image
  53 + if img.blank?
  54 + '<div class="post-pic empty"></div>'
  55 + else
  56 + '<div class="post-pic" style="background-image:url('+img+')"></div>'
  57 + end
  58 + end.to_s +
50 59 title + html
51 60 end
52 61  
... ...
app/models/article.rb
... ... @@ -769,7 +769,9 @@ class Article &lt; ActiveRecord::Base
769 769 end
770 770  
771 771 def first_image
772   - img = Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first || Nokogiri::HTML.fragment(self.body.to_s).search('img').first
  772 + img = ( image.present? && { 'src' => image.public_filename } ) ||
  773 + Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first ||
  774 + Nokogiri::HTML.fragment(self.body.to_s).search('img').first
773 775 img.nil? ? '' : img['src']
774 776 end
775 777  
... ...
app/models/blog.rb
... ... @@ -76,7 +76,7 @@ class Blog &lt; Folder
76 76 end
77 77  
78 78 settings_items :visualization_format, :type => :string, :default => 'full'
79   - validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format
  79 + validates_inclusion_of :visualization_format, :in => [ 'full', 'short', 'short+pic' ], :if => :visualization_format
80 80  
81 81 settings_items :display_posts_in_current_language, :type => :boolean, :default => false
82 82  
... ...
app/views/cms/_blog.html.erb
... ... @@ -64,7 +64,11 @@
64 64 <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%>
65 65 <% end %>
66 66  
67   -<%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ [ _('Full post'), 'full'], [ _('First paragraph'), 'short'] ])) %>
  67 +<%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [
  68 + [ _('Full post'), 'full'],
  69 + [ _('First paragraph'), 'short'],
  70 + [ _('First paragraph, with post picture'), 'short+pic']
  71 +])) %>
68 72  
69 73 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %>
70 74  
... ...
app/views/content_viewer/blog_page.html.erb
... ... @@ -18,6 +18,9 @@
18 18 format = inside_block.visualization_format
19 19 paginate = false
20 20 end
21   - (blog.empty? ? content_tag('em', _('(no posts)')) : list_posts(posts, format, paginate))
  21 + (blog.empty? ?
  22 + content_tag('em', _('(no posts)')) :
  23 + list_posts(posts, format: format, paginate: paginate)
  24 + )
22 25 %>
23 26 </div>
... ...
public/stylesheets/application.css
... ... @@ -1501,6 +1501,14 @@ a.comment-picture {
1501 1501 #content .title {
1502 1502 margin-bottom: 2px;
1503 1503 }
  1504 +.blog-post .post-pic {
  1505 + background-position: 50% 40%;
  1506 + background-size: cover;
  1507 + height: 150px;
  1508 +}
  1509 +.blog-post .post-pic.empty {
  1510 + display: none;
  1511 +}
1504 1512 .metadata, .blog-post .metadata {
1505 1513 display: block;
1506 1514 text-align: center;
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -780,6 +780,20 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
780 780 assert_no_tag :tag => 'div', :attributes => { :class => 'short-post'}, :content => /Anything/
781 781 end
782 782  
  783 + should 'show only first paragraph with picture of posts if visualization_format is short+pic' do
  784 + login_as(profile.identifier)
  785 +
  786 + blog = Blog.create!(:name => 'A blog test', :profile => profile, :visualization_format => 'short+pic')
  787 +
  788 + blog.posts << TinyMceArticle.create!(:name => 'first post', :parent => blog, :profile => profile, :body => '<p>Content to be displayed.</p> <img src="pic.jpg">')
  789 +
  790 + get :view_page, :profile => profile.identifier, :page => blog.path
  791 +
  792 + assert_select '.blog-post .post-pic' do |el|
  793 + assert_match /background-image:url\(pic.jpg\)/, el.to_s
  794 + end
  795 + end
  796 +
783 797 should 'display link to edit blog for allowed' do
784 798 blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog')
785 799 login_as(profile.identifier)
... ...
test/unit/article_test.rb
... ... @@ -1715,6 +1715,18 @@ class ArticleTest &lt; ActiveSupport::TestCase
1715 1715 assert_equal 'bar.png', a.first_image
1716 1716 end
1717 1717  
  1718 + should 'get first image from having_image' do
  1719 + a = fast_create(Article,
  1720 + :body => '<p>Foo</p><p><img src="bar.png" /></p>',
  1721 + :abstract => '<p>Lead</p><p><img src="lead.png" /></p>'
  1722 + )
  1723 + img = {}
  1724 + img.expects(:present?).returns true
  1725 + img.expects(:public_filename).returns 'pic.jpg'
  1726 + a.expects(:image).at_least_once.returns img
  1727 + assert_equal 'pic.jpg', a.first_image
  1728 + end
  1729 +
1718 1730 should 'not get first image from anywhere' do
1719 1731 a = fast_create(Article, :body => '<p>Foo</p><p>Bar</p>')
1720 1732 assert_equal '', a.first_image
... ...
test/unit/blog_helper_test.rb
... ... @@ -20,30 +20,36 @@ class BlogHelperTest &lt; ActionView::TestCase
20 20 def _(s); s; end
21 21 def h(s); s; end
22 22  
23   - should 'list published posts with class blog-post' do
24   - blog.children << published_post = create(TextileArticle, :name => 'Post', :profile => profile, :parent => blog, :published => true)
25   -
26   - expects(:display_post).with(anything, anything).returns('POST')
27   - expects(:content_tag).with('div', "POST<br style=\"clear:both\"/>", :class => 'blog-post position-1 first last odd-post-inner', :id => "post-#{published_post.id}").returns('POST')
28   - expects(:content_tag).with('div', 'POST', {:class => 'odd-post'}).returns('RESULT')
29   -
30   - assert_equal 'RESULT', list_posts(blog.posts)
31   - end
32   -
33   - should 'list even/odd posts with a different class' do
34   - blog.children << older_post = create(TextileArticle, :name => 'First post', :profile => profile, :parent => blog, :published => true)
35   -
36   - blog.children << newer_post = create(TextileArticle, :name => 'Second post', :profile => profile, :parent => blog, :published => true)
37   -
38   - expects(:display_post).with(anything, anything).returns('POST').times(2)
39   -
40   - expects(:content_tag).with('div', "POST<br style=\"clear:both\"/>", :class => 'blog-post position-1 first odd-post-inner', :id => "post-#{newer_post.id}").returns('POST 1')
41   - expects(:content_tag).with('div', "POST 1", :class => 'odd-post').returns('ODD-POST')
42   -
43   - expects(:content_tag).with('div', "POST<br style=\"clear:both\"/>", :class => 'blog-post position-2 last even-post-inner', :id => "post-#{older_post.id}").returns('POST 2')
44   - expects(:content_tag).with('div', "POST 2", :class => 'even-post').returns('EVEN-POST')
45   -
46   - assert_equal "ODD-POST\n<hr class='sep-posts'/>\nEVEN-POST", list_posts(blog.posts)
  23 + should 'list blog posts with identifiers and classes' do
  24 + blog.children << older_post = create(TextileArticle, :name => 'First post',
  25 + :profile => profile, :parent => blog, :published => true)
  26 + blog.children << some_post = create(TextileArticle, :name => 'Some post',
  27 + :profile => profile, :parent => blog, :published => true)
  28 + blog.children << hidden_post = create(TextileArticle, :name => 'Hidden post',
  29 + :profile => profile, :parent => blog, :published => false)
  30 + blog.children << newer_post = create(TextileArticle, :name => 'Last post',
  31 + :profile => profile, :parent => blog, :published => true)
  32 +
  33 + def content_tag(tag, content_or_options_with_block = nil, options = nil, &block)
  34 + if block_given?
  35 + options = content_or_options_with_block
  36 + content = block.call
  37 + else
  38 + content = content_or_options_with_block
  39 + end
  40 + options ||= {}
  41 + "<#{tag}#{options.map{|k,v| " #{k}=\"#{[v].flatten.join(' ')}\""}.join}>#{content}</#{tag}>"
  42 + end
  43 +
  44 + html = HTML::Document.new(list_posts(blog.posts)).root
  45 + assert_select html, "div#post-#{newer_post.id}.blog-post.position-1.first.odd-post" +
  46 + " > div.odd-post-inner.blog-post-inner > .title", 'Last post'
  47 + assert_select html, "div#post-#{hidden_post.id}.blog-post.position-2.not-published.even-post" +
  48 + " > div.even-post-inner.blog-post-inner > .title", 'Hidden post'
  49 + assert_select html, "div#post-#{some_post.id}.blog-post.position-3.odd-post" +
  50 + " > div.odd-post-inner.blog-post-inner > .title", 'Some post'
  51 + assert_select html, "div#post-#{older_post.id}.blog-post.position-4.last.even-post" +
  52 + " > div.even-post-inner.blog-post-inner > .title", 'First post'
47 53 end
48 54  
49 55  
... ...