Commit 553f852ef8639e0b62cb928c9fcc3a9fd72435db
Committed by
Joenio Costa
1 parent
d273adf7
Exists in
staging
and in
42 other branches
Creating a block to make some images highlighted on environment and enterprises
The user could choose which image It want to see at the moment, each image may also be associated with a link (ActionItem1564)
Showing
9 changed files
with
358 additions
and
2 deletions
Show diff stats
app/controllers/admin/environment_design_controller.rb
| ... | ... | @@ -3,7 +3,7 @@ class EnvironmentDesignController < BoxOrganizerController |
| 3 | 3 | protect 'edit_environment_design', :environment |
| 4 | 4 | |
| 5 | 5 | def available_blocks |
| 6 | - @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock ] | |
| 6 | + @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock ] | |
| 7 | 7 | end |
| 8 | 8 | |
| 9 | 9 | end | ... | ... |
app/controllers/my_profile/profile_design_controller.rb
| ... | ... | @@ -23,6 +23,7 @@ class ProfileDesignController < BoxOrganizerController |
| 23 | 23 | # blocks exclusive for enterprises |
| 24 | 24 | if profile.enterprise? |
| 25 | 25 | blocks << DisabledEnterpriseMessageBlock |
| 26 | + blocks << HighlightsBlock | |
| 26 | 27 | end |
| 27 | 28 | |
| 28 | 29 | # product block exclusive for enterprises in environments that permits it | ... | ... |
| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | +class HighlightsBlock < Block | |
| 2 | + | |
| 3 | + settings_items :images, :type => Array, :default => [] | |
| 4 | + settings_items :interval, :type => 'integer', :default => 4 | |
| 5 | + settings_items :shuffle, :type => 'boolean', :default => false | |
| 6 | + settings_items :navigation, :type => 'boolean', :default => false | |
| 7 | + | |
| 8 | + before_save do |block| | |
| 9 | + block.images = block.images.delete_if { |i| i[:image_id].blank? and i[:address].blank? and i[:position].blank? and i[:title].blank? } | |
| 10 | + block.images.each do |i| | |
| 11 | + i[:image_id] = i[:image_id].to_i | |
| 12 | + i[:position] = i[:position].to_i | |
| 13 | + begin | |
| 14 | + file = UploadedFile.find(i[:image_id]) | |
| 15 | + i[:image_src] = file.public_filename | |
| 16 | + rescue | |
| 17 | + i[:image_src] = nil | |
| 18 | + end | |
| 19 | + end | |
| 20 | + end | |
| 21 | + | |
| 22 | + def self.description | |
| 23 | + _('Highlights') | |
| 24 | + end | |
| 25 | + | |
| 26 | + def featured_images | |
| 27 | + block_images = images.select{|i| !i[:image_src].nil? }.sort { |x, y| x[:position] <=> y[:position] } | |
| 28 | + shuffle ? block_images.shuffle : block_images | |
| 29 | + end | |
| 30 | + | |
| 31 | + def content | |
| 32 | + block = self | |
| 33 | + lambda do | |
| 34 | + render :file => 'blocks/highlights', :locals => { :block => block } | |
| 35 | + end | |
| 36 | + end | |
| 37 | + | |
| 38 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | +<%= block_title(block.title) %> | |
| 2 | +<% if !block.featured_images.empty? %> | |
| 3 | + <div class='highlights-border'> | |
| 4 | + <div class='highlights-container'> | |
| 5 | + <% block.featured_images.each do |img| %> | |
| 6 | + <a href="<%= img[:address] %>" title="<%= img[:title] %>" class="highlights-image-link"> | |
| 7 | + <%= content_tag :img, nil, :src => img[:image_src], :alt => img[:title] %> | |
| 8 | + <p class="highlights-label"><%= img[:title] %></p> | |
| 9 | + </a> | |
| 10 | + <% end %> | |
| 11 | + </div> | |
| 12 | + <% if block.navigation %> | |
| 13 | + <div class='highlights-block-pager'> | |
| 14 | + </div> | |
| 15 | + <% end %> | |
| 16 | + </div> | |
| 17 | + <p class="highlights-block-footer"></p> | |
| 18 | + <script type="text/javascript"> | |
| 19 | + (function($) { | |
| 20 | + var options = {fx: 'fade', fastOnEvent: 1, timeout: <%= block.interval * 1000 %>}; | |
| 21 | + <% if block.navigation %> | |
| 22 | + options.pager = '#block-<%= block.id %> .highlights-block-pager'; | |
| 23 | + <% end %> | |
| 24 | + $('#block-<%= block.id %> .highlights-container').cycle(options); | |
| 25 | + })(jQuery); | |
| 26 | + </script> | |
| 27 | +<% else %> | |
| 28 | + <em><%= _('Please, edit this block and choose some images') %></em> | |
| 29 | +<% end %> | ... | ... |
| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | +<strong><%= _('Highlights') %></strong> | |
| 2 | +<div id='edit-highlights-block'> | |
| 3 | +<table id='highlights' class='noborder'> | |
| 4 | + <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th><th><%= _('Title') %></th></tr> | |
| 5 | + <% for image in @block.images do %> | |
| 6 | + <tr> | |
| 7 | + <td> | |
| 8 | + <%= select_tag 'block[images][][image_id]', content_tag(:option) + option_groups_from_collection_for_select(@block.box.owner.articles.select{|article| article.folder? && article.display_as_gallery? } , :images, :name, :id, :name, image[:image_id].to_i), :style => "width: 100px" %></p> | |
| 9 | + </td> | |
| 10 | + <td><%= text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 10 %></td> | |
| 11 | + <td><%= text_field_tag 'block[images][][position]', image[:position], :class => 'highlight-position', :size => 3 %></td> | |
| 12 | + <td><%= text_field_tag 'block[images][][title]', image[:title], :class => 'highlight-title', :size => 10 %></td> | |
| 13 | + </tr> | |
| 14 | + <% end %> | |
| 15 | +</table> | |
| 16 | +</div> | |
| 17 | + | |
| 18 | +<%= link_to_function(_('New highlight'), nil, :class => 'button icon-add with-text') do |page| | |
| 19 | + page.insert_html :bottom, 'highlights', content_tag('tr', | |
| 20 | + content_tag('td', select_tag('block[images][][image_id]', content_tag(:option) + option_groups_from_collection_for_select(@block.box.owner.articles.select{|article| article.folder? && article.display_as_gallery? } , :images, :name, :id, :name), :style => "width: 100px")) + | |
| 21 | + content_tag('td', text_field_tag('block[images][][address]', nil, :class => 'highlight-address', :size => 10)) + | |
| 22 | + content_tag('td', text_field_tag('block[images][][position]', nil, :class => 'highlight-position', :size => 3)) + | |
| 23 | + content_tag('td', text_field_tag('block[images][][title]', nil, :class => 'highlight-position', :size => 10)) | |
| 24 | + ) + | |
| 25 | + javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight") | |
| 26 | +end %> | |
| 27 | + | |
| 28 | +<%= labelled_form_field _('Image transition:'), select('block', 'interval', [[_('No automatic transition'), 0]] + [1, 2, 3, 4, 5, 10, 20, 30, 60].map {|item| [n_('Every 1 second', 'Every %d seconds', item) % item, item]}) %> | |
| 29 | + | |
| 30 | +<%= labelled_form_field check_box(:block, :shuffle) + _('Show images in random order'), '' %> | |
| 31 | + | |
| 32 | +<%= labelled_form_field check_box(:block, :navigation) + _('Display navigation buttons'), '' %> | ... | ... |
public/stylesheets/application.css
| ... | ... | @@ -3639,3 +3639,56 @@ h1#agenda-title { |
| 3639 | 3639 | width: 500px; |
| 3640 | 3640 | } |
| 3641 | 3641 | |
| 3642 | +/* highlights block stuff */ | |
| 3643 | + | |
| 3644 | +.highlights-block { | |
| 3645 | + float: left; | |
| 3646 | +} | |
| 3647 | + | |
| 3648 | +.highlights-block-pager { | |
| 3649 | + border: 1px solid #ccc; | |
| 3650 | + border-top: 0; | |
| 3651 | + display: inline; | |
| 3652 | + padding-right: 5px; | |
| 3653 | +} | |
| 3654 | + | |
| 3655 | +.highlights-block-pager a { | |
| 3656 | + text-decoration: none; | |
| 3657 | + margin-left: 5px; | |
| 3658 | +} | |
| 3659 | + | |
| 3660 | +.highlights-block-pager a.activeSlide:visited, | |
| 3661 | +.highlights-block-pager a.activeSlide { | |
| 3662 | + color: #000; | |
| 3663 | +} | |
| 3664 | + | |
| 3665 | +.highlights-block a, | |
| 3666 | +.highlights-block a:visited { | |
| 3667 | + text-decoration: none; | |
| 3668 | +} | |
| 3669 | + | |
| 3670 | +.highlights-image-link { | |
| 3671 | + height: 150px; | |
| 3672 | + width: 400px; | |
| 3673 | + overflow: hidden; | |
| 3674 | +} | |
| 3675 | + | |
| 3676 | +.highlights-label { | |
| 3677 | + border: 0; | |
| 3678 | + position: absolute; | |
| 3679 | + bottom: 0; | |
| 3680 | + z-index: 9999; | |
| 3681 | + background-color: #000; | |
| 3682 | + color: #fff; | |
| 3683 | + text-decoration: none; | |
| 3684 | + display: block; | |
| 3685 | + width: 100%; | |
| 3686 | + height: 30px; | |
| 3687 | + overflow: hidden; | |
| 3688 | + margin: 0; | |
| 3689 | + padding: 4px 0; | |
| 3690 | +} | |
| 3691 | + | |
| 3692 | +.highlights-image-link { | |
| 3693 | + border: 1px solid #ccc; | |
| 3694 | +} | ... | ... |
test/functional/environment_design_controller_test.rb
| ... | ... | @@ -6,7 +6,7 @@ class EnvironmentDesignController; def rescue_action(e) raise e end; end |
| 6 | 6 | |
| 7 | 7 | class EnvironmentDesignControllerTest < Test::Unit::TestCase |
| 8 | 8 | |
| 9 | - ALL_BLOCKS = [ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock ] | |
| 9 | + ALL_BLOCKS = [ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock ] | |
| 10 | 10 | |
| 11 | 11 | def setup |
| 12 | 12 | @controller = EnvironmentDesignController.new | ... | ... |
test/functional/profile_design_controller_test.rb
| ... | ... | @@ -5,6 +5,14 @@ class ProfileDesignController; def rescue_action(e) raise e end; end |
| 5 | 5 | |
| 6 | 6 | class ProfileDesignControllerTest < Test::Unit::TestCase |
| 7 | 7 | |
| 8 | + COMMOM_BLOCKS = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock] | |
| 9 | + PERSON_BLOCKS = COMMOM_BLOCKS + [FriendsBlock, FavoriteEnterprisesBlock, CommunitiesBlock, EnterprisesBlock ] | |
| 10 | + PERSON_BLOCKS_WITH_MEMBERS = PERSON_BLOCKS + [MembersBlock] | |
| 11 | + PERSON_BLOCKS_WITH_BLOG = PERSON_BLOCKS + [BlogArchivesBlock] | |
| 12 | + | |
| 13 | + ENTERPRISE_BLOCKS = COMMOM_BLOCKS + [DisabledEnterpriseMessageBlock, HighlightsBlock] | |
| 14 | + ENTERPRISE_BLOCKS_WITH_PRODUCTS_ENABLE = ENTERPRISE_BLOCKS + [ProductsBlock] | |
| 15 | + | |
| 8 | 16 | attr_reader :holder |
| 9 | 17 | def setup |
| 10 | 18 | @controller = ProfileDesignController.new |
| ... | ... | @@ -324,4 +332,69 @@ class ProfileDesignControllerTest < Test::Unit::TestCase |
| 324 | 332 | assert_tag :tag => 'div', :attributes => {:id => 'access-denied'} |
| 325 | 333 | end |
| 326 | 334 | |
| 335 | + should 'the person blocks are all available' do | |
| 336 | + profile = mock | |
| 337 | + profile.stubs(:has_members?).returns(false) | |
| 338 | + profile.stubs(:person?).returns(true) | |
| 339 | + profile.stubs(:enterprise?).returns(false) | |
| 340 | + profile.stubs(:has_blog?).returns(false) | |
| 341 | + environment = mock | |
| 342 | + profile.stubs(:environment).returns(environment) | |
| 343 | + environment.stubs(:enabled?).returns(false) | |
| 344 | + @controller.stubs(:profile).returns(profile) | |
| 345 | + assert_equal PERSON_BLOCKS, @controller.available_blocks | |
| 346 | + end | |
| 347 | + | |
| 348 | + should 'the person with members blocks are all available' do | |
| 349 | + profile = mock | |
| 350 | + profile.stubs(:has_members?).returns(true) | |
| 351 | + profile.stubs(:person?).returns(true) | |
| 352 | + profile.stubs(:enterprise?).returns(false) | |
| 353 | + profile.stubs(:has_blog?).returns(false) | |
| 354 | + environment = mock | |
| 355 | + profile.stubs(:environment).returns(environment) | |
| 356 | + environment.stubs(:enabled?).returns(false) | |
| 357 | + @controller.stubs(:profile).returns(profile) | |
| 358 | + assert_equal [], @controller.available_blocks - PERSON_BLOCKS_WITH_MEMBERS | |
| 359 | + end | |
| 360 | + | |
| 361 | + should 'the person with blog blocks are all available' do | |
| 362 | + profile = mock | |
| 363 | + profile.stubs(:has_members?).returns(false) | |
| 364 | + profile.stubs(:person?).returns(true) | |
| 365 | + profile.stubs(:enterprise?).returns(false) | |
| 366 | + profile.stubs(:has_blog?).returns(true) | |
| 367 | + environment = mock | |
| 368 | + profile.stubs(:environment).returns(environment) | |
| 369 | + environment.stubs(:enabled?).returns(false) | |
| 370 | + @controller.stubs(:profile).returns(profile) | |
| 371 | + assert_equal [], @controller.available_blocks - PERSON_BLOCKS_WITH_BLOG | |
| 372 | + end | |
| 373 | + | |
| 374 | + should 'the enterprise blocks are all available' do | |
| 375 | + profile = mock | |
| 376 | + profile.stubs(:has_members?).returns(false) | |
| 377 | + profile.stubs(:person?).returns(false) | |
| 378 | + profile.stubs(:enterprise?).returns(true) | |
| 379 | + profile.stubs(:has_blog?).returns(false) | |
| 380 | + environment = mock | |
| 381 | + profile.stubs(:environment).returns(environment) | |
| 382 | + environment.stubs(:enabled?).returns(true) | |
| 383 | + @controller.stubs(:profile).returns(profile) | |
| 384 | + assert_equal [], @controller.available_blocks - ENTERPRISE_BLOCKS | |
| 385 | + end | |
| 386 | + | |
| 387 | + should 'the enterprise with products for enterprise enable blocks are all available' do | |
| 388 | + profile = mock | |
| 389 | + profile.stubs(:has_members?).returns(false) | |
| 390 | + profile.stubs(:person?).returns(false) | |
| 391 | + profile.stubs(:enterprise?).returns(true) | |
| 392 | + profile.stubs(:has_blog?).returns(false) | |
| 393 | + environment = mock | |
| 394 | + profile.stubs(:environment).returns(environment) | |
| 395 | + environment.stubs(:enabled?).returns(false) | |
| 396 | + @controller.stubs(:profile).returns(profile) | |
| 397 | + assert_equal [], @controller.available_blocks - ENTERPRISE_BLOCKS_WITH_PRODUCTS_ENABLE | |
| 398 | + end | |
| 399 | + | |
| 327 | 400 | end | ... | ... |
| ... | ... | @@ -0,0 +1,130 @@ |
| 1 | +require File.dirname(__FILE__) + '/../test_helper' | |
| 2 | + | |
| 3 | +class HighlightsBlockTest < ActiveSupport::TestCase | |
| 4 | + | |
| 5 | + should 'default describe' do | |
| 6 | + assert_not_equal Block.description, HighlightsBlock.description | |
| 7 | + end | |
| 8 | + | |
| 9 | + should 'have field images' do | |
| 10 | + h = HighlightsBlock.new | |
| 11 | + assert_respond_to h, :images | |
| 12 | + end | |
| 13 | + | |
| 14 | + should 'have field interval' do | |
| 15 | + h = HighlightsBlock.new | |
| 16 | + assert_respond_to h, :interval | |
| 17 | + end | |
| 18 | + | |
| 19 | + should 'have field shuffle' do | |
| 20 | + h = HighlightsBlock.new | |
| 21 | + assert_respond_to h, :shuffle | |
| 22 | + end | |
| 23 | + | |
| 24 | + should 'have field navigation' do | |
| 25 | + h = HighlightsBlock.new | |
| 26 | + assert_respond_to h, :navigation | |
| 27 | + end | |
| 28 | + | |
| 29 | + should 'default value of images' do | |
| 30 | + h = HighlightsBlock.new | |
| 31 | + assert_equal [], h.images | |
| 32 | + end | |
| 33 | + | |
| 34 | + should 'default interval between transitions is 4 seconds' do | |
| 35 | + h = HighlightsBlock.new | |
| 36 | + assert_equal 4, h.interval | |
| 37 | + end | |
| 38 | + | |
| 39 | + should 'default value of shuffle' do | |
| 40 | + h = HighlightsBlock.new | |
| 41 | + assert_equal false, h.shuffle | |
| 42 | + end | |
| 43 | + | |
| 44 | + should 'default value of navigation' do | |
| 45 | + h = HighlightsBlock.new | |
| 46 | + assert_equal false, h.navigation | |
| 47 | + end | |
| 48 | + | |
| 49 | + should 'is editable' do | |
| 50 | + h = HighlightsBlock.new | |
| 51 | + assert h.editable? | |
| 52 | + end | |
| 53 | + | |
| 54 | + should 'remove images with blank fields' do | |
| 55 | + h = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => '', :position => '', :title => ''}]) | |
| 56 | + h.save! | |
| 57 | + assert_equal [{:image_id => 1, :address => '/address', :position => 1, :title => 'address', :image_src => nil}], h.images | |
| 58 | + end | |
| 59 | + | |
| 60 | + should 'be able to update display setting' do | |
| 61 | + user = create_user('testinguser').person | |
| 62 | + box = fast_create(Box, :owner_id => user.id) | |
| 63 | + block = HighlightsBlock.create!(:display => 'never', :box => box) | |
| 64 | + assert block.update_attributes!(:display => 'always') | |
| 65 | + block.reload | |
| 66 | + assert_equal 'always', block.display | |
| 67 | + end | |
| 68 | + | |
| 69 | + should 'display highlights block' do | |
| 70 | + block = HighlightsBlock.new | |
| 71 | + self.expects(:render).with(:file => 'blocks/highlights', :locals => { :block => block}) | |
| 72 | + | |
| 73 | + instance_eval(& block.content) | |
| 74 | + end | |
| 75 | + | |
| 76 | + should 'not list non existent image' do | |
| 77 | + file = mock() | |
| 78 | + UploadedFile.expects(:find).with(1).returns(file) | |
| 79 | + file.expects(:public_filename).returns('address') | |
| 80 | + block = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => 'some', :position => '2', :title => 'Some'}]) | |
| 81 | + block.save! | |
| 82 | + block.reload | |
| 83 | + assert_equal 2, block.images.count | |
| 84 | + assert_equal [{:image_id => 1, :address => '/address', :position => 1, :title => 'address', :image_src => 'address'}], block.featured_images | |
| 85 | + end | |
| 86 | + | |
| 87 | + should 'list images in order' do | |
| 88 | + f1 = mock() | |
| 89 | + f1.expects(:public_filename).returns('address') | |
| 90 | + UploadedFile.expects(:find).with(1).returns(f1) | |
| 91 | + f2 = mock() | |
| 92 | + f2.expects(:public_filename).returns('address') | |
| 93 | + UploadedFile.expects(:find).with(2).returns(f2) | |
| 94 | + f3 = mock() | |
| 95 | + f3.expects(:public_filename).returns('address') | |
| 96 | + UploadedFile.expects(:find).with(3).returns(f3) | |
| 97 | + block = HighlightsBlock.new | |
| 98 | + i1 = {:image_id => 1, :address => '/address', :position => 3, :title => 'address'} | |
| 99 | + i2 = {:image_id => 2, :address => '/address', :position => 1, :title => 'address'} | |
| 100 | + i3 = {:image_id => 3, :address => '/address', :position => 2, :title => 'address'} | |
| 101 | + block.images = [i1,i2,i3] | |
| 102 | + block.save! | |
| 103 | + block.reload | |
| 104 | + assert_equal [i1,i2,i3], block.images | |
| 105 | + assert_equal [i2,i3,i1], block.featured_images | |
| 106 | + end | |
| 107 | + | |
| 108 | + should 'list images randomically' do | |
| 109 | + f1 = mock() | |
| 110 | + f1.expects(:public_filename).returns('address') | |
| 111 | + UploadedFile.expects(:find).with(1).returns(f1) | |
| 112 | + f2 = mock() | |
| 113 | + f2.expects(:public_filename).returns('address') | |
| 114 | + UploadedFile.expects(:find).with(2).returns(f2) | |
| 115 | + f3 = mock() | |
| 116 | + f3.expects(:public_filename).returns('address') | |
| 117 | + UploadedFile.expects(:find).with(3).returns(f3) | |
| 118 | + block = HighlightsBlock.new | |
| 119 | + i1 = {:image_id => 1, :address => '/address', :position => 3, :title => 'address'} | |
| 120 | + i2 = {:image_id => 2, :address => '/address', :position => 1, :title => 'address'} | |
| 121 | + i3 = {:image_id => 3, :address => '/address', :position => 2, :title => 'address'} | |
| 122 | + block.images = [i1,i2,i3] | |
| 123 | + block.shuffle = true | |
| 124 | + block.save! | |
| 125 | + block.reload | |
| 126 | + assert_equal [i1,i2,i3], block.images | |
| 127 | + assert_not_equal [i2,i3,i1], block.featured_images | |
| 128 | + end | |
| 129 | + | |
| 130 | +end | ... | ... |