Commit 1e4063df909242eb8f9dc4cd157041fd87613943

Authored by Leandro Santos
Committed by Joenio Costa
1 parent b361aebc

Create a block to make the products highlighted:

* This block must be available to Enterprises and the enterprise
  administrator could choose what products will be highlighted
* The environment could have this block and in this case the products
  are choosen randomically

(ActionItem1576)
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, HighlightsBlock ]
  6 + @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock ]
7 7 end
8 8  
9 9 end
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -24,6 +24,7 @@ class ProfileDesignController < BoxOrganizerController
24 24 if profile.enterprise?
25 25 blocks << DisabledEnterpriseMessageBlock
26 26 blocks << HighlightsBlock
  27 + blocks << FeaturedProductsBlock
27 28 end
28 29  
29 30 # product block exclusive for enterprises in environments that permits it
... ...
app/helpers/application_helper.rb
... ... @@ -960,4 +960,9 @@ module ApplicationHelper
960 960 text_field_tag(name, value, options.merge(:class => 'colorpicker_field'))
961 961 end
962 962  
  963 + # for now force currency to Brazillian format, like: "12.345,20"
  964 + def float_to_currency(price)
  965 + number_to_currency(price, :unit => 'R$', :separator => ',', :delimiter => '.')
  966 + end
  967 +
963 968 end
... ...
app/models/enterprise.rb
... ... @@ -51,6 +51,10 @@ class Enterprise &lt; Organization
51 51 environment ? environment.active_enterprise_fields : []
52 52 end
53 53  
  54 + def highlighted_products_with_image(options = {})
  55 + Product.find(:all, {:conditions => {:highlighted => true}, :joins => :image}.merge(options))
  56 + end
  57 +
54 58 def required_fields
55 59 environment ? environment.required_enterprise_fields : []
56 60 end
... ...
app/models/environment.rb
... ... @@ -628,4 +628,9 @@ class Environment &lt; ActiveRecord::Base
628 628 end
629 629 end
630 630  
  631 + def highlighted_products_with_image(options = {})
  632 + Product.find(:all, {:conditions => {:highlighted => true, :enterprise_id => self.enterprises.find(:all, :select => :id) }, :joins => :image}.merge(options))
  633 + end
  634 +
631 635 end
  636 +
... ...
app/models/featured_products_block.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +class FeaturedProductsBlock < Block
  2 +
  3 + settings_items :product_ids, :type => Array, :default => []
  4 + settings_items :groups_of, :type => :integer, :default => 3
  5 + settings_items :speed, :type => :integer, :default => 1000
  6 + settings_items :reflect, :type => :boolean, :default => true
  7 +
  8 + before_save do |block|
  9 + if block.owner.kind_of?(Environment) && block.product_ids.blank?
  10 + seed = block.owner.products.count
  11 + block.product_ids = block.owner.highlighted_products_with_image(:offset => (rand(seed) % (seed - block.groups_of * 3)), :limit => block.groups_of * 3).map(&:id)
  12 + end
  13 + block.groups_of = block.groups_of.to_i
  14 + end
  15 +
  16 + def self.description
  17 + _('Featured Products')
  18 + end
  19 +
  20 + def products
  21 + Product.find(self.product_ids) || []
  22 + end
  23 +
  24 + def products_for_selection
  25 + self.owner.highlighted_products_with_image
  26 + end
  27 +
  28 + def content
  29 + block = self
  30 + lambda do
  31 + render :file => 'blocks/featured_products', :locals => { :block => block }
  32 + end
  33 + end
  34 +
  35 +end
