Commit d7f514c234162fb6fbed0648c89d453897fdc2a9
Exists in
master
and in
29 other branches
Merge branch 'AI2888-context_block' of /mnt/ebs/repositories/participa/noosfero
Showing
15 changed files
with
638 additions
and
16 deletions
Show diff stats
app/models/article.rb
@@ -288,6 +288,11 @@ class Article < ActiveRecord::Base | @@ -288,6 +288,11 @@ class Article < ActiveRecord::Base | ||
288 | 'text-html' | 288 | 'text-html' |
289 | end | 289 | end |
290 | 290 | ||
291 | + # TODO Migrate the class method icon_name to instance methods. | ||
292 | + def icon_name | ||
293 | + self.class.icon_name(self) | ||
294 | + end | ||
295 | + | ||
291 | def mime_type | 296 | def mime_type |
292 | 'text/html' | 297 | 'text/html' |
293 | end | 298 | end |
@@ -350,22 +355,6 @@ class Article < ActiveRecord::Base | @@ -350,22 +355,6 @@ class Article < ActiveRecord::Base | ||
350 | true | 355 | true |
351 | end | 356 | end |
352 | 357 | ||
353 | - def folder? | ||
354 | - false | ||
355 | - end | ||
356 | - | ||
357 | - def blog? | ||
358 | - false | ||
359 | - end | ||
360 | - | ||
361 | - def forum? | ||
362 | - false | ||
363 | - end | ||
364 | - | ||
365 | - def uploaded_file? | ||
366 | - false | ||
367 | - end | ||
368 | - | ||
369 | def has_posts? | 358 | def has_posts? |
370 | false | 359 | false |
371 | end | 360 | end |
@@ -464,6 +453,7 @@ class Article < ActiveRecord::Base | @@ -464,6 +453,7 @@ class Article < ActiveRecord::Base | ||
464 | named_scope :galleries, :conditions => { :type => 'Gallery' } | 453 | named_scope :galleries, :conditions => { :type => 'Gallery' } |
465 | named_scope :images, :conditions => { :is_image => true } | 454 | named_scope :images, :conditions => { :is_image => true } |
466 | named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] | 455 | named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] |
456 | + named_scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } } | ||
467 | 457 | ||
468 | named_scope :more_popular, :order => 'hits DESC' | 458 | named_scope :more_popular, :order => 'hits DESC' |
469 | named_scope :more_comments, :order => "comments_count DESC" | 459 | named_scope :more_comments, :order => "comments_count DESC" |
@@ -596,6 +586,22 @@ class Article < ActiveRecord::Base | @@ -596,6 +586,22 @@ class Article < ActiveRecord::Base | ||
596 | false | 586 | false |
597 | end | 587 | end |
598 | 588 | ||
589 | + def folder? | ||
590 | + false | ||
591 | + end | ||
592 | + | ||
593 | + def blog? | ||
594 | + false | ||
595 | + end | ||
596 | + | ||
597 | + def forum? | ||
598 | + false | ||
599 | + end | ||
600 | + | ||
601 | + def uploaded_file? | ||
602 | + false | ||
603 | + end | ||
604 | + | ||
599 | def author | 605 | def author |
600 | if versions.empty? | 606 | if versions.empty? |
601 | last_changed_by | 607 | last_changed_by |
plugins/context_content/controllers/profile/context_content_plugin_profile_controller.rb
0 → 100644
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +class ContextContentPluginProfileController < ProfileController | ||
2 | + append_view_path File.join(File.dirname(__FILE__) + '/../../views') | ||
3 | + | ||
4 | + def view_content | ||
5 | + block = Block.find(params[:id]) | ||
6 | + p = params[:page].to_i | ||
7 | + contents = block.contents(profile.articles.find(params[:article_id]), p) | ||
8 | + | ||
9 | + if contents | ||
10 | + render :update do |page| | ||
11 | + page.replace_html "context_content_#{block.id}", :file => "blocks/context_content", :locals => {:block => block, :contents => contents} | ||
12 | + page.replace_html "context_content_more_#{block.id}", :partial => 'blocks/more', :locals => {:block => block, :contents => contents, :article_id => params[:article_id] } | ||
13 | + end | ||
14 | + else | ||
15 | + render :text => "invalid page", :status => 500 | ||
16 | + end | ||
17 | + end | ||
18 | + | ||
19 | +end |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +class ContextContentPlugin < Noosfero::Plugin | ||
2 | + | ||
3 | + def self.plugin_name | ||
4 | + "Display Context Content" | ||
5 | + end | ||
6 | + | ||
7 | + def self.plugin_description | ||
8 | + _("A plugin that display content based on page context.") | ||
9 | + end | ||
10 | + | ||
11 | + def self.extra_blocks | ||
12 | + { | ||
13 | + ContextContentPlugin::ContextContentBlock => { :type => [Person, Community, Enterprise] } | ||
14 | + } | ||
15 | + end | ||
16 | + | ||
17 | + def stylesheet? | ||
18 | + true | ||
19 | + end | ||
20 | + | ||
21 | +end |
plugins/context_content/lib/context_content_plugin/context_content_block.rb
0 → 100644
@@ -0,0 +1,96 @@ | @@ -0,0 +1,96 @@ | ||
1 | +class ContextContentPlugin::ContextContentBlock < Block | ||
2 | + | ||
3 | + settings_items :show_name, :type => :boolean, :default => true | ||
4 | + settings_items :show_image, :type => :boolean, :default => true | ||
5 | + settings_items :show_parent_content, :type => :boolean, :default => true | ||
6 | + settings_items :types, :type => Array, :default => ['UploadedFile'] | ||
7 | + settings_items :limit, :type => :integer, :default => 6 | ||
8 | + | ||
9 | + alias :profile :owner | ||
10 | + | ||
11 | + include Noosfero::Plugin::HotSpot | ||
12 | + | ||
13 | + def self.description | ||
14 | + _('Display context content') | ||
15 | + end | ||
16 | + | ||
17 | + def help | ||
18 | + _('This block displays content based on context.') | ||
19 | + end | ||
20 | + | ||
21 | + def available_content_types | ||
22 | + @available_content_types ||= [UploadedFile, Event, TinyMceArticle, TextileArticle, RawHTMLArticle, Folder, Blog, Forum, Gallery, RssFeed] + plugins.dispatch(:content_types) | ||
23 | + checked_types = types.map {|t| t.constantize} | ||
24 | + checked_types + (@available_content_types - checked_types) | ||
25 | + end | ||
26 | + | ||
27 | + def first_content_types | ||
28 | + available_content_types.first(first_types_count) | ||
29 | + end | ||
30 | + | ||
31 | + def more_content_types | ||
32 | + available_content_types.drop(first_types_count) | ||
33 | + end | ||
34 | + | ||
35 | + def first_types_count | ||
36 | + [2, types.length].max | ||
37 | + end | ||
38 | + | ||
39 | + def types=(new_types) | ||
40 | + settings[:types] = new_types.reject(&:blank?) | ||
41 | + end | ||
42 | + | ||
43 | + def content_image(content) | ||
44 | + block = self | ||
45 | + lambda do | ||
46 | + if content.image? | ||
47 | + image_tag(content.public_filename(:thumb)) | ||
48 | + else | ||
49 | + extra_class = content.uploaded_file? ? "extension-#{content.extension}" : '' | ||
50 | + klasses = [content.icon_name].flatten.map{|name| 'icon-'+name}.join(' ') | ||
51 | + content_tag 'div', '', :class => "context-icon #{klasses} #{extra_class}" | ||
52 | + end | ||
53 | + end | ||
54 | + end | ||
55 | + | ||
56 | + def contents(page, p=1) | ||
57 | + return @children unless @children.blank? | ||
58 | + if page | ||
59 | + @children = page.children.with_types(types).paginate(:per_page => limit, :page => p) | ||
60 | + (@children.blank? && show_parent_content) ? contents(page.parent, p) : @children | ||
61 | + else | ||
62 | + nil | ||
63 | + end | ||
64 | + end | ||
65 | + | ||
66 | + def footer | ||
67 | + block = self | ||
68 | + lambda do | ||
69 | + contents = block.contents(@page) | ||
70 | + if contents | ||
71 | + content_tag('div', | ||
72 | + render(:partial => 'blocks/more', :locals => {:block => block, :contents => contents, :article_id => @page.id}), :id => "context_content_more_#{block.id}", :class => "more_button") | ||
73 | + else | ||
74 | + '' | ||
75 | + end | ||
76 | + end | ||
77 | + end | ||
78 | + | ||
79 | + def content(args={}) | ||
80 | + block = self | ||
81 | + lambda do | ||
82 | + contents = block.contents(@page) | ||
83 | + if !contents.blank? | ||
84 | + block_title(block.title) + content_tag('div', | ||
85 | + render(:file => 'blocks/context_content', :locals => {:block => block, :contents => contents}), :class => 'contents', :id => "context_content_#{block.id}") | ||
86 | + else | ||
87 | + '' | ||
88 | + end | ||
89 | + end | ||
90 | + end | ||
91 | + | ||
92 | + def cacheable? | ||
93 | + false | ||
94 | + end | ||
95 | + | ||
96 | +end |
@@ -0,0 +1,54 @@ | @@ -0,0 +1,54 @@ | ||
1 | +.context-content-plugin_context-content-block .contents .item img { | ||
2 | + width: 100%; | ||
3 | + max-height: 60px; | ||
4 | +} | ||
5 | + | ||
6 | +.context-content-plugin_context-content-block .contents .item .image { | ||
7 | + height: 60px; | ||
8 | +} | ||
9 | + | ||
10 | +.context-content-plugin_context-content-block .contents .item .context-icon { | ||
11 | + background-repeat: no-repeat; | ||
12 | + background-position: center; | ||
13 | + height: 100%; | ||
14 | +} | ||
15 | + | ||
16 | +.context-content-plugin_context-content-block .contents .item { | ||
17 | + width: 60px; | ||
18 | + height: 95px; | ||
19 | + display: inline-block; | ||
20 | + vertical-align: top; | ||
21 | + margin: 5px; | ||
22 | + list-style-type: none; | ||
23 | + border: 1px solid #FFF; | ||
24 | + padding: 5px; | ||
25 | +} | ||
26 | + | ||
27 | +.context-content-plugin_context-content-block .contents .item:hover { | ||
28 | + border: 1px solid #CCC; | ||
29 | + -moz-border-radius: 5px; | ||
30 | + -webkit-border-radius: 5px; | ||
31 | + background: #EEE; | ||
32 | + text-decoration: none; | ||
33 | +} | ||
34 | + | ||
35 | +.context-content-plugin_context-content-block .contents .item .name { | ||
36 | + text-align: center; | ||
37 | + font-size: 8pt; | ||
38 | + word-wrap: break-word; | ||
39 | +} | ||
40 | + | ||
41 | +.context-content-plugin_context-content-block .contents .item a { | ||
42 | + text-decoration: none; | ||
43 | +} | ||
44 | + | ||
45 | +#content .context-content-plugin_context-content-block .contents .item .icon-text-html { background-image: url(/designs/icons/default/Tango/32x32/mimetypes/text-html.png) } | ||
46 | +#content .context-content-plugin_context-content-block .contents .item .icon-application-pdf { background-image: url(/designs/icons/default/Tango/32x32/mimetypes/gnome-mime-application-pdf.png) } | ||
47 | +#content .context-content-plugin_context-content-block .contents .item .icon-application-vnd-oasis-opendocument-text { background-image: url(/designs/icons/default/Tango/32x32/mimetypes/gnome-mime-application-vnd.oasis.opendocument.text.png) } | ||
48 | +#content .context-content-plugin_context-content-block .contents .item .icon-folder { background-image: url(/designs/icons/default/Tango/32x32/places/folder.png) } | ||
49 | +#content .context-content-plugin_context-content-block .contents .item .icon-text-plain { background-image: url(/designs/icons/default/Tango/32x32/mimetypes/text-x-generic.png) } | ||
50 | +#content .context-content-plugin_context-content-block .contents .item .icon-blog { background-image: url(/designs/icons/default/mod/32x32/apps/text-editor.png) } | ||
51 | +#content .context-content-plugin_context-content-block .contents .item .icon-forum { background-image: url(/designs/icons/default/Tango/32x32/apps/system-users.png) } | ||
52 | +#content .context-content-plugin_context-content-block .contents .item .icon-gallery { background-image: url(/designs/icons/default/Tango/32x32/mimetypes/image-x-generic.png) } | ||
53 | +#content .context-content-plugin_context-content-block .contents .item .icon-rss-feed { background-image: url(/images/icons-mime/rss-feed.png) } | ||
54 | +#content .context-content-plugin_context-content-block .contents .item .icon-event { background-image: url(/designs/icons/default/Tango/32x32/mimetypes/stock_calendar.png) } |
plugins/context_content/test/functional/content_viewer_controller_test.rb
0 → 100644
@@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class ContentViewerController | ||
4 | + append_view_path File.join(File.dirname(__FILE__) + '/../../views') | ||
5 | + def rescue_action(e) | ||
6 | + raise e | ||
7 | + end | ||
8 | +end | ||
9 | + | ||
10 | +class ContentViewerControllerTest < ActionController::TestCase | ||
11 | + | ||
12 | + def setup | ||
13 | + @profile = fast_create(Community) | ||
14 | + @page = fast_create(Folder, :profile_id => @profile.id) | ||
15 | + | ||
16 | + box = Box.create!(:owner => @profile) | ||
17 | + @block = ContextContentPlugin::ContextContentBlock.new(:box => box) | ||
18 | + @block.types = ['TinyMceArticle'] | ||
19 | + @block.limit = 1 | ||
20 | + @block.save! | ||
21 | + end | ||
22 | + | ||
23 | + should 'do not display context content block if it has no contents' do | ||
24 | + get :view_page, @page.url | ||
25 | + assert_no_tag 'div', :attributes => {:id => "context_content_#{@block.id}", :class => 'contents'} | ||
26 | + assert_no_tag 'div', :attributes => {:id => "context_content_more_#{@block.id}", :class => 'more_button'} | ||
27 | + end | ||
28 | + | ||
29 | + should 'display context content block if it has contents' do | ||
30 | + article = fast_create(TinyMceArticle, :parent_id => @page.id, :profile_id => @profile.id, :name => 'article1') | ||
31 | + get :view_page, @page.url | ||
32 | + assert_tag 'div', :attributes => {:id => "context_content_#{@block.id}", :class => 'contents'} | ||
33 | + assert_no_tag 'div', :attributes => {:id => "context_content_more_#{@block.id}", :class => 'more_button'}, :descendant => {:tag => 'a'} | ||
34 | + assert_match /article1/, @response.body | ||
35 | + end | ||
36 | + | ||
37 | + should 'display context content block with pagination' do | ||
38 | + article1 = fast_create(TinyMceArticle, :parent_id => @page.id, :profile_id => @profile.id) | ||
39 | + article2 = fast_create(TinyMceArticle, :parent_id => @page.id, :profile_id => @profile.id) | ||
40 | + get :view_page, @page.url | ||
41 | + assert_tag 'div', :attributes => {:id => "context_content_#{@block.id}", :class => 'contents'} | ||
42 | + assert_tag 'div', :attributes => {:id => "context_content_more_#{@block.id}", :class => 'more_button'}, :descendant => {:tag => 'a', :attributes => {:class => 'button icon-button icon-left disabled'} } | ||
43 | + assert_tag 'div', :attributes => {:id => "context_content_more_#{@block.id}", :class => 'more_button'}, :descendant => {:tag => 'a', :attributes => {:class => 'button icon-button icon-right'} } | ||
44 | + end | ||
45 | + | ||
46 | +end |
plugins/context_content/test/functional/context_content_plugin_profile_controller_test.rb
0 → 100644
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class ContextContentPluginProfileControllerTest < ActionController::TestCase | ||
4 | + | ||
5 | + class ContextContentPluginProfileController; def rescue_action(e) raise e end; end | ||
6 | + | ||
7 | + def setup | ||
8 | + @profile = fast_create(Community) | ||
9 | + @block = ContextContentPlugin::ContextContentBlock.new | ||
10 | + @block.types = ['TinyMceArticle'] | ||
11 | + @block.limit = 1 | ||
12 | + @block.save! | ||
13 | + @page = fast_create(Folder, :profile_id => @profile.id) | ||
14 | + end | ||
15 | + | ||
16 | + should 'render response error if contents is nil' do | ||
17 | + xhr :get, :view_content, :id => @block.id, :article_id => @page.id, :page => 1, :profile => @profile.identifier | ||
18 | + assert_response 500 | ||
19 | + end | ||
20 | + | ||
21 | + should 'render error if page do not exists' do | ||
22 | + article = fast_create(TinyMceArticle, :parent_id => @page.id, :profile_id => @profile.id) | ||
23 | + xhr :get, :view_content, :id => @block.id, :article_id => @page.id, :page => 2, :profile => @profile.identifier | ||
24 | + assert_response 500 | ||
25 | + end | ||
26 | + | ||
27 | + should 'replace div with content for page passed as parameter' do | ||
28 | + article1 = fast_create(TinyMceArticle, :parent_id => @page.id, :profile_id => @profile.id, :name => 'article1') | ||
29 | + article2 = fast_create(TinyMceArticle, :parent_id => @page.id, :profile_id => @profile.id, :name => 'article2') | ||
30 | + xhr :get, :view_content, :id => @block.id, :article_id => @page.id, :page => 2, :profile => @profile.identifier | ||
31 | + assert_response :success | ||
32 | + assert_match /context_content_#{@block.id}/, @response.body | ||
33 | + assert_match /context_content_more_#{@block.id}/, @response.body | ||
34 | + assert_match /article2/, @response.body | ||
35 | + end | ||
36 | + | ||
37 | + should 'do not render pagination buttons if it has only one page' do | ||
38 | + article1 = fast_create(TinyMceArticle, :parent_id => @page.id, :profile_id => @profile.id, :name => 'article1') | ||
39 | + xhr :get, :view_content, :id => @block.id, :article_id => @page.id, :page => 2, :profile => @profile.identifier | ||
40 | + assert_no_match /context_content_more_#{@block.id}/, @response.body | ||
41 | + end | ||
42 | + | ||
43 | +end |
plugins/context_content/test/functional/profile_design_controller_test.rb
0 → 100644
@@ -0,0 +1,54 @@ | @@ -0,0 +1,54 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class ProfileDesignController | ||
4 | + append_view_path File.join(File.dirname(__FILE__) + '/../../views') | ||
5 | + def rescue_action(e) | ||
6 | + raise e | ||
7 | + end | ||
8 | +end | ||
9 | + | ||
10 | +class ProfileDesignControllerTest < ActionController::TestCase | ||
11 | + | ||
12 | + def setup | ||
13 | + Environment.delete_all | ||
14 | + @environment = Environment.create(:name => 'testenv', :is_default => true) | ||
15 | + @environment.enabled_plugins = ['ContextContentPlugin'] | ||
16 | + @environment.save! | ||
17 | + | ||
18 | + @profile = fast_create(Community, :environment_id => @environment.id) | ||
19 | + @page = fast_create(Folder, :profile_id => @profile.id) | ||
20 | + | ||
21 | + box = Box.create!(:owner => @profile) | ||
22 | + @block = ContextContentPlugin::ContextContentBlock.new(:box => box) | ||
23 | + @block.types = ['TinyMceArticle'] | ||
24 | + @block.limit = 1 | ||
25 | + @block.save! | ||
26 | + | ||
27 | + user = create_user('testinguser') | ||
28 | + @profile.add_admin(user.person) | ||
29 | + login_as(user.login) | ||
30 | + end | ||
31 | + | ||
32 | + should 'be able to edit context content block' do | ||
33 | + get :edit, :id => @block.id, :profile => @profile.identifier | ||
34 | + assert_tag :tag => 'input', :attributes => { :id => 'block_title' } | ||
35 | + assert_tag :tag => 'input', :attributes => { :id => 'block_show_image' } | ||
36 | + assert_tag :tag => 'input', :attributes => { :id => 'block_show_name' } | ||
37 | + assert_tag :tag => 'input', :attributes => { :id => 'block_show_parent_content' } | ||
38 | + assert_tag :tag => 'input', :attributes => { :id => 'block_types' } | ||
39 | + end | ||
40 | + | ||
41 | + should 'be able to save TrackListBlock' do | ||
42 | + @block.show_image = false | ||
43 | + @block.show_name = false | ||
44 | + @block.show_parent_content = false | ||
45 | + @block.save! | ||
46 | + get :edit, :id => @block.id, :profile => @profile.identifier | ||
47 | + post :save, :id => @block.id, :block => {:title => 'context', :show_image => '0', :show_name => '0', :show_parent_content => '0', :types => ['TinyMceArticle', '', nil, 'Folder'] }, :profile => @profile.identifier | ||
48 | + @block.reload | ||
49 | + assert_equal 'context', @block.title | ||
50 | + assert !@block.show_image && !@block.show_name && !@block.show_parent_content | ||
51 | + assert_equal ['TinyMceArticle', 'Folder'], @block.types | ||
52 | + end | ||
53 | + | ||
54 | +end |
plugins/context_content/test/unit/context_content_block_test.rb
0 → 100644
@@ -0,0 +1,181 @@ | @@ -0,0 +1,181 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class ContextContentBlockTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([]) | ||
7 | + @block = ContextContentPlugin::ContextContentBlock.create! | ||
8 | + @block.types = ['TinyMceArticle'] | ||
9 | + end | ||
10 | + | ||
11 | + should 'describe itself' do | ||
12 | + assert_not_equal Block.description, ContextContentPlugin::ContextContentBlock.description | ||
13 | + end | ||
14 | + | ||
15 | + should 'has a help' do | ||
16 | + assert @block.help | ||
17 | + end | ||
18 | + | ||
19 | + should 'return nothing if page is nil' do | ||
20 | + assert_equal nil, @block.contents(nil) | ||
21 | + end | ||
22 | + | ||
23 | + should 'render nothing if it has no content to show' do | ||
24 | + assert_equal '', instance_eval(&@block.content) | ||
25 | + end | ||
26 | + | ||
27 | + should 'render context content block view' do | ||
28 | + @page = fast_create(Folder) | ||
29 | + article = fast_create(TinyMceArticle, :parent_id => @page.id) | ||
30 | + expects(:block_title).with(@block.title).returns('').once | ||
31 | + expects(:content_tag).returns('').once | ||
32 | + expects(:render).with(:file => 'blocks/context_content', :locals => {:block => @block, :contents => [article]}) | ||
33 | + instance_eval(&@block.content) | ||
34 | + end | ||
35 | + | ||
36 | + should 'return children of page' do | ||
37 | + folder = fast_create(Folder) | ||
38 | + article = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
39 | + assert_equal [article], @block.contents(folder) | ||
40 | + end | ||
41 | + | ||
42 | + should 'limit number of children to display' do | ||
43 | + @block.limit = 2 | ||
44 | + folder = fast_create(Folder) | ||
45 | + article1 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
46 | + article2 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
47 | + article3 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
48 | + assert_equal 2, @block.contents(folder).length | ||
49 | + end | ||
50 | + | ||
51 | + should 'show contents for next page' do | ||
52 | + @block.limit = 2 | ||
53 | + folder = fast_create(Folder) | ||
54 | + article1 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
55 | + article2 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
56 | + article3 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
57 | + assert_equal [article3], @block.contents(folder, 2) | ||
58 | + end | ||
59 | + | ||
60 | + should 'show parent contents for next page' do | ||
61 | + @block.limit = 2 | ||
62 | + folder = fast_create(Folder) | ||
63 | + article1 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
64 | + article2 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
65 | + article3 = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
66 | + assert_equal [article3], @block.contents(article1, 2) | ||
67 | + end | ||
68 | + | ||
69 | + should 'return parent children if page has no children' do | ||
70 | + folder = fast_create(Folder) | ||
71 | + article = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
72 | + assert_equal [article], @block.contents(article) | ||
73 | + end | ||
74 | + | ||
75 | + should 'do not return parent children if show_parent_content is false' do | ||
76 | + @block.show_parent_content = false | ||
77 | + folder = fast_create(Folder) | ||
78 | + article = fast_create(TinyMceArticle, :parent_id => folder.id) | ||
79 | + assert_equal [], @block.contents(article) | ||
80 | + end | ||
81 | + | ||
82 | + should 'return nil if a page has no parent' do | ||
83 | + folder = fast_create(Folder) | ||
84 | + assert_equal nil, @block.contents(folder) | ||
85 | + end | ||
86 | + | ||
87 | + should 'return available content types with checked types first' do | ||
88 | + @block.types = ['TinyMceArticle', 'Folder'] | ||
89 | + assert_equal [TinyMceArticle, Folder, UploadedFile, Event, TextileArticle, RawHTMLArticle, Blog, Forum, Gallery, RssFeed], @block.available_content_types | ||
90 | + end | ||
91 | + | ||
92 | + should 'return available content types' do | ||
93 | + @block.types = [] | ||
94 | + assert_equal [UploadedFile, Event, TinyMceArticle, TextileArticle, RawHTMLArticle, Folder, Blog, Forum, Gallery, RssFeed], @block.available_content_types | ||
95 | + end | ||
96 | + | ||
97 | + should 'return first 2 content types' do | ||
98 | + assert_equal 2, @block.first_content_types.length | ||
99 | + end | ||
100 | + | ||
101 | + should 'return all but first 2 content types' do | ||
102 | + assert_equal @block.available_content_types.length - 2, @block.more_content_types.length | ||
103 | + end | ||
104 | + | ||
105 | + should 'return 2 as default value for first_types_count' do | ||
106 | + assert_equal 2, @block.first_types_count | ||
107 | + end | ||
108 | + | ||
109 | + should 'return types length if it has more than 2 selected types' do | ||
110 | + @block.types = ['UploadedFile', 'Event', 'Folder'] | ||
111 | + assert_equal 3, @block.first_types_count | ||
112 | + end | ||
113 | + | ||
114 | + should 'return selected types at first_content_types' do | ||
115 | + @block.types = ['UploadedFile', 'Event', 'Folder'] | ||
116 | + assert_equal [UploadedFile, Event, Folder], @block.first_content_types | ||
117 | + assert_equal @block.available_content_types - [UploadedFile, Event, Folder], @block.more_content_types | ||
118 | + end | ||
119 | + | ||
120 | + should 'include plugin content at available content types' do | ||
121 | + class SomePluginContent;end | ||
122 | + class SomePlugin; def content_types; SomePluginContent end end | ||
123 | + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([SomePlugin.new]) | ||
124 | + | ||
125 | + @block.types = [] | ||
126 | + assert_equal [UploadedFile, Event, TinyMceArticle, TextileArticle, RawHTMLArticle, Folder, Blog, Forum, Gallery, RssFeed, SomePluginContent], @block.available_content_types | ||
127 | + end | ||
128 | + | ||
129 | + should 'display thumbnail for image content' do | ||
130 | + content = UploadedFile.new(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | ||
131 | + content = FilePresenter.for(content) | ||
132 | + expects(:image_tag).once | ||
133 | + instance_eval(&@block.content_image(content)) | ||
134 | + end | ||
135 | + | ||
136 | + should 'display div as content image for content that is not a image' do | ||
137 | + content = fast_create(Folder) | ||
138 | + content = FilePresenter.for(content) | ||
139 | + expects(:content_tag).once | ||
140 | + instance_eval(&@block.content_image(content)) | ||
141 | + end | ||
142 | + | ||
143 | + should 'display div with extension class for uploaded file that is not a image' do | ||
144 | + content = UploadedFile.new(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain')) | ||
145 | + content = FilePresenter.for(content) | ||
146 | + expects(:content_tag).with('div', '', :class => "context-icon icon-text icon-text-plain extension-txt").once | ||
147 | + instance_eval(&@block.content_image(content)) | ||
148 | + end | ||
149 | + | ||
150 | + should 'do not display pagination links if page is nil' do | ||
151 | + @page = nil | ||
152 | + assert_equal '', instance_eval(&@block.footer) | ||
153 | + end | ||
154 | + | ||
155 | + should 'do not display pagination links if it has until one page' do | ||
156 | + assert_equal '', instance_eval(&@block.footer) | ||
157 | + end | ||
158 | + | ||
159 | + should 'display pagination links if it has more than one page' do | ||
160 | + @block.limit = 2 | ||
161 | + @page = fast_create(Folder) | ||
162 | + article1 = fast_create(TinyMceArticle, :parent_id => @page.id) | ||
163 | + article2 = fast_create(TinyMceArticle, :parent_id => @page.id) | ||
164 | + article3 = fast_create(TinyMceArticle, :parent_id => @page.id) | ||
165 | + expects(:content_tag).once | ||
166 | + expects(:render).with(:partial => 'blocks/more', :locals => {:block => @block, :contents => [article1, article2], :article_id => @page.id}).once | ||
167 | + instance_eval(&@block.footer) | ||
168 | + end | ||
169 | + | ||
170 | + should 'return box owner on profile method call' do | ||
171 | + profile = fast_create(Community) | ||
172 | + box = Box.create(:owner_type => 'Profile', :owner_id => profile.id) | ||
173 | + block = ContextContentPlugin::ContextContentBlock.create!(:box => box) | ||
174 | + assert_equal profile, block.profile | ||
175 | + end | ||
176 | + | ||
177 | + should 'not be cacheable' do | ||
178 | + assert !@block.cacheable? | ||
179 | + end | ||
180 | + | ||
181 | +end |
plugins/context_content/test/unit/context_content_plugin_test.rb
0 → 100644
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class ContextContentPluginTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + include Noosfero::Plugin::HotSpot | ||
6 | + | ||
7 | + def setup | ||
8 | + @environment = fast_create(Environment) | ||
9 | + @environment.enable_plugin(ContextContentPlugin) | ||
10 | + end | ||
11 | + | ||
12 | + attr_reader :environment | ||
13 | + | ||
14 | + should 'has a name' do | ||
15 | + assert_not_equal Noosfero::Plugin.plugin_name, ContextContentPlugin.plugin_name | ||
16 | + end | ||
17 | + | ||
18 | + should 'describe itself' do | ||
19 | + assert_not_equal Noosfero::Plugin.plugin_description, ContextContentPlugin.plugin_description | ||
20 | + end | ||
21 | + | ||
22 | + should 'return ContextContentBlock in extra_blocks class method' do | ||
23 | + assert ContextContentPlugin.extra_blocks.keys.include?(ContextContentPlugin::ContextContentBlock) | ||
24 | + end | ||
25 | + | ||
26 | + should 'return false for class method has_admin_url?' do | ||
27 | + assert !ContextContentPlugin.has_admin_url? | ||
28 | + end | ||
29 | + | ||
30 | + should 'ContextContentBlock not available for environment' do | ||
31 | + assert_not_includes plugins.dispatch(:extra_blocks, :type => Environment), ContextContentPlugin::ContextContentBlock | ||
32 | + end | ||
33 | + | ||
34 | + should 'ContextContentBlock available for community' do | ||
35 | + assert_includes plugins.dispatch(:extra_blocks, :type => Community), ContextContentPlugin::ContextContentBlock | ||
36 | + end | ||
37 | + | ||
38 | + should 'has stylesheet' do | ||
39 | + assert ContextContentPlugin.new.stylesheet? | ||
40 | + end | ||
41 | + | ||
42 | + [Person, Community, Enterprise].each do |klass| | ||
43 | + should "ContextContentBlock be available for #{klass.name}" do | ||
44 | + assert_includes plugins.dispatch(:extra_blocks, :type => klass), ContextContentPlugin::ContextContentBlock | ||
45 | + end | ||
46 | + end | ||
47 | + | ||
48 | +end |
@@ -0,0 +1,4 @@ | @@ -0,0 +1,4 @@ | ||
1 | +<% if contents.total_pages > 1 %> | ||
2 | + <%= link_to_remote(nil, :url => {:id => block.id, :controller => 'context_content_plugin_profile', :action => 'view_content', :page => contents.previous_page, :article_id => article_id }, :html => {:class => "button icon-button icon-left #{contents.previous_page ? '':'disabled'}".strip}, :condition => "#{!contents.previous_page.nil?}", :success => "jQuery('#context_content_#{block.id}').effect('slide', {direction: 'left'});" )%> | ||
3 | + <%= link_to_remote(nil, :url => {:id => block.id, :controller => 'context_content_plugin_profile', :action => 'view_content', :page => contents.next_page, :article_id => article_id }, :html => {:class => "button icon-button icon-right #{contents.next_page ? '':'disabled'}".strip}, :condition => "#{!contents.next_page.nil?}", :success => "jQuery('#context_content_#{block.id}').effect('slide', {direction: 'right'});" )%> | ||
4 | +<% end %> |
plugins/context_content/views/blocks/context_content.rhtml
0 → 100644
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +<% contents.each do |content| %> | ||
2 | + <% content = FilePresenter.for(content) %> | ||
3 | + <span class="item"> | ||
4 | + <a href="<%= url_for(content.view_url) %>"> | ||
5 | + <div class="image"> | ||
6 | + <%= instance_eval(&block.content_image(content)) if block.show_image %> | ||
7 | + </div> | ||
8 | + <% if block.show_name %> | ||
9 | + <div class="name"><%= short_filename(content.name, 30) %></div> | ||
10 | + <% end %> | ||
11 | + </a> | ||
12 | + </span> | ||
13 | +<% end %> |
plugins/context_content/views/box_organizer/context_content_plugin/_context_content_block.rhtml
0 → 100644
@@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
1 | +<div id='edit-context-content-block'> | ||
2 | + <%= labelled_form_field _('Limit of items'), text_field(:block, :limit, :size => 3) %> | ||
3 | + <%= labelled_form_field check_box(:block, :show_name) + _('Show content name'), '' %> | ||
4 | + <%= labelled_form_field check_box(:block, :show_image) + _('Show content image'), '' %> | ||
5 | + <%= labelled_form_field check_box(:block, :show_parent_content) + _('Show parent content when children is empty'), '' %> | ||
6 | + | ||
7 | + <br/> | ||
8 | + <%= label :block, :types, _('Display content types:'), :class => 'formlabel' %> | ||
9 | + <div class="content_types"> | ||
10 | + <% @block.first_content_types.each do |type| %> | ||
11 | + <%= labelled_form_field check_box(:block, 'types', {:multiple => true}, type.name, nil) + _(type.short_description), '' %> | ||
12 | + <% end %> | ||
13 | + <% if !@block.more_content_types.empty? %> | ||
14 | + <a href="#" onclick="jQuery('.content_types .more').toggle(); return false;"><%= _('more') %></a> | ||
15 | + <% end %> | ||
16 | + <div class="more" style="display: none"> | ||
17 | + <% @block.more_content_types.each do |type| %> | ||
18 | + <%= labelled_form_field check_box(:block, 'types', {:multiple => true}, type.name, nil) + _(type.short_description), '' %> | ||
19 | + <% end %> | ||
20 | + </div> | ||
21 | + </div> | ||
22 | + <br/> | ||
23 | +</div> |
plugins/context_content/views/profile_design/context_content_plugin
0 → 120000
test/unit/article_test.rb
@@ -1773,4 +1773,17 @@ class ArticleTest < ActiveSupport::TestCase | @@ -1773,4 +1773,17 @@ class ArticleTest < ActiveSupport::TestCase | ||
1773 | end | 1773 | end |
1774 | end | 1774 | end |
1775 | 1775 | ||
1776 | + should 'return articles with specific types' do | ||
1777 | + Article.delete_all | ||
1778 | + | ||
1779 | + c1 = fast_create(TinyMceArticle, :name => 'Testing article 1', :body => 'Article body 1', :profile_id => profile.id) | ||
1780 | + c2 = fast_create(TextArticle, :name => 'Testing article 2', :body => 'Article body 2', :profile_id => profile.id) | ||
1781 | + c3 = fast_create(Event, :name => 'Testing article 3', :body => 'Article body 3', :profile_id => profile.id) | ||
1782 | + c4 = fast_create(RssFeed, :name => 'Testing article 4', :body => 'Article body 4', :profile_id => profile.id) | ||
1783 | + c5 = fast_create(TextileArticle, :name => 'Testing article 5', :body => 'Article body 5', :profile_id => profile.id) | ||
1784 | + | ||
1785 | + assert_equivalent [c1,c2], Article.with_types(['TinyMceArticle', 'TextArticle']) | ||
1786 | + assert_equivalent [c3], Article.with_types(['Event']) | ||
1787 | + end | ||
1788 | + | ||
1776 | end | 1789 | end |