Commit d7f514c234162fb6fbed0648c89d453897fdc2a9
Exists in
master
and in
28 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 |