... ...
app/views/blocks/featured_products.rhtml 0 → 100644
... ... @@ -0,0 +1,55 @@
  1 +<%= block_title(block.title) %>
  2 +<% unless block.products.blank? %>
  3 + <%= link_to content_tag(:span, _('Previous')), '#', :class => 'featured-product-prev featured-product-arrow' %>
  4 + <div class="featured-products-block-container">
  5 + <ul class="featured-products-list">
  6 + <% block.products.in_groups_of(block.groups_of).each do |group| %>
  7 + <li class="featured-products-group">
  8 + <div class="featured-product-items">
  9 + <ul>
  10 + <% group.reject{ |x| x.nil? }.each_with_index do |p, i| %>
  11 + <li class="featured-product-item">
  12 + <%= link_to content_tag(:img, nil, :src => p.image.public_filename(:thumb), :alt => p.name, :class => ('reflect' if block.reflect)), product_path(p.enterprise.identifier, p), :class => 'featured-product-image' %>
  13 + <div class="featured-product-info position-<%= i + 1 %>" style="display: none">
  14 + <div class="featured-product-text">
  15 + <h3><%= p.name %></h3>
  16 + <p class="featured-product-price"><%= float_to_currency(p.price) %></p>
  17 + <p class="featured-product-desc"><%= p.description.chars[0...50].to_s + '...' %></p>
  18 + <p><%= link_to _('See More'), product_path(p.enterprise.identifier, p), :class => 'featured-product-link' %></p>
  19 + </div>
  20 + </div>
  21 + </li>
  22 + <% end %>
  23 + </ul>
  24 + </div>
  25 + </li>
  26 + <% end %>
  27 + </ul>
  28 + </div>
  29 + <%= link_to content_tag(:span, _('Next')), '#', :class => 'featured-product-next featured-product-arrow' %>
  30 + <script type="text/javascript">
  31 + (function($) {
  32 + var options = {
  33 + fx : 'scrollHorz',
  34 + timeout: 0,
  35 + prev: '#block-<%= block.id %> .featured-product-prev',
  36 + next: '#block-<%= block.id %> .featured-product-next',
  37 + speed: <%= block.speed || 2000 %>
  38 + }
  39 + $('#block-<%= block.id %> .featured-products-list').cycle(options);
  40 +
  41 + $(document).ready(function(){
  42 + $(".featured-product-item").hover(
  43 + function() {
  44 + $(".featured-product-info", this).fadeIn('slow');
  45 + },
  46 + function() {
  47 + $(".featured-product-info", this).fadeOut('slow');
  48 + });
  49 + });
  50 + })(jQuery);
  51 + </script>
  52 + <p class="featured-products-footer"></p>
  53 +<% else %>
  54 + <em><%= _('Please, edit this block and choose some products') %></em>
  55 +<% end %>
... ...
app/views/box_organizer/_featured_products_block.rhtml 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +<strong><%= _('Featured Products') %></strong>
  2 +<div id='edit-featured-products-block'>
  3 + <p><%= label_tag _('Choose some products') %></p>
  4 + <p><%= select_tag 'block[product_ids][]', options_for_select(@block.products_for_selection.map{|p| [p.name, p.id.to_s]}, @block.product_ids), :multiple => true %></p>
  5 + <p><%= labelled_form_field check_box(:block, :reflect) + _('Reflect products'), '' %></p>
  6 + <p><%= labelled_form_field(_('Transition speed (in seconds)'), select('block', 'speed', (1..10).to_a.collect{|i| [i, i*1000] })) %>
  7 + <p><%= labelled_form_field(_('In groups of'), select('block', 'groups_of', (1..10).to_a)) %>
  8 +</div>
... ...
app/views/layouts/_javascript.rhtml
1   -<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorpicker', 'colorpicker-noosfero', :cache => 'cache-general' %>
  1 +<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorpicker', 'colorpicker-noosfero', 'reflection', :cache => 'cache-general' %>
... ...
app/views/manage_products/_form.rhtml
... ... @@ -6,6 +6,7 @@
6 6 <%= required display_form_field( _('Name:'), f.text_field(:name) ) %>
7 7 <%= display_form_field( _('Price:'), f.text_field(:price) ) %>
8 8 <%= display_form_field( _('Description:'), f.text_area(:description, :rows => 10) ) %>
  9 + <%= labelled_form_field(f.check_box(:highlighted) + _('Highlight this product'),'') %>
9 10 <% f.fields_for :image_builder, @product.image do |i| %>
10 11 <%= file_field_or_thumbnail(_('Image:'), @product.image, i) %>
11 12 <% end %>
... ...
db/migrate/20100619031945_add_highlighted_to_product.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddHighlightedToProduct < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :products, :highlighted, :boolean
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :products, :highlighted
  8 + end
  9 +end
