Commit d9eb363116e58df526147cfdc1d529caa203484f
1 parent
6602995b
Exists in
master
and in
28 other branches
Adding new features to SlideshowBlock, and blocks in general
* added option to shuffle images
* added navigation buttons
* other changes:
* Removed "toggle visibility" button and action in BoxOrganizer
Controller
* Bock#visible? now receives an optional context so that blocks can
decide where they must be shown or not
* BoxesHelper now passes the context into the Block#visible? method
* Added title to Uploaded files and displaying it instead of the
description when viewing files
(ActionItem1358)
Showing
24 changed files
with
323 additions
and
95 deletions
Show diff stats
app/controllers/box_organizer_controller.rb
| @@ -100,13 +100,6 @@ class BoxOrganizerController < ApplicationController | @@ -100,13 +100,6 @@ class BoxOrganizerController < ApplicationController | ||
| 100 | end | 100 | end |
| 101 | end | 101 | end |
| 102 | 102 | ||
| 103 | - def toggle_visibility | ||
| 104 | - @block = boxes_holder.blocks.find(params[:id]) | ||
| 105 | - @block.visible = !@block.visible? | ||
| 106 | - @block.save | ||
| 107 | - redirect_to :action => 'index' | ||
| 108 | - end | ||
| 109 | - | ||
| 110 | protected :boxes_editor? | 103 | protected :boxes_editor? |
| 111 | 104 | ||
| 112 | end | 105 | end |
app/helpers/boxes_helper.rb
| @@ -59,10 +59,11 @@ module BoxesHelper | @@ -59,10 +59,11 @@ module BoxesHelper | ||
| 59 | end | 59 | end |
| 60 | 60 | ||
| 61 | def display_box_content(box, main_content) | 61 | def display_box_content(box, main_content) |
| 62 | - box_decorator.select_blocks(box.blocks).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box) | 62 | + context = { :article => @page } |
| 63 | + box_decorator.select_blocks(box.blocks, context).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box) | ||
| 63 | end | 64 | end |
| 64 | 65 | ||
| 65 | - def select_blocks(arr) | 66 | + def select_blocks(arr, context) |
| 66 | arr | 67 | arr |
| 67 | end | 68 | end |
| 68 | 69 | ||
| @@ -83,7 +84,7 @@ module BoxesHelper | @@ -83,7 +84,7 @@ module BoxesHelper | ||
| 83 | end | 84 | end |
| 84 | 85 | ||
| 85 | options = { | 86 | options = { |
| 86 | - :class => classes = ['block', block.css_classes ].uniq.join(' '), | 87 | + :class => classes = ['block', block_css_classes(block) ].uniq.join(' '), |
| 87 | :id => "block-#{block.id}" | 88 | :id => "block-#{block.id}" |
| 88 | } | 89 | } |
| 89 | if ( block.respond_to? 'help' ) | 90 | if ( block.respond_to? 'help' ) |
| @@ -134,8 +135,8 @@ module BoxesHelper | @@ -134,8 +135,8 @@ module BoxesHelper | ||
| 134 | def self.block_edit_buttons(block) | 135 | def self.block_edit_buttons(block) |
| 135 | '' | 136 | '' |
| 136 | end | 137 | end |
| 137 | - def self.select_blocks(arr) | ||
| 138 | - arr.select(&:visible?) | 138 | + def self.select_blocks(arr, context) |
| 139 | + arr.select { |block| block.visible?(context) } | ||
| 139 | end | 140 | end |
| 140 | end | 141 | end |
| 141 | 142 | ||
| @@ -201,7 +202,6 @@ module BoxesHelper | @@ -201,7 +202,6 @@ module BoxesHelper | ||
| 201 | end | 202 | end |
| 202 | 203 | ||
| 203 | if !block.main? | 204 | if !block.main? |
| 204 | - buttons << icon_button(:eyes, _('Toggle block visibility'), {:action => 'toggle_visibility', :id => block.id}) | ||
| 205 | buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')}) | 205 | buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')}) |
| 206 | end | 206 | end |
| 207 | 207 | ||
| @@ -217,8 +217,18 @@ module BoxesHelper | @@ -217,8 +217,18 @@ module BoxesHelper | ||
| 217 | end | 217 | end |
| 218 | 218 | ||
| 219 | def import_blocks_stylesheets(options = {}) | 219 | def import_blocks_stylesheets(options = {}) |
| 220 | - @blocks_css_files ||= current_blocks.map{|b|'blocks/' + b.css_class_name}.uniq | 220 | + @blocks_css_files ||= current_blocks.map{|b|'blocks/' + block_css_class_name(b)}.uniq |
| 221 | stylesheet_import(@blocks_css_files, options) | 221 | stylesheet_import(@blocks_css_files, options) |
| 222 | end | 222 | end |
| 223 | 223 | ||
| 224 | + def block_css_class_name(block) | ||
| 225 | + block.class.name.underscore.gsub('_', '-') | ||
| 226 | + end | ||
| 227 | + def block_css_classes(block) | ||
| 228 | + classes = block_css_class_name(block) | ||
| 229 | + classes += ' invisible-block' if block.display == 'never' | ||
| 230 | + classes | ||
| 231 | + end | ||
| 232 | + | ||
| 233 | + | ||
| 224 | end | 234 | end |
app/helpers/content_viewer_helper.rb
| @@ -13,7 +13,7 @@ module ContentViewerHelper | @@ -13,7 +13,7 @@ module ContentViewerHelper | ||
| 13 | end | 13 | end |
| 14 | 14 | ||
| 15 | def article_title(article, args = {}) | 15 | def article_title(article, args = {}) |
| 16 | - title = article.abstract if article.kind_of?(UploadedFile) && article.image? | 16 | + title = article.display_title if article.kind_of?(UploadedFile) && article.image? |
| 17 | title = article.title if title.blank? | 17 | title = article.title if title.blank? |
| 18 | title = content_tag('h1', title, :class => 'title') | 18 | title = content_tag('h1', title, :class => 'title') |
| 19 | if article.belongs_to_blog? | 19 | if article.belongs_to_blog? |
| @@ -35,4 +35,9 @@ module ContentViewerHelper | @@ -35,4 +35,9 @@ module ContentViewerHelper | ||
| 35 | link_to( number_of_comments(article), article.url.merge(:anchor => 'comments_list') ) | 35 | link_to( number_of_comments(article), article.url.merge(:anchor => 'comments_list') ) |
| 36 | end | 36 | end |
| 37 | 37 | ||
| 38 | + def image_label(image) | ||
| 39 | + text = image.title || image.abstract | ||
| 40 | + text && (text.first(40) + (text.size > 40 ? '…' : '')) | ||
| 41 | + end | ||
| 42 | + | ||
| 38 | end | 43 | end |
app/models/block.rb
| @@ -11,14 +11,46 @@ class Block < ActiveRecord::Base | @@ -11,14 +11,46 @@ class Block < ActiveRecord::Base | ||
| 11 | belongs_to :box | 11 | belongs_to :box |
| 12 | 12 | ||
| 13 | acts_as_having_settings | 13 | acts_as_having_settings |
| 14 | - settings_items :visible, :type => :boolean, :default => true | ||
| 15 | 14 | ||
| 16 | named_scope :enabled, :conditions => { :enabled => true } | 15 | named_scope :enabled, :conditions => { :enabled => true } |
| 17 | 16 | ||
| 18 | - def visible? | ||
| 19 | - visible | 17 | + # Determines whether a given block must be visible. Optionally a |
| 18 | + # <tt>context</tt> must be specified. <tt>context</tt> must be a hash, and | ||
| 19 | + # may contain the following keys: | ||
| 20 | + # | ||
| 21 | + # * <tt>:article</tt>: the article being viewed currently | ||
| 22 | + def visible?(context = nil) | ||
| 23 | + if settings[:visible] == false || display == 'never' | ||
| 24 | + return false | ||
| 25 | + end | ||
| 26 | + if context && context[:article] && display == 'home_page_only' | ||
| 27 | + return context[:article] == owner.home_page | ||
| 28 | + end | ||
| 29 | + true | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | + # The condition for displaying a block. It can assume the following values: | ||
| 33 | + # | ||
| 34 | + # * <tt>'always'</tt>: the block is always displayed | ||
| 35 | + # * <tt>'never'</tt>: the block is hidden (it does not appear for visitors) | ||
| 36 | + # * <tt>'home_page_only'</tt> the block is displayed only when viewing the | ||
| 37 | + # homepage of its owner. | ||
| 38 | + def display | ||
| 39 | + if settings[:visible] == false | ||
| 40 | + 'never' | ||
| 41 | + else | ||
| 42 | + settings[:display] || 'always' | ||
| 43 | + end | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + # Sets the <tt>value</tt> attribute. | ||
| 47 | + def display=(value) | ||
| 48 | + settings[:display] = value | ||
| 49 | + # clear the old setting | ||
| 50 | + settings[:visible] = nil | ||
| 20 | end | 51 | end |
| 21 | 52 | ||
| 53 | + | ||
| 22 | # returns the description of the block, used when the user sees a list of | 54 | # returns the description of the block, used when the user sees a list of |
| 23 | # blocks to choose one to include in the design. | 55 | # blocks to choose one to include in the design. |
| 24 | # | 56 | # |
| @@ -66,16 +98,6 @@ class Block < ActiveRecord::Base | @@ -66,16 +98,6 @@ class Block < ActiveRecord::Base | ||
| 66 | box ? box.owner : nil | 98 | box ? box.owner : nil |
| 67 | end | 99 | end |
| 68 | 100 | ||
| 69 | - def css_class_name | ||
| 70 | - self.class.name.underscore.gsub('_', '-') | ||
| 71 | - end | ||
| 72 | - | ||
| 73 | - def css_classes | ||
| 74 | - classes = css_class_name | ||
| 75 | - classes += ' invisible-block' unless visible? | ||
| 76 | - classes | ||
| 77 | - end | ||
| 78 | - | ||
| 79 | def default_title | 101 | def default_title |
| 80 | '' | 102 | '' |
| 81 | end | 103 | end |
app/models/slideshow_block.rb
| @@ -2,9 +2,11 @@ class SlideshowBlock < Block | @@ -2,9 +2,11 @@ class SlideshowBlock < Block | ||
| 2 | 2 | ||
| 3 | settings_items :gallery_id, :type => 'integer' | 3 | settings_items :gallery_id, :type => 'integer' |
| 4 | settings_items :interval, :type => 'integer', :default => 4 | 4 | settings_items :interval, :type => 'integer', :default => 4 |
| 5 | + settings_items :shuffle, :type => 'boolean', :default => false | ||
| 6 | + settings_items :navigation, :type => 'boolean', :default => false | ||
| 5 | 7 | ||
| 6 | def self.description | 8 | def self.description |
| 7 | - _('Display images from gallery as slideshow') | 9 | + _('Slideshow block') |
| 8 | end | 10 | end |
| 9 | 11 | ||
| 10 | def gallery | 12 | def gallery |
| @@ -12,35 +14,18 @@ class SlideshowBlock < Block | @@ -12,35 +14,18 @@ class SlideshowBlock < Block | ||
| 12 | end | 14 | end |
| 13 | 15 | ||
| 14 | def content | 16 | def content |
| 17 | + block = self | ||
| 15 | if gallery | 18 | if gallery |
| 16 | images = gallery.images | 19 | images = gallery.images |
| 17 | - block_id = id | ||
| 18 | - block_title = title | ||
| 19 | - lambda do | ||
| 20 | - block_title(block_title) + | ||
| 21 | - content_tag('div', | ||
| 22 | - images.map do |i| | ||
| 23 | - link_to( | ||
| 24 | - content_tag('div', '', :style => "background-image: url(#{i.public_filename(:thumb)})"), | ||
| 25 | - (i.external_link || i.view_url), :target => '_blank' | ||
| 26 | - ) | ||
| 27 | - end.join("\n"), | ||
| 28 | - :class => 'slideshow-container' | ||
| 29 | - ) | 20 | + if shuffle |
| 21 | + images = images.shuffle | ||
| 30 | end | 22 | end |
| 31 | - else | ||
| 32 | lambda do | 23 | lambda do |
| 33 | - content_tag('em', _('Please select a gallery to display its images.')) | 24 | + render :file => 'blocks/slideshow', :locals => { :block => block, :images => images } |
| 34 | end | 25 | end |
| 35 | - end | ||
| 36 | - end | ||
| 37 | - | ||
| 38 | - def footer | ||
| 39 | - if gallery | ||
| 40 | - block_id = id | ||
| 41 | - interval_sec = interval * 1000 | 26 | + else |
| 42 | lambda do | 27 | lambda do |
| 43 | - javascript_tag("jQuery('#block-#{block_id} .slideshow-container').cycle({fx: 'fade', timeout: #{interval_sec}})") | 28 | + render :file => 'blocks/slideshow', :locals => { :block => block, :images => nil } |
| 44 | end | 29 | end |
| 45 | end | 30 | end |
| 46 | end | 31 | end |
app/models/uploaded_file.rb
| @@ -4,6 +4,13 @@ | @@ -4,6 +4,13 @@ | ||
| 4 | # of the file itself is kept. (FIXME?) | 4 | # of the file itself is kept. (FIXME?) |
| 5 | class UploadedFile < Article | 5 | class UploadedFile < Article |
| 6 | 6 | ||
| 7 | + settings_items :title, :type => 'string' | ||
| 8 | + validates_size_of :title, :maximum => 60, :if => (lambda { |file| !file.title.blank? }) | ||
| 9 | + | ||
| 10 | + def display_title | ||
| 11 | + title.blank? ? name : title | ||
| 12 | + end | ||
| 13 | + | ||
| 7 | def self.max_size | 14 | def self.max_size |
| 8 | UploadedFile.attachment_options[:max_size] | 15 | UploadedFile.attachment_options[:max_size] |
| 9 | end | 16 | end |
| @@ -74,11 +81,14 @@ class UploadedFile < Article | @@ -74,11 +81,14 @@ class UploadedFile < Article | ||
| 74 | :class => 'gallery-navigation' | 81 | :class => 'gallery-navigation' |
| 75 | ) | 82 | ) |
| 76 | end.to_s + | 83 | end.to_s + |
| 77 | - tag('img', :src => article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') | 84 | + tag('img', :src => article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') + |
| 85 | + content_tag('p', article.abstract, :class => 'uploaded-file-description') | ||
| 86 | + | ||
| 78 | end | 87 | end |
| 79 | else | 88 | else |
| 80 | lambda do | 89 | lambda do |
| 81 | - content_tag('ul', content_tag('li', link_to(article.name, article.url, :class => article.css_class_name))) | 90 | + content_tag('ul', content_tag('li', link_to(article.name, article.url, :class => article.css_class_name))) + |
| 91 | + content_tag('p', article.abstract, :class => 'uploaded-file-description') | ||
| 82 | end | 92 | end |
| 83 | end | 93 | end |
| 84 | end | 94 | end |
| @@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
| 1 | +<%= block_title(block.title) %> | ||
| 2 | +<% if images %> | ||
| 3 | + <% description = images.any? { |img| !img.abstract.blank? } %> | ||
| 4 | + <div class='slideshow-border<%= (description ? ' with-descriptions' : '')%>'> | ||
| 5 | + <div class='slideshow-container'> | ||
| 6 | + <% images.each do |img| %> | ||
| 7 | + <a href="<%= url_for(img.external_link.blank? ? img.view_url: img.external_link) %>"> | ||
| 8 | + <%= content_tag('div', '', :style => "background-image: url(#{img.public_filename(:thumb)})", :title => (img.abstract.blank? ? '' : img.abstract)) %> | ||
| 9 | + <% if !img.abstract.blank? %> | ||
| 10 | + <span class='image-description'><%= img.abstract %></span> | ||
| 11 | + <% end %> | ||
| 12 | + </a> | ||
| 13 | + <% end %> | ||
| 14 | + </div> | ||
| 15 | + <% if block.navigation %> | ||
| 16 | + <div class='slideshow-block-navigation'> | ||
| 17 | + <%= link_to _('Previous'), '#', :class => 'icon-media-prev' %> | ||
| 18 | + <% if block.interval > 0 %> | ||
| 19 | + <%= link_to ' ', '#', :class => 'icon-media-pause', :onclick => "togglePlayback('#block-#{block.id} .slideshow-container', this); return false;" %> | ||
| 20 | + <% end %> | ||
| 21 | + <%= link_to _('Next'), '#', :class => 'icon-media-next' %> | ||
| 22 | + </div> | ||
| 23 | + <% end %> | ||
| 24 | + </div> | ||
| 25 | + <script type="text/javascript"> | ||
| 26 | + (function($) { | ||
| 27 | + var options = {fx: 'fade', pause: 1, fastOnEvent: 1, timeout: <%= block.interval * 1000 %>}; | ||
| 28 | + <% if block.navigation %> | ||
| 29 | + options.prev = '#block-<%= block.id %> .icon-media-prev'; | ||
| 30 | + options.next = '#block-<%= block.id %> .icon-media-next'; | ||
| 31 | + <% end %> | ||
| 32 | + $('#block-<%= block.id %> .slideshow-container').cycle(options); | ||
| 33 | + })(jQuery); | ||
| 34 | + | ||
| 35 | + function togglePlayback(slideshow, button) { | ||
| 36 | + var $ = jQuery; | ||
| 37 | + if (button.className == 'icon-media-pause') { | ||
| 38 | + button.className = 'icon-media-play'; | ||
| 39 | + $(slideshow).cycle('pause'); | ||
| 40 | + } else { | ||
| 41 | + button.className = 'icon-media-pause'; | ||
| 42 | + $(slideshow).cycle('resume'); | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + </script> | ||
| 46 | +<% else %> | ||
| 47 | + <em><%= _('Please, edit this block and select an image gallery.') %></em> | ||
| 48 | +<% end %> | ||
| 49 | + |
app/views/box_organizer/_slideshow_block.rhtml
| @@ -3,4 +3,8 @@ | @@ -3,4 +3,8 @@ | ||
| 3 | [ _('%{gallery} (%{count} images)') % {:gallery => item.path, :count => item.images.count}, item.id ] | 3 | [ _('%{gallery} (%{count} images)') % {:gallery => item.path, :count => item.images.count}, item.id ] |
| 4 | }) %> | 4 | }) %> |
| 5 | 5 | ||
| 6 | -<%= labelled_form_field _('Seconds between image transitions'), select('block', 'interval', [1, 2, 3, 4, 5, 10, 20, 30, 60] ) %> | 6 | +<%= 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]}) %> |
| 7 | + | ||
| 8 | +<%= labelled_form_field check_box(:block, :shuffle) + _('Show images in random order'), '' %> | ||
| 9 | + | ||
| 10 | +<%= labelled_form_field check_box(:block, :navigation) + _('Display navigation buttons'), '' %> |
app/views/box_organizer/edit.rhtml
| @@ -6,6 +6,18 @@ | @@ -6,6 +6,18 @@ | ||
| 6 | 6 | ||
| 7 | <%= render :partial => partial_for_class(@block.class) %> | 7 | <%= render :partial => partial_for_class(@block.class) %> |
| 8 | 8 | ||
| 9 | + <%= labelled_form_field _('Display this block:'), '' %> | ||
| 10 | + <div style='margin-left: 10px'> | ||
| 11 | + <%= radio_button(:block, :display, 'always') %> | ||
| 12 | + <%= label_tag('block_display_always', _('In all pages')) %> | ||
| 13 | + <br/> | ||
| 14 | + <%= radio_button(:block, :display, 'home_page_only') %> | ||
| 15 | + <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %> | ||
| 16 | + <br/> | ||
| 17 | + <%= radio_button(:block, :display, 'never') %> | ||
| 18 | + <%= label_tag('block_display_never', _("Don't display")) %> | ||
| 19 | + </div> | ||
| 20 | + | ||
| 9 | <% button_bar do %> | 21 | <% button_bar do %> |
| 10 | <%= submit_button(:save, _('Save')) %> | 22 | <%= submit_button(:save, _('Save')) %> |
| 11 | <%= lightbox_close_button(_('Cancel')) %> | 23 | <%= lightbox_close_button(_('Cancel')) %> |
app/views/cms/_uploaded_file.rhtml
| 1 | -<%= labelled_form_field(_('Describe this file:'), text_area(:article, :abstract, :rows => 3, :cols => 64)) %> | 1 | +<%= labelled_form_field(_('Title'), text_field(:article, :title, :maxlength => 60)) %> |
| 2 | +<%= labelled_form_field(_('Description'), text_area(:article, :abstract, :rows => 3, :cols => 64)) %> | ||
| 2 | <% if @article.image? %> | 3 | <% if @article.image? %> |
| 3 | <%= f.text_field(:external_link, :size => 64) %> | 4 | <%= f.text_field(:external_link, :size => 64) %> |
| 4 | <% end %> | 5 | <% end %> |
app/views/content_viewer/_uploaded_file.rhtml
| 1 | <% if uploaded_file.image? %> | 1 | <% if uploaded_file.image? %> |
| 2 | - <div> <%= link_to image_tag(uploaded_file.public_filename(:thumb), :alt => uploaded_file.abstract), uploaded_file.view_url %> </div> | 2 | + <div> <%= link_to image_tag(uploaded_file.public_filename(:thumb), :alt => uploaded_file.display_title), uploaded_file.view_url %> </div> |
| 3 | + <span><%= image_label(uploaded_file) %></span> | ||
| 3 | <% else %> | 4 | <% else %> |
| 4 | <%= render :partial => 'article', :object => uploaded_file %> | 5 | <%= render :partial => 'article', :object => uploaded_file %> |
| 5 | <% end %> | 6 | <% end %> |
| 6 | - |
app/views/content_viewer/image_gallery.rhtml
| @@ -8,7 +8,6 @@ | @@ -8,7 +8,6 @@ | ||
| 8 | <% @images.each do |a| %> | 8 | <% @images.each do |a| %> |
| 9 | <% content_tag('li', :title => a.abstract, :class => 'image-gallery-item' ) do %> | 9 | <% content_tag('li', :title => a.abstract, :class => 'image-gallery-item' ) do %> |
| 10 | <%= render :partial => partial_for_class(a.class), :object => a %> | 10 | <%= render :partial => partial_for_class(a.class), :object => a %> |
| 11 | - <span><%= a.abstract && (a.abstract.first(40) + (a.abstract.size > 40 ? '…' : ''))%></span> | ||
| 12 | <% end %> | 11 | <% end %> |
| 13 | <% end %> | 12 | <% end %> |
| 14 | </ul> | 13 | </ul> |
app/views/content_viewer/view_page.rhtml
| @@ -19,7 +19,7 @@ | @@ -19,7 +19,7 @@ | ||
| 19 | </div> | 19 | </div> |
| 20 | <% end %> | 20 | <% end %> |
| 21 | 21 | ||
| 22 | -<div> | 22 | +<div<%= " class='logged-in'" if user %>> |
| 23 | <%= article_title(@page, :no_link => true) %> | 23 | <%= article_title(@page, :no_link => true) %> |
| 24 | <div id="article-actions"> | 24 | <div id="article-actions"> |
| 25 | <% if @page.allow_post_content?(user) %> | 25 | <% if @page.allow_post_content?(user) %> |
lib/tasks/release.rake
| @@ -10,7 +10,7 @@ namespace :noosfero do | @@ -10,7 +10,7 @@ namespace :noosfero do | ||
| 10 | end | 10 | end |
| 11 | 11 | ||
| 12 | version = Noosfero::VERSION | 12 | version = Noosfero::VERSION |
| 13 | - desc 'checks if there is already a tag for the curren version' | 13 | + desc 'checks if there is already a tag for the current version' |
| 14 | task :check_tag do | 14 | task :check_tag do |
| 15 | sh "git tag | grep '^#{version}$' >/dev/null" do |ok, res| | 15 | sh "git tag | grep '^#{version}$' >/dev/null" do |ok, res| |
| 16 | if ok | 16 | if ok |
public/designs/icons/tango/style.css
| @@ -64,3 +64,8 @@ | @@ -64,3 +64,8 @@ | ||
| 64 | .icon-slideshow { background-image: url(Tango/16x16/mimetypes/x-office-presentation.png) } | 64 | .icon-slideshow { background-image: url(Tango/16x16/mimetypes/x-office-presentation.png) } |
| 65 | .icon-photos { background-image: url(Tango/16x16/devices/camera-photo.png) } | 65 | .icon-photos { background-image: url(Tango/16x16/devices/camera-photo.png) } |
| 66 | 66 | ||
| 67 | +.icon-media-pause { background-image: url(Tango/16x16/actions/media-playback-pause.png) } | ||
| 68 | +.icon-media-play { background-image: url(Tango/16x16/actions/media-playback-start.png) } | ||
| 69 | +.icon-media-prev { background-image: url(Tango/16x16/actions/media-skip-backward.png) } | ||
| 70 | +.icon-media-next { background-image: url(Tango/16x16/actions/media-skip-forward.png) } | ||
| 71 | + |
public/designs/themes/base/article.css
| @@ -16,8 +16,12 @@ hr.pre-posts, hr.sep-posts { | @@ -16,8 +16,12 @@ hr.pre-posts, hr.sep-posts { | ||
| 16 | overflow: visible; | 16 | overflow: visible; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | +#article .logged-in h1 { | ||
| 20 | + margin-top: 25px; | ||
| 21 | +} | ||
| 22 | + | ||
| 19 | #article-actions { | 23 | #article-actions { |
| 20 | - top: -18px; | 24 | + top: -28px; |
| 21 | } | 25 | } |
| 22 | 26 | ||
| 23 | #article-actions a.button, | 27 | #article-actions a.button, |
public/stylesheets/blocks/slideshow-block.css
| 1 | .slideshow-block .slideshow-container { | 1 | .slideshow-block .slideshow-container { |
| 2 | - margin: auto; | 2 | + margin-bottom: 10px; |
| 3 | +} | ||
| 4 | + | ||
| 5 | +.slideshow-block .slideshow-container a { | ||
| 6 | + width: 100%; | ||
| 7 | + display: block; | ||
| 8 | + text-decoration: none; | ||
| 9 | +} | ||
| 10 | +.slideshow-block .slideshow-container a:hover { | ||
| 11 | + text-decoration: none; | ||
| 3 | } | 12 | } |
| 4 | 13 | ||
| 5 | .slideshow-block .slideshow-container div { | 14 | .slideshow-block .slideshow-container div { |
| 6 | - width: 130px; | ||
| 7 | height: 130px; | 15 | height: 130px; |
| 8 | background-position: 50% 50%; | 16 | background-position: 50% 50%; |
| 9 | background-repeat: no-repeat; | 17 | background-repeat: no-repeat; |
| 10 | - margin: auto; | 18 | +} |
| 19 | + | ||
| 20 | +.slideshow-block .with-descriptions { | ||
| 21 | + border: 1px solid #ddd; | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +.slideshow-block .image-description { | ||
| 25 | + display: block; | ||
| 26 | + padding: 10px; | ||
| 27 | + height: 34px; | ||
| 28 | + overflow: hidden; | ||
| 29 | + border-top: 1px solid #ddd; | ||
| 30 | + background-color: white; | ||
| 31 | + color: black; | ||
| 11 | } | 32 | } |
| 12 | 33 | ||
| 13 | .msie .slideshow-block .slideshow-container div { | 34 | .msie .slideshow-block .slideshow-container div { |
| 14 | cursor: pointer; | 35 | cursor: pointer; |
| 15 | } | 36 | } |
| 37 | + | ||
| 38 | +.slideshow-block { | ||
| 39 | + text-align: center; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +.slideshow-block .slideshow-block-navigation { | ||
| 43 | + margin: 8px 0px; | ||
| 44 | +} | ||
| 45 | +.slideshow-block .slideshow-block-navigation a { | ||
| 46 | + background-color: white; | ||
| 47 | + background-repeat: no-repeat; | ||
| 48 | + border: 1px solid #ddd; | ||
| 49 | + padding: 2px; | ||
| 50 | + text-decoration: none; | ||
| 51 | + font-variant: small-caps; | ||
| 52 | + font-size: 10px; | ||
| 53 | +} | ||
| 54 | +.slideshow-block .slideshow-block-navigation a:hover { | ||
| 55 | + text-decoration: none; | ||
| 56 | + border-color: #999; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +.slideshow-block .slideshow-block-navigation .icon-media-prev { | ||
| 60 | + padding-left: 18px; | ||
| 61 | + background-position: left; | ||
| 62 | +} | ||
| 63 | +.slideshow-block .slideshow-block-navigation .icon-media-next { | ||
| 64 | + padding-right: 18px; | ||
| 65 | + background-position: right; | ||
| 66 | + | ||
| 67 | +} | ||
| 68 | +.slideshow-block .slideshow-block-navigation .icon-media-pause, | ||
| 69 | +.slideshow-block .slideshow-block-navigation .icon-media-play { | ||
| 70 | + background-position: 50% 50%; | ||
| 71 | + display: inline-block; | ||
| 72 | + width: 16px; | ||
| 73 | +} |
public/stylesheets/controller_content_viewer.css
| @@ -65,3 +65,10 @@ div#article-parent { | @@ -65,3 +65,10 @@ div#article-parent { | ||
| 65 | #article .gallery-navigation .total-of-images { | 65 | #article .gallery-navigation .total-of-images { |
| 66 | font-weight: bold; | 66 | font-weight: bold; |
| 67 | } | 67 | } |
| 68 | + | ||
| 69 | +#article .uploaded-file-description { | ||
| 70 | + background: #f6f6f6; | ||
| 71 | + border-top: 1px solid #ccc; | ||
| 72 | + border-bottom: 1px solid #ccc; | ||
| 73 | + padding: 1em; | ||
| 74 | +} |
test/functional/application_controller_test.rb
| @@ -406,7 +406,7 @@ class ApplicationControllerTest < Test::Unit::TestCase | @@ -406,7 +406,7 @@ class ApplicationControllerTest < Test::Unit::TestCase | ||
| 406 | p = create_user_full('test_user').person | 406 | p = create_user_full('test_user').person |
| 407 | @controller.expects(:profile).at_least_once.returns(p) | 407 | @controller.expects(:profile).at_least_once.returns(p) |
| 408 | b = p.blocks[1] | 408 | b = p.blocks[1] |
| 409 | - b.expects(:visible).returns(false) | 409 | + b.expects(:visible?).returns(false) |
| 410 | b.save! | 410 | b.save! |
| 411 | 411 | ||
| 412 | get :index, :profile => p.identifier | 412 | get :index, :profile => p.identifier |
test/functional/profile_design_controller_test.rb
| @@ -285,15 +285,6 @@ class ProfileDesignControllerTest < Test::Unit::TestCase | @@ -285,15 +285,6 @@ class ProfileDesignControllerTest < Test::Unit::TestCase | ||
| 285 | assert_no_tag :tag => 'input', :attributes => { :id => 'type_blogarchivesblock', :value => 'BlogArchivesBlock' } | 285 | assert_no_tag :tag => 'input', :attributes => { :id => 'type_blogarchivesblock', :value => 'BlogArchivesBlock' } |
| 286 | end | 286 | end |
| 287 | 287 | ||
| 288 | - should 'toggle block visibility' do | ||
| 289 | - state = @b1.visible? | ||
| 290 | - get :toggle_visibility, :id => @b1.id, :profile => holder.identifier | ||
| 291 | - block = Block.find(@b1.id) | ||
| 292 | - | ||
| 293 | - assert_equal block, assigns(:block) | ||
| 294 | - assert_equal !state, block.visible? | ||
| 295 | - end | ||
| 296 | - | ||
| 297 | should 'offer to create feed reader block' do | 288 | should 'offer to create feed reader block' do |
| 298 | get :add_block, :profile => 'designtestuser' | 289 | get :add_block, :profile => 'designtestuser' |
| 299 | assert_tag :tag => 'input', :attributes => { :id => 'type_feedreaderblock', :value => 'FeedReaderBlock' } | 290 | assert_tag :tag => 'input', :attributes => { :id => 'type_feedreaderblock', :value => 'FeedReaderBlock' } |
test/unit/block_test.rb
| @@ -22,12 +22,6 @@ class BlockTest < Test::Unit::TestCase | @@ -22,12 +22,6 @@ class BlockTest < Test::Unit::TestCase | ||
| 22 | assert_nil Block.new.owner | 22 | assert_nil Block.new.owner |
| 23 | end | 23 | end |
| 24 | 24 | ||
| 25 | - should 'generate CSS class name' do | ||
| 26 | - block = Block.new | ||
| 27 | - block.class.expects(:name).returns('SomethingBlock') | ||
| 28 | - assert_equal 'something-block', block.css_class_name | ||
| 29 | - end | ||
| 30 | - | ||
| 31 | should 'provide no footer by default' do | 25 | should 'provide no footer by default' do |
| 32 | assert_nil Block.new.footer | 26 | assert_nil Block.new.footer |
| 33 | end | 27 | end |
| @@ -52,12 +46,18 @@ class BlockTest < Test::Unit::TestCase | @@ -52,12 +46,18 @@ class BlockTest < Test::Unit::TestCase | ||
| 52 | assert_equal 'my title', b.view_title | 46 | assert_equal 'my title', b.view_title |
| 53 | end | 47 | end |
| 54 | 48 | ||
| 55 | - should 'have a visible setting' do | 49 | + should 'be backwards compatible with old "visible" setting' do |
| 56 | b = Block.new | 50 | b = Block.new |
| 57 | - assert b.visible? | ||
| 58 | - b.visible = false | ||
| 59 | - b.save | 51 | + b.settings[:visible] = false |
| 60 | assert !b.visible? | 52 | assert !b.visible? |
| 53 | + assert_equal 'never', b.display | ||
| 54 | + end | ||
| 55 | + | ||
| 56 | + should 'clean old "visible setting" when display is set' do | ||
| 57 | + b = Block.new | ||
| 58 | + b.settings[:visible] = false | ||
| 59 | + b.display = 'never' | ||
| 60 | + assert_nil b.settings[:visible] | ||
| 61 | end | 61 | end |
| 62 | 62 | ||
| 63 | should 'be cacheable' do | 63 | should 'be cacheable' do |
| @@ -80,4 +80,24 @@ class BlockTest < Test::Unit::TestCase | @@ -80,4 +80,24 @@ class BlockTest < Test::Unit::TestCase | ||
| 80 | assert_not_includes Block.enabled, block2 | 80 | assert_not_includes Block.enabled, block2 |
| 81 | end | 81 | end |
| 82 | 82 | ||
| 83 | + should 'be displayed everywhere by default' do | ||
| 84 | + assert_equal true, Block.new.visible? | ||
| 85 | + end | ||
| 86 | + | ||
| 87 | + should 'not display when set to hidden' do | ||
| 88 | + assert_equal false, Block.new(:display => 'never').visible? | ||
| 89 | + assert_equal false, Block.new(:display => 'never').visible?(:article => Article.new) | ||
| 90 | + end | ||
| 91 | + | ||
| 92 | + should 'be able to be displayed only in the homepage' do | ||
| 93 | + profile = Profile.new | ||
| 94 | + home_page = Article.new | ||
| 95 | + profile.home_page = home_page | ||
| 96 | + block = Block.new(:display => 'home_page_only') | ||
| 97 | + block.stubs(:owner).returns(profile) | ||
| 98 | + | ||
| 99 | + assert_equal true, block.visible?(:article => home_page) | ||
| 100 | + assert_equal false, block.visible?(:article => Article.new) | ||
| 101 | + end | ||
| 102 | + | ||
| 83 | end | 103 | end |
test/unit/boxes_helper_test.rb
| @@ -41,7 +41,7 @@ class BoxesHelperTest < Test::Unit::TestCase | @@ -41,7 +41,7 @@ class BoxesHelperTest < Test::Unit::TestCase | ||
| 41 | p = create_user_with_blocks | 41 | p = create_user_with_blocks |
| 42 | 42 | ||
| 43 | b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] | 43 | b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] |
| 44 | - b.visible = false; b.save! | 44 | + b.display = 'never'; b.save! |
| 45 | box = b.box | 45 | box = b.box |
| 46 | box.expects(:blocks).returns([b]) | 46 | box.expects(:blocks).returns([b]) |
| 47 | expects(:display_block).with(b, '') | 47 | expects(:display_block).with(b, '') |
| @@ -55,7 +55,7 @@ class BoxesHelperTest < Test::Unit::TestCase | @@ -55,7 +55,7 @@ class BoxesHelperTest < Test::Unit::TestCase | ||
| 55 | p = create_user_with_blocks | 55 | p = create_user_with_blocks |
| 56 | 56 | ||
| 57 | b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] | 57 | b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] |
| 58 | - b.visible = false; b.save! | 58 | + b.display = 'never'; b.save! |
| 59 | box = b.box | 59 | box = b.box |
| 60 | box.expects(:blocks).returns([b]) | 60 | box.expects(:blocks).returns([b]) |
| 61 | expects(:display_block).with(b, '').never | 61 | expects(:display_block).with(b, '').never |
| @@ -85,4 +85,13 @@ class BoxesHelperTest < Test::Unit::TestCase | @@ -85,4 +85,13 @@ class BoxesHelperTest < Test::Unit::TestCase | ||
| 85 | assert_tag_in_string insert_boxes('main content'), :tag => "div", :attributes => { :id => 'profile-footer' }, :content => 'my custom footer' | 85 | assert_tag_in_string insert_boxes('main content'), :tag => "div", :attributes => { :id => 'profile-footer' }, :content => 'my custom footer' |
| 86 | end | 86 | end |
| 87 | 87 | ||
| 88 | + should 'calculate CSS class names correctly' do | ||
| 89 | + assert_equal 'slideshow-block', block_css_class_name(SlideshowBlock.new) | ||
| 90 | + assert_equal 'main-block', block_css_class_name(MainBlock.new) | ||
| 91 | + end | ||
| 92 | + | ||
| 93 | + should 'add invisible CSS class name for invisible blocks' do | ||
| 94 | + assert !block_css_classes(Block.new(:display => 'always')).split.any? { |item| item == 'invisible-block'} | ||
| 95 | + assert block_css_classes(Block.new(:display => 'never')).split.any? { |item| item == 'invisible-block'} | ||
| 96 | + end | ||
| 88 | end | 97 | end |
test/unit/slideshow_block_test.rb
| @@ -20,15 +20,35 @@ class SlideshowBlockTest < ActiveSupport::TestCase | @@ -20,15 +20,35 @@ class SlideshowBlockTest < ActiveSupport::TestCase | ||
| 20 | assert_equal 4, slideshow.interval | 20 | assert_equal 4, slideshow.interval |
| 21 | end | 21 | end |
| 22 | 22 | ||
| 23 | - should 'not invoke javascript when has no gallery' do | ||
| 24 | - slideshow_block = SlideshowBlock.new() | ||
| 25 | - assert_nil slideshow_block.footer | 23 | + should 'list in the same order' do |
| 24 | + gallery = mock | ||
| 25 | + images = [] | ||
| 26 | + images.expects(:shuffle).never | ||
| 27 | + gallery.stubs(:images).returns(images) | ||
| 28 | + | ||
| 29 | + block = SlideshowBlock.new | ||
| 30 | + block.stubs(:gallery).returns(gallery) | ||
| 31 | + block.content | ||
| 26 | end | 32 | end |
| 27 | 33 | ||
| 28 | - should 'invoke javascript when has gallery' do | ||
| 29 | - gallery = fast_create(Folder, :profile_id => profile.id) | ||
| 30 | - slideshow_block = SlideshowBlock.new(:gallery_id => gallery.id) | ||
| 31 | - assert_not_nil slideshow_block.footer | 34 | + should 'list in random order' do |
| 35 | + gallery = mock | ||
| 36 | + images = [] | ||
| 37 | + shuffled = [] | ||
| 38 | + gallery.stubs(:images).returns(images) | ||
| 39 | + images.expects(:shuffle).once.returns(shuffled) | ||
| 40 | + | ||
| 41 | + block = SlideshowBlock.new(:shuffle => true) | ||
| 42 | + block.stubs(:gallery).returns(gallery) | ||
| 43 | + block.content | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + should 'not shuffle by default' do | ||
| 47 | + assert_equal false, SlideshowBlock.new.shuffle | ||
| 48 | + end | ||
| 49 | + | ||
| 50 | + should 'not display navigation by default' do | ||
| 51 | + assert_equal false, SlideshowBlock.new.navigation | ||
| 32 | end | 52 | end |
| 33 | 53 | ||
| 34 | end | 54 | end |
test/unit/uploaded_file_test.rb
| @@ -113,10 +113,34 @@ class UploadedFileTest < Test::Unit::TestCase | @@ -113,10 +113,34 @@ class UploadedFileTest < Test::Unit::TestCase | ||
| 113 | p = create_user('test_user').person | 113 | p = create_user('test_user').person |
| 114 | file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => p) | 114 | file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => p) |
| 115 | 115 | ||
| 116 | - stubs(:content_tag) | 116 | + stubs(:content_tag).returns('link') |
| 117 | expects(:link_to).with(file.name, file.url, :class => file.css_class_name) | 117 | expects(:link_to).with(file.name, file.url, :class => file.css_class_name) |
| 118 | 118 | ||
| 119 | instance_eval(&file.to_html) | 119 | instance_eval(&file.to_html) |
| 120 | end | 120 | end |
| 121 | 121 | ||
| 122 | + should 'have title' do | ||
| 123 | + assert_equal 'my title', UploadedFile.new(:title => 'my title').title | ||
| 124 | + end | ||
| 125 | + | ||
| 126 | + should 'limit title to 140 characters' do | ||
| 127 | + upload = UploadedFile.new | ||
| 128 | + | ||
| 129 | + upload.title = '+' * 61; upload.valid? | ||
| 130 | + assert upload.errors[:title] | ||
| 131 | + | ||
| 132 | + upload.title = '+' * 60; upload.valid? | ||
| 133 | + assert !upload.errors[:title] | ||
| 134 | + | ||
| 135 | + end | ||
| 136 | + | ||
| 137 | + should 'always provide a display title' do | ||
| 138 | + upload = UploadedFile.new(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain')) | ||
| 139 | + assert_equal 'test.txt', upload.display_title | ||
| 140 | + upload.title = 'My text file' | ||
| 141 | + assert_equal 'My text file', upload.display_title | ||
| 142 | + upload.title = '' | ||
| 143 | + assert_equal 'test.txt', upload.display_title | ||
| 144 | + end | ||
| 145 | + | ||
| 122 | end | 146 | end |