Commit fe596c845d2dc4bbf2b3ef355077abfec5436408
Exists in
master
and in
29 other branches
Merge branch 'post-pic' into 'next'
Improve blog posts listing A help for armengeless themes. See merge request !543
Showing
9 changed files
with
97 additions
and
39 deletions
Show diff stats
app/helpers/blog_helper.rb
@@ -17,28 +17,28 @@ module BlogHelper | @@ -17,28 +17,28 @@ module BlogHelper | ||
17 | _('Configure blog') | 17 | _('Configure blog') |
18 | end | 18 | end |
19 | 19 | ||
20 | - def list_posts(articles, format = 'full', paginate = true) | 20 | + def list_posts(articles, conf = { format: 'full', paginate: true }) |
21 | pagination = will_paginate(articles, { | 21 | pagination = will_paginate(articles, { |
22 | :param_name => 'npage', | 22 | :param_name => 'npage', |
23 | :previous_label => _('« Newer posts'), | 23 | :previous_label => _('« Newer posts'), |
24 | :next_label => _('Older posts »'), | 24 | :next_label => _('Older posts »'), |
25 | :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"} | 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 | content = [] | 27 | content = [] |
28 | artic_len = articles.length | 28 | artic_len = articles.length |
29 | articles.each_with_index{ |art,i| | 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 | position = (i%2 == 0) ? 'odd-post' : 'even-post' | 31 | position = (i%2 == 0) ? 'odd-post' : 'even-post' |
32 | css_add << 'first' if i == 0 | 32 | css_add << 'first' if i == 0 |
33 | css_add << 'last' if i == (artic_len-1) | 33 | css_add << 'last' if i == (artic_len-1) |
34 | css_add << 'not-published' if !art.published? | 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 | content.join("\n<hr class='sep-posts'/>\n") + (pagination or '') | 43 | content.join("\n<hr class='sep-posts'/>\n") + (pagination or '') |
44 | end | 44 | end |
@@ -46,7 +46,16 @@ module BlogHelper | @@ -46,7 +46,16 @@ module BlogHelper | ||
46 | def display_post(article, format = 'full') | 46 | def display_post(article, format = 'full') |
47 | no_comments = (format == 'full') ? false : true | 47 | no_comments = (format == 'full') ? false : true |
48 | title = article_title(article, :no_comments => no_comments) | 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 | title + html | 59 | title + html |
51 | end | 60 | end |
52 | 61 |
app/models/article.rb
@@ -769,7 +769,9 @@ class Article < ActiveRecord::Base | @@ -769,7 +769,9 @@ class Article < ActiveRecord::Base | ||
769 | end | 769 | end |
770 | 770 | ||
771 | def first_image | 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 | img.nil? ? '' : img['src'] | 775 | img.nil? ? '' : img['src'] |
774 | end | 776 | end |
775 | 777 |
app/models/blog.rb
@@ -76,7 +76,7 @@ class Blog < Folder | @@ -76,7 +76,7 @@ class Blog < Folder | ||
76 | end | 76 | end |
77 | 77 | ||
78 | settings_items :visualization_format, :type => :string, :default => 'full' | 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 | settings_items :display_posts_in_current_language, :type => :boolean, :default => false | 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,7 +64,11 @@ | ||
64 | <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%> | 64 | <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%> |
65 | <% end %> | 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 | <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %> | 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,6 +18,9 @@ | ||
18 | format = inside_block.visualization_format | 18 | format = inside_block.visualization_format |
19 | paginate = false | 19 | paginate = false |
20 | end | 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 | </div> | 26 | </div> |
public/stylesheets/application.css
@@ -1501,6 +1501,14 @@ a.comment-picture { | @@ -1501,6 +1501,14 @@ a.comment-picture { | ||
1501 | #content .title { | 1501 | #content .title { |
1502 | margin-bottom: 2px; | 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 | .metadata, .blog-post .metadata { | 1512 | .metadata, .blog-post .metadata { |
1505 | display: block; | 1513 | display: block; |
1506 | text-align: center; | 1514 | text-align: center; |
test/functional/content_viewer_controller_test.rb
@@ -780,6 +780,20 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -780,6 +780,20 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
780 | assert_no_tag :tag => 'div', :attributes => { :class => 'short-post'}, :content => /Anything/ | 780 | assert_no_tag :tag => 'div', :attributes => { :class => 'short-post'}, :content => /Anything/ |
781 | end | 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 | should 'display link to edit blog for allowed' do | 797 | should 'display link to edit blog for allowed' do |
784 | blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog') | 798 | blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog') |
785 | login_as(profile.identifier) | 799 | login_as(profile.identifier) |
test/unit/article_test.rb
@@ -1715,6 +1715,18 @@ class ArticleTest < ActiveSupport::TestCase | @@ -1715,6 +1715,18 @@ class ArticleTest < ActiveSupport::TestCase | ||
1715 | assert_equal 'bar.png', a.first_image | 1715 | assert_equal 'bar.png', a.first_image |
1716 | end | 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 | should 'not get first image from anywhere' do | 1730 | should 'not get first image from anywhere' do |
1719 | a = fast_create(Article, :body => '<p>Foo</p><p>Bar</p>') | 1731 | a = fast_create(Article, :body => '<p>Foo</p><p>Bar</p>') |
1720 | assert_equal '', a.first_image | 1732 | assert_equal '', a.first_image |
test/unit/blog_helper_test.rb
@@ -20,30 +20,36 @@ class BlogHelperTest < ActionView::TestCase | @@ -20,30 +20,36 @@ class BlogHelperTest < ActionView::TestCase | ||
20 | def _(s); s; end | 20 | def _(s); s; end |
21 | def h(s); s; end | 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 | end | 53 | end |
48 | 54 | ||
49 | 55 |