... ...
db/schema.rb
... ... @@ -9,7 +9,8 @@
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11  
12   -ActiveRecord::Schema.define(:version => 20100514133346) do
  12 +
  13 +ActiveRecord::Schema.define(:version => 20100619031945) do
13 14  
14 15 create_table "article_versions", :force => true do |t|
15 16 t.integer "article_id"
... ... @@ -240,6 +241,7 @@ ActiveRecord::Schema.define(:version =&gt; 20100514133346) do
240 241 t.datetime "updated_at"
241 242 t.float "lat"
242 243 t.float "lng"
  244 + t.boolean "highlighted"
243 245 end
244 246  
245 247 add_index "products", ["enterprise_id"], :name => "index_products_on_enterprise_id"
... ...
public/javascripts/reflection.js 0 → 100644
... ... @@ -0,0 +1,177 @@
  1 +/**
  2 + * reflection.js v2.0
  3 + * http://cow.neondragon.net/stuff/reflection/
  4 + * Freely distributable under MIT-style license.
  5 + */
  6 +
  7 +/* From prototype.js */
  8 +if (!document.myGetElementsByClassName) {
  9 + document.myGetElementsByClassName = function(className) {
  10 + var children = document.getElementsByTagName('*') || document.all;
  11 + var elements = new Array();
  12 +
  13 + for (var i = 0; i < children.length; i++) {
  14 + var child = children[i];
  15 + var classNames = child.className.split(' ');
  16 + for (var j = 0; j < classNames.length; j++) {
  17 + if (classNames[j] == className) {
  18 + elements.push(child);
  19 + break;
  20 + }
  21 + }
  22 + }
  23 + return elements;
  24 + }
  25 +}
  26 +
  27 +var Reflection = {
  28 + defaultHeight : 0.5,
  29 + defaultOpacity: 0.5,
  30 +
  31 + add: function(image, options) {
  32 + Reflection.remove(image);
  33 +
  34 + doptions = { "height" : Reflection.defaultHeight, "opacity" : Reflection.defaultOpacity }
  35 + if (options) {
  36 + for (var i in doptions) {
  37 + if (!options[i]) {
  38 + options[i] = doptions[i];
  39 + }
  40 + }
  41 + } else {
  42 + options = doptions;
  43 + }
  44 +
  45 + try {
  46 + var d = document.createElement('div');
  47 + var p = image;
  48 +
  49 + var classes = p.className.split(' ');
  50 + var newClasses = '';
  51 + for (j=0;j<classes.length;j++) {
  52 + if (classes[j] != "reflect") {
  53 + if (newClasses) {
  54 + newClasses += ' '
  55 + }
  56 +
  57 + newClasses += classes[j];
  58 + }
  59 + }
  60 +
  61 + var reflectionHeight = Math.floor(p.height*options['height']);
  62 + var divHeight = Math.floor(p.height*(1+options['height']));
  63 +
  64 + var reflectionWidth = p.width;
  65 +
  66 + if (document.all && !window.opera) {
  67 + /* Fix hyperlinks */
  68 + if(p.parentElement.tagName == 'A') {
  69 + var d = document.createElement('a');
  70 + d.href = p.parentElement.href;
  71 + }
  72 +
  73 + /* Copy original image's classes & styles to div */
  74 + d.className = newClasses;
  75 + p.className = 'reflected';
  76 +
  77 + d.style.cssText = p.style.cssText;
  78 + p.style.cssText = 'vertical-align: bottom';
  79 +
  80 + var reflection = document.createElement('img');
  81 + reflection.src = p.src;
  82 + reflection.style.width = reflectionWidth+'px';
  83 + reflection.style.display = 'block';
  84 + reflection.style.height = p.height+"px";
  85 +
  86 + reflection.style.marginBottom = "-"+(p.height-reflectionHeight)+'px';
  87 + reflection.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity='+(options['opacity']*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+(options['height']*100)+')';
  88 +
  89 + d.style.width = reflectionWidth+'px';
  90 + d.style.height = divHeight+'px';
  91 + p.parentNode.replaceChild(d, p);
  92 +
  93 + d.appendChild(p);
  94 + d.appendChild(reflection);
  95 + } else {
  96 + var canvas = document.createElement('canvas');
  97 + if (canvas.getContext) {
  98 + /* Copy original image's classes & styles to div */
  99 + d.className = newClasses;
  100 + p.className = 'reflected';
  101 +
  102 + d.style.cssText = p.style.cssText;
  103 + p.style.cssText = 'vertical-align: bottom';
  104 +
  105 + var context = canvas.getContext("2d");
  106 +
  107 + canvas.style.height = reflectionHeight+'px';
  108 + canvas.style.width = reflectionWidth+'px';
  109 + canvas.height = reflectionHeight;
  110 + canvas.width = reflectionWidth;
  111 +
  112 + d.style.width = reflectionWidth+'px';
  113 + d.style.height = divHeight+'px';
  114 + p.parentNode.replaceChild(d, p);
  115 +
  116 + d.appendChild(p);
  117 + d.appendChild(canvas);
  118 +
  119 + context.save();
  120 +
  121 + context.translate(0,image.height-1);
  122 + context.scale(1,-1);
  123 +
  124 + context.drawImage(image, 0, 0, reflectionWidth, image.height);
  125 +
  126 + context.restore();
  127 +
  128 + context.globalCompositeOperation = "destination-out";
  129 + var gradient = context.createLinearGradient(0, 0, 0, reflectionHeight);
  130 +
  131 + gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
  132 + gradient.addColorStop(0, "rgba(255, 255, 255, "+(1-options['opacity'])+")");
  133 +
  134 + context.fillStyle = gradient;
  135 + context.rect(0, 0, reflectionWidth, reflectionHeight*2);
  136 + context.fill();
  137 + }
  138 + }
  139 + } catch (e) {
  140 + }
  141 + },
  142 +
  143 + remove : function(image) {
  144 + if (image.className == "reflected") {
  145 + image.className = image.parentNode.className;
  146 + image.parentNode.parentNode.replaceChild(image, image.parentNode);
  147 + }
  148 + }
  149 +}
  150 +
  151 +function addReflections() {
  152 + var rimages = document.myGetElementsByClassName('reflect');
  153 + for (i=0;i<rimages.length;i++) {
  154 + var rheight = null;
  155 + var ropacity = null;
  156 +
  157 + var classes = rimages[i].className.split(' ');
  158 + for (j=0;j<classes.length;j++) {
  159 + if (classes[j].indexOf("rheight") == 0) {
  160 + var rheight = classes[j].substring(7)/100;
  161 + } else if (classes[j].indexOf("ropacity") == 0) {
  162 + var ropacity = classes[j].substring(8)/100;
  163 + }
  164 + }
  165 +
  166 + Reflection.add(rimages[i], { height: rheight, opacity : ropacity});
  167 + }
  168 +}
  169 +
  170 +if (window.addEventListener) { // DOM method for binding an event
  171 + window.addEventListener("load", addReflections, false);
  172 +} else if (window.attachEvent) { // IE exclusive method for binding an event
  173 + window.attachEvent("onload", addReflections);
  174 +} else { // Support older browsers
  175 + var previousOnload = window.onload;
  176 + window.onload = function() { if (previousOnload) previousOnload(); addReflections(); }
  177 +}
