Commit d7f514c234162fb6fbed0648c89d453897fdc2a9

Authored by Rodrigo Souto
2 parents dbd92aba 411fc108

Merge branch 'AI2888-context_block' of /mnt/ebs/repositories/participa/noosfero

app/models/article.rb
... ... @@ -288,6 +288,11 @@ class Article < ActiveRecord::Base
288 288 'text-html'
289 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 296 def mime_type
292 297 'text/html'
293 298 end
... ... @@ -350,22 +355,6 @@ class Article < ActiveRecord::Base
350 355 true
351 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 358 def has_posts?
370 359 false
371 360 end
... ... @@ -464,6 +453,7 @@ class Article < ActiveRecord::Base
464 453 named_scope :galleries, :conditions => { :type => 'Gallery' }
465 454 named_scope :images, :conditions => { :is_image => true }
466 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 458 named_scope :more_popular, :order => 'hits DESC'
469 459 named_scope :more_comments, :order => "comments_count DESC"
... ... @@ -596,6 +586,22 @@ class Article < ActiveRecord::Base
596 586 false
597 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 605 def author
600 606 if versions.empty?
601 607 last_changed_by
... ...
plugins/context_content/controllers/profile/context_content_plugin_profile_controller.rb 0 → 100644
... ... @@ -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
... ...
plugins/context_content/lib/context_content_plugin.rb 0 → 100644
... ... @@ -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 @@
  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
... ...
plugins/context_content/public/style.css 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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
... ...
plugins/context_content/views/blocks/_more.rhtml 0 → 100644
... ... @@ -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 @@
  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 @@
  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
... ... @@ -0,0 +1 @@
  1 +../box_organizer/context_content_plugin/
0 2 \ No newline at end of file
... ...
test/unit/article_test.rb
... ... @@ -1773,4 +1773,17 @@ class ArticleTest &lt; ActiveSupport::TestCase
1773 1773 end
1774 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 1789 end
... ...