Commit d9eb363116e58df526147cfdc1d529caa203484f
1 parent
6602995b
Exists in
master
and in
22 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 | 100 | end |
| 101 | 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 | 103 | protected :boxes_editor? |
| 111 | 104 | |
| 112 | 105 | end | ... | ... |
app/helpers/boxes_helper.rb
| ... | ... | @@ -59,10 +59,11 @@ module BoxesHelper |
| 59 | 59 | end |
| 60 | 60 | |
| 61 | 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 | 64 | end |
| 64 | 65 | |
| 65 | - def select_blocks(arr) | |
| 66 | + def select_blocks(arr, context) | |
| 66 | 67 | arr |
| 67 | 68 | end |
| 68 | 69 | |
| ... | ... | @@ -83,7 +84,7 @@ module BoxesHelper |
| 83 | 84 | end |
| 84 | 85 | |
| 85 | 86 | options = { |
| 86 | - :class => classes = ['block', block.css_classes ].uniq.join(' '), | |
| 87 | + :class => classes = ['block', block_css_classes(block) ].uniq.join(' '), | |
| 87 | 88 | :id => "block-#{block.id}" |
| 88 | 89 | } |
| 89 | 90 | if ( block.respond_to? 'help' ) |
| ... | ... | @@ -134,8 +135,8 @@ module BoxesHelper |
| 134 | 135 | def self.block_edit_buttons(block) |
| 135 | 136 | '' |
| 136 | 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 | 140 | end |
| 140 | 141 | end |
| 141 | 142 | |
| ... | ... | @@ -201,7 +202,6 @@ module BoxesHelper |
| 201 | 202 | end |
| 202 | 203 | |
| 203 | 204 | if !block.main? |
| 204 | - buttons << icon_button(:eyes, _('Toggle block visibility'), {:action => 'toggle_visibility', :id => block.id}) | |
| 205 | 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 | 206 | end |
| 207 | 207 | |
| ... | ... | @@ -217,8 +217,18 @@ module BoxesHelper |
| 217 | 217 | end |
| 218 | 218 | |
| 219 | 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 | 221 | stylesheet_import(@blocks_css_files, options) |
| 222 | 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 | 234 | end | ... | ... |
app/helpers/content_viewer_helper.rb
| ... | ... | @@ -13,7 +13,7 @@ module ContentViewerHelper |
| 13 | 13 | end |
| 14 | 14 | |
| 15 | 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 | 17 | title = article.title if title.blank? |
| 18 | 18 | title = content_tag('h1', title, :class => 'title') |
| 19 | 19 | if article.belongs_to_blog? |
| ... | ... | @@ -35,4 +35,9 @@ module ContentViewerHelper |
| 35 | 35 | link_to( number_of_comments(article), article.url.merge(:anchor => 'comments_list') ) |
| 36 | 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 | 43 | end | ... | ... |
app/models/block.rb
| ... | ... | @@ -11,14 +11,46 @@ class Block < ActiveRecord::Base |
| 11 | 11 | belongs_to :box |
| 12 | 12 | |
| 13 | 13 | acts_as_having_settings |
| 14 | - settings_items :visible, :type => :boolean, :default => true | |
| 15 | 14 | |
| 16 | 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 | 51 | end |
| 21 | 52 | |
| 53 | + | |
| 22 | 54 | # returns the description of the block, used when the user sees a list of |
| 23 | 55 | # blocks to choose one to include in the design. |
| 24 | 56 | # |
| ... | ... | @@ -66,16 +98,6 @@ class Block < ActiveRecord::Base |
| 66 | 98 | box ? box.owner : nil |
| 67 | 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 | 101 | def default_title |
| 80 | 102 | '' |
| 81 | 103 | end | ... | ... |
app/models/slideshow_block.rb
| ... | ... | @@ -2,9 +2,11 @@ class SlideshowBlock < Block |
| 2 | 2 | |
| 3 | 3 | settings_items :gallery_id, :type => 'integer' |
| 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 | 8 | def self.description |
| 7 | - _('Display images from gallery as slideshow') | |
| 9 | + _('Slideshow block') | |
| 8 | 10 | end |
| 9 | 11 | |
| 10 | 12 | def gallery |
| ... | ... | @@ -12,35 +14,18 @@ class SlideshowBlock < Block |
| 12 | 14 | end |
| 13 | 15 | |
| 14 | 16 | def content |
| 17 | + block = self | |
| 15 | 18 | if gallery |
| 16 | 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 | 22 | end |
| 31 | - else | |
| 32 | 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 | 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 | 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 | 29 | end |
| 45 | 30 | end |
| 46 | 31 | end | ... | ... |
app/models/uploaded_file.rb
| ... | ... | @@ -4,6 +4,13 @@ |
| 4 | 4 | # of the file itself is kept. (FIXME?) |
| 5 | 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 | 14 | def self.max_size |
| 8 | 15 | UploadedFile.attachment_options[:max_size] |
| 9 | 16 | end |
| ... | ... | @@ -74,11 +81,14 @@ class UploadedFile < Article |
| 74 | 81 | :class => 'gallery-navigation' |
| 75 | 82 | ) |
| 76 | 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 | 87 | end |
| 79 | 88 | else |
| 80 | 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 | 92 | end |
| 83 | 93 | end |
| 84 | 94 | end | ... | ... |
| ... | ... | @@ -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 | 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 | |
| 7 | 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 | 21 | <% button_bar do %> |
| 10 | 22 | <%= submit_button(:save, _('Save')) %> |
| 11 | 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 | 3 | <% if @article.image? %> |
| 3 | 4 | <%= f.text_field(:external_link, :size => 64) %> |
| 4 | 5 | <% end %> | ... | ... |
app/views/content_viewer/_uploaded_file.rhtml
| 1 | 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 | 4 | <% else %> |
| 4 | 5 | <%= render :partial => 'article', :object => uploaded_file %> |
| 5 | 6 | <% end %> |
| 6 | - | ... | ... |
app/views/content_viewer/image_gallery.rhtml
| ... | ... | @@ -8,7 +8,6 @@ |
| 8 | 8 | <% @images.each do |a| %> |
| 9 | 9 | <% content_tag('li', :title => a.abstract, :class => 'image-gallery-item' ) do %> |
| 10 | 10 | <%= render :partial => partial_for_class(a.class), :object => a %> |
| 11 | - <span><%= a.abstract && (a.abstract.first(40) + (a.abstract.size > 40 ? '…' : ''))%></span> | |
| 12 | 11 | <% end %> |
| 13 | 12 | <% end %> |
| 14 | 13 | </ul> | ... | ... |
app/views/content_viewer/view_page.rhtml
lib/tasks/release.rake
| ... | ... | @@ -10,7 +10,7 @@ namespace :noosfero do |
| 10 | 10 | end |
| 11 | 11 | |
| 12 | 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 | 14 | task :check_tag do |
| 15 | 15 | sh "git tag | grep '^#{version}$' >/dev/null" do |ok, res| |
| 16 | 16 | if ok | ... | ... |
public/designs/icons/tango/style.css
| ... | ... | @@ -64,3 +64,8 @@ |
| 64 | 64 | .icon-slideshow { background-image: url(Tango/16x16/mimetypes/x-office-presentation.png) } |
| 65 | 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
public/stylesheets/blocks/slideshow-block.css
| 1 | 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 | 14 | .slideshow-block .slideshow-container div { |
| 6 | - width: 130px; | |
| 7 | 15 | height: 130px; |
| 8 | 16 | background-position: 50% 50%; |
| 9 | 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 | 34 | .msie .slideshow-block .slideshow-container div { |
| 14 | 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 | 65 | #article .gallery-navigation .total-of-images { |
| 66 | 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 | 406 | p = create_user_full('test_user').person |
| 407 | 407 | @controller.expects(:profile).at_least_once.returns(p) |
| 408 | 408 | b = p.blocks[1] |
| 409 | - b.expects(:visible).returns(false) | |
| 409 | + b.expects(:visible?).returns(false) | |
| 410 | 410 | b.save! |
| 411 | 411 | |
| 412 | 412 | get :index, :profile => p.identifier | ... | ... |
test/functional/profile_design_controller_test.rb
| ... | ... | @@ -285,15 +285,6 @@ class ProfileDesignControllerTest < Test::Unit::TestCase |
| 285 | 285 | assert_no_tag :tag => 'input', :attributes => { :id => 'type_blogarchivesblock', :value => 'BlogArchivesBlock' } |
| 286 | 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 | 288 | should 'offer to create feed reader block' do |
| 298 | 289 | get :add_block, :profile => 'designtestuser' |
| 299 | 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 | 22 | assert_nil Block.new.owner |
| 23 | 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 | 25 | should 'provide no footer by default' do |
| 32 | 26 | assert_nil Block.new.footer |
| 33 | 27 | end |
| ... | ... | @@ -52,12 +46,18 @@ class BlockTest < Test::Unit::TestCase |
| 52 | 46 | assert_equal 'my title', b.view_title |
| 53 | 47 | end |
| 54 | 48 | |
| 55 | - should 'have a visible setting' do | |
| 49 | + should 'be backwards compatible with old "visible" setting' do | |
| 56 | 50 | b = Block.new |
| 57 | - assert b.visible? | |
| 58 | - b.visible = false | |
| 59 | - b.save | |
| 51 | + b.settings[:visible] = false | |
| 60 | 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 | 61 | end |
| 62 | 62 | |
| 63 | 63 | should 'be cacheable' do |
| ... | ... | @@ -80,4 +80,24 @@ class BlockTest < Test::Unit::TestCase |
| 80 | 80 | assert_not_includes Block.enabled, block2 |
| 81 | 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 | 103 | end | ... | ... |
test/unit/boxes_helper_test.rb
| ... | ... | @@ -41,7 +41,7 @@ class BoxesHelperTest < Test::Unit::TestCase |
| 41 | 41 | p = create_user_with_blocks |
| 42 | 42 | |
| 43 | 43 | b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] |
| 44 | - b.visible = false; b.save! | |
| 44 | + b.display = 'never'; b.save! | |
| 45 | 45 | box = b.box |
| 46 | 46 | box.expects(:blocks).returns([b]) |
| 47 | 47 | expects(:display_block).with(b, '') |
| ... | ... | @@ -55,7 +55,7 @@ class BoxesHelperTest < Test::Unit::TestCase |
| 55 | 55 | p = create_user_with_blocks |
| 56 | 56 | |
| 57 | 57 | b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] |
| 58 | - b.visible = false; b.save! | |
| 58 | + b.display = 'never'; b.save! | |
| 59 | 59 | box = b.box |
| 60 | 60 | box.expects(:blocks).returns([b]) |
| 61 | 61 | expects(:display_block).with(b, '').never |
| ... | ... | @@ -85,4 +85,13 @@ class BoxesHelperTest < Test::Unit::TestCase |
| 85 | 85 | assert_tag_in_string insert_boxes('main content'), :tag => "div", :attributes => { :id => 'profile-footer' }, :content => 'my custom footer' |
| 86 | 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 | 97 | end | ... | ... |
test/unit/slideshow_block_test.rb
| ... | ... | @@ -20,15 +20,35 @@ class SlideshowBlockTest < ActiveSupport::TestCase |
| 20 | 20 | assert_equal 4, slideshow.interval |
| 21 | 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 | 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 | 52 | end |
| 33 | 53 | |
| 34 | 54 | end | ... | ... |
test/unit/uploaded_file_test.rb
| ... | ... | @@ -113,10 +113,34 @@ class UploadedFileTest < Test::Unit::TestCase |
| 113 | 113 | p = create_user('test_user').person |
| 114 | 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 | 117 | expects(:link_to).with(file.name, file.url, :class => file.css_class_name) |
| 118 | 118 | |
| 119 | 119 | instance_eval(&file.to_html) |
| 120 | 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 | 146 | end | ... | ... |