... ...
public/stylesheets/application.css
... ... @@ -3692,3 +3692,110 @@ h1#agenda-title {
3692 3692 .highlights-image-link {
3693 3693 border: 1px solid #ccc;
3694 3694 }
  3695 +
  3696 +/* Featured Products stuff */
  3697 +
  3698 +.featured-product-items {
  3699 + width: 100%;
  3700 + display: table;
  3701 + margin: 0 auto;
  3702 + text-align: center;
  3703 +}
  3704 +
  3705 +.featured-product-items ul {
  3706 + display: table-row;
  3707 +}
  3708 +
  3709 +.featured-product-item {
  3710 + list-style-type: none;
  3711 + display: table-cell !important;
  3712 +}
  3713 +
  3714 +.featured-product-item div {
  3715 + margin: 0 auto;
  3716 +}
  3717 +
  3718 +.featured-products-list {
  3719 + padding: 0;
  3720 +}
  3721 +
  3722 +.featured-product-arrow {
  3723 + float: left;
  3724 + width: 20px;
  3725 + background-repeat: no-repeat;
  3726 + height: 160px;
  3727 + background-position: center 55px;
  3728 +}
  3729 +
  3730 +.featured-product-arrow span {
  3731 + display: none;
  3732 +}
  3733 +
  3734 +.featured-product-prev {
  3735 + background-image: url(/designs/icons/tango/Tango/16x16/actions/go-previous.png);
  3736 +}
  3737 +
  3738 +.featured-product-next {
  3739 + background-image: url(/designs/icons/tango/Tango/16x16/actions/go-next.png);
  3740 +}
  3741 +
  3742 +.featured-products-block-container {
  3743 + width: 92%;
  3744 +}
  3745 +
  3746 +.box-2 .featured-products-block-container,
  3747 +.box-3 .featured-products-block-container {
  3748 + width: 78%;
  3749 +}
  3750 +
  3751 +.featured-products-group {
  3752 + width: 100%;
  3753 + margin: 0 auto;
  3754 + text-align: center;
  3755 +}
  3756 +
  3757 +.featured-product-desc {
  3758 + display: none;
  3759 +}
  3760 +
  3761 +.featured-products-block-container,
  3762 +.featured-products-group {
  3763 + overflow: hidden;
  3764 + float: left;
  3765 + height: 160px;
  3766 + position: relative;
  3767 +}
  3768 +
  3769 +.featured-products-group ul {
  3770 + padding: 0;
  3771 + padding-left: 4px;
  3772 +}
  3773 +
  3774 +.featured-products-footer {
  3775 + clear: both;
  3776 +}
  3777 +
  3778 +.featured-product-info {
  3779 + position: absolute;
  3780 + top: 0;
  3781 + z-index: 9999;
  3782 + height: 125px;
  3783 + overflow: hidden;
  3784 + font-size: 11px;
  3785 + background-color: #fff;
  3786 + opacity: 0.7;
  3787 + border: 1px solid #333;
  3788 + padding: 5px;
  3789 + text-align: left;
  3790 +}
  3791 +
  3792 +.box-2 .featured-product-info,
  3793 +.box-3 .featured-product-info {
  3794 + width: 110px;
  3795 + margin-left: 50%;
  3796 + left: -60px;
  3797 +}
  3798 +
  3799 +#content .featured-product-info h3 {
  3800 + font-size: 11px;
  3801 +}
... ...
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, HighlightsBlock ]
  9 + ALL_BLOCKS = [ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock ]
10 10  
11 11 def setup
12 12 @controller = EnvironmentDesignController.new
... ...
test/functional/profile_design_controller_test.rb
... ... @@ -10,7 +10,7 @@ class ProfileDesignControllerTest &lt; Test::Unit::TestCase
10 10 PERSON_BLOCKS_WITH_MEMBERS = PERSON_BLOCKS + [MembersBlock]
11 11 PERSON_BLOCKS_WITH_BLOG = PERSON_BLOCKS + [BlogArchivesBlock]
12 12  
13   - ENTERPRISE_BLOCKS = COMMOM_BLOCKS + [DisabledEnterpriseMessageBlock, HighlightsBlock]
  13 + ENTERPRISE_BLOCKS = COMMOM_BLOCKS + [DisabledEnterpriseMessageBlock, HighlightsBlock, FeaturedProductsBlock]
14 14 ENTERPRISE_BLOCKS_WITH_PRODUCTS_ENABLE = ENTERPRISE_BLOCKS + [ProductsBlock]
15 15  
16 16 attr_reader :holder
... ...
test/unit/application_helper_test.rb
... ... @@ -579,6 +579,11 @@ class ApplicationHelperTest &lt; Test::Unit::TestCase
579 579 assert_equal 'filename.mp3', short_filename('filename.mp3')
580 580 end
581 581  
  582 + include ActionView::Helpers::NumberHelper
  583 + should 'format float to money as Brazillian currency' do
  584 + assert_equal 'R$10,00', float_to_currency(10.0)
  585 + end
  586 +
582 587 protected
583 588  
584 589 def url_for(args = {})
... ...
test/unit/enterprise_test.rb
... ... @@ -377,4 +377,22 @@ class EnterpriseTest &lt; Test::Unit::TestCase
377 377 ent = Enterprise.create!(:name => 'test enteprise', :identifier => 'test_ent')
378 378 assert_equal 3, ent.boxes.size
379 379 end
  380 +
  381 + should 'collect the highlighted products with image' do
  382 + env = Environment.default
  383 + e1 = fast_create(Enterprise)
  384 + p1 = e1.products.create!(:name => 'test_prod1')
  385 + products = []
  386 + 3.times {|n|
  387 + products.push(Product.create!(:name => "product #{n}", :enterprise_id => e1.id, :highlighted => true, :image_builder => {
  388 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  389 + }))
  390 + }
  391 + Product.create!(:name => "product 4", :enterprise_id => e1.id, :highlighted => true)
  392 + Product.create!(:name => "product 5", :enterprise_id => e1.id, :image_builder => {
  393 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  394 + })
  395 + assert_equal products, e1.highlighted_products_with_image
  396 + end
  397 +
380 398 end
... ...
test/unit/environment_test.rb
... ... @@ -374,6 +374,23 @@ class EnvironmentTest &lt; Test::Unit::TestCase
374 374 assert_includes env.products, p1
375 375 end
376 376  
  377 + should 'collect the highlighted products with image through enterprises' do
  378 + env = Environment.default
  379 + e1 = fast_create(Enterprise)
  380 + p1 = e1.products.create!(:name => 'test_prod1')
  381 + products = []
  382 + 3.times {|n|
  383 + products.push(Product.create!(:name => "product #{n}", :enterprise_id => e1.id, :highlighted => true, :image_builder => {
  384 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  385 + }))
  386 + }
  387 + Product.create!(:name => "product 4", :enterprise_id => e1.id, :highlighted => true)
  388 + Product.create!(:name => "product 5", :enterprise_id => e1.id, :image_builder => {
  389 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  390 + })
  391 + assert_equal products, env.highlighted_products_with_image
  392 + end
  393 +
377 394 should 'not have person through communities' do
378 395 env = Environment.default
379 396 com = fast_create(Community)
... ...
test/unit/featured_products_block_test.rb 0 → 100644
... ... @@ -0,0 +1,127 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class FeaturedProductsBlockTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @profile = fast_create(Profile)
  7 + @environment = Environment.default
  8 + @environment.boxes << Box.new
  9 + end
  10 + attr_reader :profile
  11 +
  12 + should 'refer to products' do
  13 + products = []
  14 + 3.times {|n| products.push(Product.create!(:name => "product #{n}", :enterprise_id => profile.id)) }
  15 + featured_products_block = FeaturedProductsBlock.create!(:product_ids => products.map(&:id))
  16 + assert_equal products, featured_products_block.products
  17 + end
  18 +
  19 + should "have method products_for_selection" do
  20 + block = FeaturedProductsBlock.new
  21 + assert_respond_to block, 'products_for_selection'
  22 + end
  23 +
  24 + should " the defaul product_ids be an empty array" do
  25 + block = FeaturedProductsBlock.new
  26 + assert_equal [], block.product_ids
  27 + end
  28 +
  29 + should " the defaul groups_of be 3" do
  30 + block = FeaturedProductsBlock.new
  31 + assert_equal 3, block.groups_of
  32 + end
  33 +
  34 + should 'default interval between transitions is 1000 miliseconds' do
  35 + block = FeaturedProductsBlock.new
  36 + assert_equal 1000, block.speed
  37 + end
  38 +
  39 + should "reflect by default" do
  40 + block = FeaturedProductsBlock.new
  41 + assert_equal true, block.reflect
  42 + end
  43 +
  44 + should 'describe itself' do
  45 + assert_not_equal Block.description, FeaturedProductsBlock.description
  46 + end
  47 +
  48 + should "the groups_of variabe be a integer" do
  49 + block = FeaturedProductsBlock.new
  50 + assert_kind_of Integer, block.groups_of
  51 + block.groups_of = 2
  52 + block.save
  53 + block.reload
  54 + assert_kind_of Integer, block.groups_of
  55 + block.groups_of = '2'
  56 + block.save
  57 + block.reload
  58 + assert_kind_of Integer, block.groups_of
  59 + end
  60 +
  61 + should "an environment block collect product automatically" do
  62 + block = FeaturedProductsBlock.new()
  63 + block.product_ids = []
  64 + enterprise = Enterprise.create!(:name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
  65 + 3.times {|n|
  66 + Product.create!(:name => "product #{n}", :enterprise_id => enterprise.id, :highlighted => true, :image_builder => {
  67 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  68 + })
  69 + }
  70 + @environment.boxes.first.blocks<< block
  71 +
  72 + assert_not_equal [], block.product_ids
  73 + end
  74 +
  75 + should "an environment block collect just product with image automatically" do
  76 + block = FeaturedProductsBlock.new()
  77 + block.product_ids = []
  78 + enterprise = Enterprise.create!(:name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
  79 + 3.times {|n|
  80 + Product.create!(:name => "product #{n}", :enterprise_id => enterprise.id, :highlighted => true)
  81 + }
  82 + @environment.boxes.first.blocks<< block
  83 +
  84 + assert_equal [], block.product_ids
  85 + end
  86 +
  87 + should "an environment block collect just highlighted product automatically" do
  88 + block = FeaturedProductsBlock.new()
  89 + block.product_ids = []
  90 + enterprise = Enterprise.create!(:name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
  91 + 3.times {|n|
  92 + Product.create!(:name => "product #{n}", :enterprise_id => enterprise.id, :image_builder => {
  93 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  94 + })
  95 + }
  96 + @environment.boxes.first.blocks<< block
  97 +
  98 + assert_equal [], block.product_ids
  99 + end
  100 +
  101 + should 'display feature products block' do
  102 + block = FeaturedProductsBlock.new
  103 +
  104 + self.expects(:render).with(:file => 'blocks/featured_products', :locals => { :block => block})
  105 + instance_eval(& block.content)
  106 + end
  107 +
  108 + should "return just highlighted products with image for selection" do
  109 + block = FeaturedProductsBlock.new()
  110 + block.product_ids = []
  111 + enterprise = Enterprise.create!(:name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
  112 + products = []
  113 + 3.times {|n|
  114 + products.push(Product.create!(:name => "product #{n}", :enterprise_id => enterprise.id, :highlighted => true, :image_builder => {
  115 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  116 + }))
  117 + }
  118 + Product.create!(:name => "product 4", :enterprise_id => enterprise.id, :highlighted => true)
  119 + Product.create!(:name => "product 5", :enterprise_id => enterprise.id, :image_builder => {
  120 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  121 + })
  122 + @environment.boxes.first.blocks<< block
  123 +
  124 + assert_equal products, block.products_for_selection
  125 + end
  126 +
  127 +end
... ...
test/unit/highlights_block_test.rb
... ... @@ -119,12 +119,14 @@ class HighlightsBlockTest &lt; ActiveSupport::TestCase
119 119 i1 = {:image_id => 1, :address => '/address', :position => 3, :title => 'address'}
120 120 i2 = {:image_id => 2, :address => '/address', :position => 1, :title => 'address'}
121 121 i3 = {:image_id => 3, :address => '/address', :position => 2, :title => 'address'}
122   - block.images = [i1,i2,i3]
  122 + i4 = {:image_id => 4, :address => '/address', :position => 5, :title => 'address'}
  123 + i5 = {:image_id => 5, :address => '/address', :position => 4, :title => 'address'}
  124 + block.images = [i1,i2,i3,i4,i5]
123 125 block.shuffle = true
124 126 block.save!
125 127 block.reload
126   - assert_equal [i1,i2,i3], block.images
127   - assert_not_equal [i2,i3,i1], block.featured_images
  128 + assert_equal [i1,i2,i3,i4,i5], block.images
  129 + assert_not_equal [i2,i3,i1,i4,i5], block.featured_images
128 130 end
129 131  
130 132 end
... ...