Commit 364e52a3cfbc1b6a0943d99e31dba1880e1111fa

Authored by Victor Costa
2 parents d66a1bc8 4eb04441

Merge branch 'master' into production

Conflicts:
	lib/noosfero/plugin.rb
Showing 98 changed files with 1013 additions and 451 deletions   Show diff stats
app/controllers/my_profile/cms_controller.rb
... ... @@ -105,6 +105,11 @@ class CmsController < MyProfileController
105 105 end
106 106 end
107 107 end
  108 +
  109 + unless @article.kind_of?(RssFeed)
  110 + @escaped_body = CGI::escapeHTML(@article.body || '')
  111 + @escaped_abstract = CGI::escapeHTML(@article.abstract || '')
  112 + end
108 113 end
109 114  
110 115 def new
... ...
app/controllers/my_profile/manage_products_controller.rb
... ... @@ -35,7 +35,7 @@ class ManageProductsController < ApplicationController
35 35 end
36 36  
37 37 def categories_for_selection
38   - @category = Category.find(params[:category_id]) if params[:category_id]
  38 + @category = environment.categories.find_by_id params[:category_id]
39 39 @object_name = params[:object_name]
40 40 if @category
41 41 @categories = @category.children
... ... @@ -95,6 +95,20 @@ class ManageProductsController < ApplicationController
95 95 end
96 96 end
97 97  
  98 + def show_category_tree
  99 + @category = environment.categories.find params[:category_id]
  100 + render :partial => 'selected_category_tree'
  101 + end
  102 +
  103 + def search_categories
  104 + @term = params[:term].downcase
  105 + conditions = ['LOWER(name) LIKE ? OR LOWER(name) LIKE ?', "#{@term}%", "% #{@term}%"]
  106 + @categories = ProductCategory.all :conditions => conditions, :limit => 10
  107 + render :json => (@categories.map do |category|
  108 + {:label => category.name, :value => category.id}
  109 + end)
  110 + end
  111 +
98 112 def add_input
99 113 @product = @profile.products.find(params[:id])
100 114 @input = @product.inputs.build
... ...
app/controllers/my_profile/maps_controller.rb
... ... @@ -16,6 +16,7 @@ class MapsController < MyProfileController
16 16  
17 17 Profile.transaction do
18 18 if profile.update_attributes!(params[:profile_data])
  19 + BlockSweeper.expire_blocks profile.blocks.select{ |b| b.class == LocationBlock }
19 20 session[:notice] = _('Address was updated successfully!')
20 21 redirect_to :action => 'edit_location'
21 22 end
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -15,6 +15,7 @@ class ContentViewerController < ApplicationController
15 15 path = get_path(params[:page], params[:format])
16 16  
17 17 @version = params[:version].to_i
  18 + @npage = params[:npage] || '1'
18 19  
19 20 if path.blank?
20 21 @page = profile.home_page
... ... @@ -131,7 +132,7 @@ class ContentViewerController < ApplicationController
131 132 end
132 133  
133 134 unless @page.display_to?(user)
134   - if !profile.visible? || profile.secret? || (user && user.follows?(profile))
  135 + if !profile.visible? || profile.secret? || (user && user.follows?(profile)) || user.blank?
135 136 render_access_denied
136 137 else #!profile.public?
137 138 private_profile_partial_parameters
... ...
app/helpers/application_helper.rb
... ... @@ -1226,35 +1226,6 @@ module ApplicationHelper
1226 1226 list.sort.inject(Hash.new(0)){|h,i| h[i] += 1; h }.collect{ |x, n| [n, connector, x].join(" ") }.sort
1227 1227 end
1228 1228  
1229   - #FIXME Use time_ago_in_words instead of this method if you're using Rails 2.2+
1230   - def time_ago_as_sentence(from_time, include_seconds = false)
1231   - to_time = Time.now
1232   - from_time = Time.parse(from_time.to_s)
1233   - from_time = from_time.to_time if from_time.respond_to?(:to_time)
1234   - to_time = to_time.to_time if to_time.respond_to?(:to_time)
1235   - distance_in_minutes = (((to_time - from_time).abs)/60).round
1236   - distance_in_seconds = ((to_time - from_time).abs).round
1237   - case distance_in_minutes
1238   - when 0..1
1239   - return (distance_in_minutes == 0) ? _('less than a minute') : _('1 minute') unless include_seconds
1240   - case distance_in_seconds
1241   - when 0..4 then _('less than 5 seconds')
1242   - when 5..9 then _('less than 10 seconds')
1243   - when 10..19 then _('less than 20 seconds')
1244   - when 20..39 then _('half a minute')
1245   - when 40..59 then _('less than a minute')
1246   - else _('1 minute')
1247   - end
1248   -
1249   - when 2..44 then _('%{distance} minutes ago') % { :distance => distance_in_minutes }
1250   - when 45..89 then _('about 1 hour ago')
1251   - when 90..1439 then _('about %{distance} hours ago') % { :distance => (distance_in_minutes.to_f / 60.0).round }
1252   - when 1440..2879 then _('1 day ago')
1253   - when 2880..10079 then _('%{distance} days ago') % { :distance => (distance_in_minutes / 1440).round }
1254   - else show_time(from_time)
1255   - end
1256   - end
1257   -
1258 1229 def comment_balloon(options = {}, &block)
1259 1230 wrapper = content_tag(:div, capture(&block), :class => 'comment-balloon-content')
1260 1231 (1..8).to_a.reverse.each { |i| wrapper = content_tag(:div, wrapper, :class => "comment-wrapper-#{i}") }
... ...
app/helpers/blog_helper.rb
... ... @@ -22,7 +22,9 @@ module BlogHelper
22 22 :param_name => 'npage',
23 23 :previous_label => _('« Newer posts'),
24 24 :next_label => _('Older posts »'),
25   - :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
  25 + :params => {:action=>"view_page",
  26 + :page=>articles.first.parent.path.split('/'),
  27 + :controller=>"content_viewer"}
26 28 }) if articles.present? && conf[:paginate]
27 29 content = []
28 30 artic_len = articles.length
... ... @@ -44,7 +46,7 @@ module BlogHelper
44 46 end
45 47  
46 48 def display_post(article, format = 'full')
47   - no_comments = (format == 'full') ? false : true
  49 + no_comments = (format == 'full' || format == 'compact' ) ? false : true
48 50 title = article_title(article, :no_comments => no_comments)
49 51 method = "display_#{format.split('+')[0]}_format"
50 52 html = send(method, FilePresenter.for(article)).html_safe
... ... @@ -55,8 +57,12 @@ module BlogHelper
55 57 else
56 58 '<div class="post-pic" style="background-image:url('+img+')"></div>'
57 59 end
58   - end.to_s +
59   - title + html
  60 + end.to_s + title + html
  61 + end
  62 +
  63 + def display_compact_format(article)
  64 + render :file => 'content_viewer/_display_compact_format',
  65 + :locals => { :article => article, :format => "compact" }
60 66 end
61 67  
62 68 def display_full_format(article)
... ...
app/helpers/comment_helper.rb
1 1 module CommentHelper
  2 + include DatesHelper
2 3  
3 4 def article_title(article, args = {})
4 5 title = article.title
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -2,6 +2,7 @@ module ContentViewerHelper
2 2  
3 3 include BlogHelper
4 4 include ForumHelper
  5 + include DatesHelper
5 6  
6 7 def display_number_of_comments(n)
7 8 base_str = "<span class='comment-count hide'>#{n}</span>"
... ... @@ -24,8 +25,9 @@ module ContentViewerHelper
24 25 unless args[:no_comments] || !article.accept_comments
25 26 comments = (" - %s") % link_to_comments(article)
26 27 end
  28 + date_format = show_with_right_format_date article
27 29 title << content_tag('span',
28   - content_tag('span', show_date(article.published_at), :class => 'date') +
  30 + date_format +
29 31 content_tag('span', _(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') +
30 32 content_tag('span', comments, :class => 'comments'),
31 33 :class => 'created-at'
... ... @@ -34,6 +36,24 @@ module ContentViewerHelper
34 36 title
35 37 end
36 38  
  39 + def show_with_right_format_date article
  40 + date_format = article.environment.date_format
  41 + use_numbers = false
  42 + year = true
  43 + left_time = false
  44 + if date_format == 'numbers_with_year'
  45 + use_numbers = true
  46 + elsif date_format == 'numbers'
  47 + use_numbers = true
  48 + year = false
  49 + elsif date_format == 'month_name'
  50 + year = false
  51 + elsif date_format == 'past_time'
  52 + left_time = true
  53 + end
  54 + content_tag('span', show_date(article.published_at, use_numbers , year, left_time), :class => 'date')
  55 + end
  56 +
37 57 def link_to_comments(article, args = {})
38 58 return '' unless article.accept_comments?
39 59 reference_to_article number_of_comments(article), article, 'comments_list'
... ...
app/helpers/dates_helper.rb
... ... @@ -2,6 +2,7 @@ require &#39;noosfero/i18n&#39;
2 2  
3 3 module DatesHelper
4 4  
  5 + include ActionView::Helpers::DateHelper
5 6 def months
6 7 I18n.t('date.month_names')
7 8 end
... ... @@ -15,10 +16,12 @@ module DatesHelper
15 16 end
16 17  
17 18 # formats a date for displaying.
18   - def show_date(date, use_numbers = false, year=true)
  19 + def show_date(date, use_numbers = false, year = true, left_time = false)
19 20 if date && use_numbers
20 21 date_format = year ? _('%{month}/%{day}/%{year}') : _('%{month}/%{day}')
21 22 date_format % { :day => date.day, :month => date.month, :year => date.year }
  23 + elsif date && left_time
  24 + date_format = time_ago_in_words(date)
22 25 elsif date
23 26 date_format = year ? _('%{month_name} %{day}, %{year}') : _('%{month_name} %{day}')
24 27 date_format % { :day => date.day, :month_name => month_name(date.month), :year => date.year }
... ...
app/helpers/events_helper.rb
1 1 module EventsHelper
2 2  
  3 + include DatesHelper
3 4 def list_events(date, events)
4 5 title = _('Events for %s') % show_date_month(date)
5 6 content_tag('h2', title) +
... ...
app/helpers/folder_helper.rb
1   -require 'short_filename'
2   -
3 1 module FolderHelper
4 2  
5   - include ShortFilename
6 3 include ArticleHelper
7 4  
8 5 def list_contents(configure={})
... ... @@ -10,8 +7,8 @@ module FolderHelper
10 7 configure[:list_type] ||= :folder
11 8 if !configure[:contents].blank?
12 9 configure[:contents] = configure[:contents].paginate(
13   - :order => "updated_at DESC",
14   - :per_page => 10,
  10 + :order => "name ASC",
  11 + :per_page => 30,
15 12 :page => params[:npage]
16 13 )
17 14  
... ... @@ -25,49 +22,32 @@ module FolderHelper
25 22 articles.select {|article| article.display_to?(user)}
26 23 end
27 24  
28   - def display_content_in_listing(configure={})
29   - recursive = configure[:recursive] || false
30   - list_type = configure[:list_type] || :folder
31   - level = configure[:level] || 0
32   - content = FilePresenter.for configure[:content]
  25 + def display_content_icon(content_item)
  26 + content = FilePresenter.for content_item
33 27 content_link = if content.image?
34   - link_to('&nbsp;' * (level * 4) +
35   - image_tag(icon_for_article(content)) + short_filename(content.name),
  28 + link_to(
  29 + image_tag(icon_for_article(content, :bigicon)),
36 30 content.url.merge(:view => true)
37 31 )
38 32 else
39   - link_to('&nbsp;' * (level * 4) +
40   - short_filename(content.name),
41   - content.url.merge(:view => true), :class => icon_for_article(content)
  33 + link_to('',
  34 + content.url.merge(:view => true),
  35 + :class => icon_for_article(content, :bigicon)
42 36 )
43 37 end
44   - result = content_tag(
45   - 'tr',
46   - content_tag('td', content_link ) +
47   - content_tag('td', show_date(content.updated_at), :class => 'last-update'),
48   - :class => "#{list_type}-item"
49   - )
50   - if recursive
51   - result + content.children.map {|item|
52   - display_content_in_listing :content=>item, :recursive=>recursive,
53   - :list_type=>list_type, :level=>level+1
54   - }.join("\n")
55   - else
56   - result
57   - end
58 38 end
59 39  
60   - def icon_for_article(article)
  40 + def icon_for_article(article, size = 'icon')
61 41 article = FilePresenter.for article
62   - icon = article.respond_to?(:icon_name) ?
63   - article.icon_name :
64   - article.class.icon_name(article)
65   - if (icon =~ /\//)
66   - icon
  42 + if article.respond_to?(:sized_icon)
  43 + article.sized_icon(size)
67 44 else
68   - klasses = 'icon ' + [icon].flatten.map{|name| 'icon-'+name}.join(' ')
  45 + icon = article.respond_to?(:icon_name) ?
  46 + article.icon_name :
  47 + article.class.icon_name(article)
  48 + klasses = "#{size} " + [icon].flatten.map{|name| "#{size}-"+name}.join(' ')
69 49 if article.kind_of?(UploadedFile) || article.kind_of?(FilePresenter)
70   - klasses += ' icon-upload-file'
  50 + klasses += " #{size}-upload-file"
71 51 end
72 52 klasses
73 53 end
... ...
app/helpers/forum_helper.rb
1 1 module ForumHelper
  2 + include ActionView::Helpers::DateHelper
2 3  
3 4 def cms_label_for_new_children
4 5 _('New discussion topic')
... ... @@ -42,9 +43,9 @@ module ForumHelper
42 43 def last_topic_update(article)
43 44 info = article.info_from_last_update
44 45 if info[:author_url]
45   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
  46 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
46 47 else
47   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
  48 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
48 49 end
49 50 end
50 51  
... ...
app/helpers/manage_products_helper.rb
... ... @@ -75,9 +75,12 @@ module ManageProductsHelper
75 75 end
76 76  
77 77 def categories_container(categories_selection_html, hierarchy_html = '')
78   - hidden_field_tag('selected_category_id') +
79   - content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') +
80   - content_tag('div', categories_selection_html, :id => 'categories_container_wrapper')
  78 + content_tag 'div',
  79 + render('categories_autocomplete') +
  80 + hidden_field_tag('selected_category_id') +
  81 + content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') +
  82 + content_tag('div', categories_selection_html, :id => 'categories_container_wrapper'),
  83 + :id => 'categories-container'
81 84 end
82 85  
83 86 def select_for_categories(categories, level = 0)
... ...
app/models/article.rb
... ... @@ -28,7 +28,7 @@ class Article &lt; ActiveRecord::Base
28 28 def initialize(*params)
29 29 super
30 30  
31   - if !params.blank? && params.first.has_key?(:profile)
  31 + if !params.blank? && params.first.has_key?(:profile) && !params.first[:profile].blank?
32 32 profile = params.first[:profile]
33 33 self.published = false unless profile.public?
34 34 end
... ...
app/models/blog.rb
... ... @@ -76,9 +76,12 @@ class Blog &lt; Folder
76 76 end
77 77  
78 78 settings_items :visualization_format, :type => :string, :default => 'full'
79   - validates_inclusion_of :visualization_format, :in => [ 'full', 'short', 'short+pic' ], :if => :visualization_format
  79 + validates_inclusion_of :visualization_format,
  80 + :in => [ 'full', 'short', 'short+pic', 'compact'],
  81 + :if => :visualization_format
80 82  
81   - settings_items :display_posts_in_current_language, :type => :boolean, :default => false
  83 + settings_items :display_posts_in_current_language,
  84 + :type => :boolean, :default => false
82 85  
83 86 alias :display_posts_in_current_language? :display_posts_in_current_language
84 87  
... ...
app/models/environment.rb
... ... @@ -3,7 +3,17 @@
3 3 # domains.
4 4 class Environment < ActiveRecord::Base
5 5  
6   - attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound, :noreply_email, :signup_welcome_screen_body, :members_whitelist_enabled, :members_whitelist, :highlighted_news_amount, :portal_news_amount
  6 + attr_accessible :name, :is_default, :signup_welcome_text_subject,
  7 + :signup_welcome_text_body, :terms_of_use,
  8 + :message_for_disabled_enterprise, :news_amount_by_folder,
  9 + :default_language, :languages, :description,
  10 + :organization_approval_method, :enabled_plugins,
  11 + :enabled_features, :redirection_after_login,
  12 + :redirection_after_signup, :contact_email, :theme,
  13 + :reports_lower_bound, :noreply_email,
  14 + :signup_welcome_screen_body, :members_whitelist_enabled,
  15 + :members_whitelist, :highlighted_news_amount,
  16 + :portal_news_amount, :date_format
7 17  
8 18 has_many :users
9 19  
... ... @@ -14,6 +24,12 @@ class Environment &lt; ActiveRecord::Base
14 24  
15 25 IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/
16 26  
  27 + validates_inclusion_of :date_format,
  28 + :in => [ 'numbers_with_year', 'numbers',
  29 + 'month_name_with_year', 'month_name',
  30 + 'past_time'],
  31 + :if => :date_format
  32 +
17 33 def self.verify_filename(filename)
18 34 filename += '.txt' if File.extname(filename) =~ IDENTIFY_SCRIPTS
19 35 filename
... ...
app/models/profile.rb
... ... @@ -1006,19 +1006,11 @@ private :generate_url, :url_options
1006 1006 self.save
1007 1007 end
1008 1008  
1009   - def disabled?
1010   - !visible
1011   - end
1012   -
1013 1009 def enable
1014 1010 self.visible = true
1015 1011 self.save
1016 1012 end
1017 1013  
1018   - def enabled?
1019   - visible
1020   - end
1021   -
1022 1014 def control_panel_settings_button
1023 1015 {:title => _('Edit Profile'), :icon => 'edit-profile'}
1024 1016 end
... ...
app/models/uploaded_file.rb
1   -require 'short_filename'
2   -
3 1 # Article type that handles uploaded files.
4 2 #
5 3 # Limitation: only file metadata are versioned. Only the latest version
... ... @@ -14,8 +12,6 @@ class UploadedFile &lt; Article
14 12  
15 13 track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }, :custom_target => :parent
16 14  
17   - include ShortFilename
18   -
19 15 def title
20 16 if self.name.present? then self.name else self.filename end
21 17 end
... ... @@ -65,7 +61,7 @@ class UploadedFile &lt; Article
65 61 # :min_size => 2.megabytes
66 62 # :max_size => 5.megabytes
67 63 has_attachment :storage => :file_system,
68   - :thumbnails => { :icon => [24,24], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
  64 + :thumbnails => { :icon => [24,24], :bigicon => [50,50], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
69 65 :thumbnail_class => Thumbnail,
70 66 :max_size => self.max_size
71 67  
... ...
app/presenters/image.rb
... ... @@ -4,6 +4,10 @@ class FilePresenter::Image &lt; FilePresenter
4 4 f.image? ? 10 : nil
5 5 end
6 6  
  7 + def sized_icon(size)
  8 + public_filename size
  9 + end
  10 +
7 11 def icon_name
8 12 public_filename :icon
9 13 end
... ...
app/views/admin_panel/_site_info.html.erb
... ... @@ -3,6 +3,21 @@
3 3 <%= labelled_form_field(_('No reply email'), text_field(:environment, :noreply_email)) %>
4 4 <% themes_options = Theme.system_themes.map {|theme| [theme.name, theme.id] }.sort %>
5 5 <%= labelled_form_field(_('Theme'), select(:environment, :theme, options_for_select(themes_options, environment.theme))) %>
  6 +
  7 +<%= labelled_form_field(
  8 + _("Article's date format"),
  9 + select(:environment, :date_format,
  10 + options_for_select([
  11 + [ _('mm/dd/yyyy'), 'numbers_with_year'],
  12 + [ _('mm/dd'), 'numbers'],
  13 + [ _('Month dd, yyyy'), 'month_name_with_year'],
  14 + [ _('Month dd'), 'month_name'],
  15 + [ _('X minutes/hours/days/months/years ago'), 'past_time']
  16 + ], environment.date_format
  17 + )
  18 + )
  19 +) %>
  20 +
6 21 <%= required f.text_field(:reports_lower_bound, :size => 3) %>
7 22 <%= labelled_form_field(_('Default language'), select(:environment, :default_language, environment.locales.invert, { :selected => environment.default_locale, :include_blank => true })) %>
8 23 <%= label_tag :languages, _('Available languages') %>
... ...
app/views/cms/_blog.html.erb
... ... @@ -67,7 +67,8 @@
67 67 <%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [
68 68 [ _('Full post'), 'full'],
69 69 [ _('First paragraph'), 'short'],
70   - [ _('First paragraph, with post picture'), 'short+pic']
  70 + [ _('First paragraph, with post picture'), 'short+pic'],
  71 + [ _("Title, Image, Lead"), 'compact']
71 72 ])) %>
72 73  
73 74 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %>
... ...
app/views/cms/_view_items.html.erb 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +<% @articles.each do |article| article = FilePresenter.for article %>
  2 + <tr title="<%= article.title%>" >
  3 + <td class="article-name">
  4 + <%= link_to_article(article) %>
  5 + </td>
  6 + <% short_description = article.respond_to?(:short_description) ?
  7 + article.short_description :
  8 + article.class.short_description %>
  9 + <td class="article-mime" title=<%= short_description.to_json %>>
  10 + <%= short_description %>
  11 + </td>
  12 + <td class="last-update">
  13 + <%= time_ago_in_words article.updated_at %>
  14 + </td>
  15 + <td class="article-controls">
  16 + <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit, article) %>
  17 + <%= button_without_text :eyes, _('Public view'), article.view_url %>
  18 + <%= display_spread_button(article) unless remove_content_button(:spread, article) %>
  19 + <% if user.can_change_homepage? && !remove_content_button(:home, article) %>
  20 + <% if profile.home_page != article %>
  21 + <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %>
  22 + <% else %>
  23 + <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %>
  24 + <% end %>
  25 + <% end %>
  26 + <%= display_delete_button(article) if !remove_content_button(:delete, article) %>
  27 + </td>
  28 + </tr>
  29 +<% end %>
... ...
app/views/cms/view.html.erb
... ... @@ -37,6 +37,7 @@
37 37 <tr>
38 38 <th><%= _('Name') %></th>
39 39 <th><%= _('Type') %></th>
  40 + <th><%= _('Last update') %></th>
40 41 <th><%= _('Actions') %></th>
41 42 </tr>
42 43  
... ... @@ -54,32 +55,7 @@
54 55 </tr>
55 56 <% end %>
56 57  
57   - <% @articles.each do |article| article = FilePresenter.for article %>
58   - <tr title="<%= article.title%>" >
59   - <td class="article-name">
60   - <%= link_to_article(article) %>
61   - </td>
62   - <% short_description = article.respond_to?(:short_description) ?
63   - article.short_description :
64   - article.class.short_description %>
65   - <td class="article-mime" title=<%= short_description.to_json %>>
66   - <%= short_description %>
67   - </td>
68   - <td class="article-controls">
69   - <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit, article) %>
70   - <%= button_without_text :eyes, _('Public view'), article.view_url %>
71   - <%= display_spread_button(article) unless remove_content_button(:spread, article) %>
72   - <% if user.can_change_homepage? && !remove_content_button(:home, article) %>
73   - <% if profile.home_page != article %>
74   - <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %>
75   - <% else %>
76   - <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %>
77   - <% end %>
78   - <% end %>
79   - <%= display_delete_button(article) if !remove_content_button(:delete, article) %>
80   - </td>
81   - </tr>
82   - <% end %>
  58 + <%= render 'view_items' %>
83 59  
84 60 </table>
85 61  
... ...
app/views/content_viewer/_display_compact_format.html.erb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +<% if article.image %>
  2 + <% className = "article-compact-abstract-with-image" %>
  3 + <% if article.image.thumbnails_processed? %>
  4 + <% image_file = article.image.public_filename(:big) %>
  5 + <% else %>
  6 + <% image_file = "/images/icons-app/image-loading-thumb.png" %>
  7 + <% end %>
  8 +<% else %>
  9 + <% className = "article-compact-abstract" %>
  10 +<% end %>
  11 +
  12 +<div>
  13 + <% if article.image %>
  14 + <div class = "article-compact-image">
  15 + <%= image_tag(image_file) %>
  16 + </div>
  17 + <% end %>
  18 + <div class = <%= className %> >
  19 + <%= article.abstract.truncate(400) %>
  20 + </div>
  21 +</div>
... ...
app/views/content_viewer/blog_page.html.erb
... ... @@ -8,7 +8,7 @@
8 8 </div>
9 9 </div>
10 10 <hr class="pre-posts"/>
11   -<div class="blog-posts">
  11 +<div class="blog-posts page-<%= @npage %>">
12 12 <% paginate = true %>
13 13 <%=
14 14 posts = @posts
... ...
app/views/content_viewer/folder.html.erb
1 1 <% unless folder.body.blank? %>
2   - <div>
  2 + <div class="folder-description">
3 3 <%= folder.body %>
4 4 </div>
5   - <hr/>
6 5 <% end %>
7 6  
8 7 <% if folder.children.empty? %>
... ...
app/views/manage_products/_categories_autocomplete.html.erb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +<%= text_field_tag 'product_category_id', '', :placeholder => _('type a category for the product') %>
  2 +
  3 +<%= javascript_include_tag '/javascripts/product_categories.js' %>
  4 +<% javascript_tag do %>
  5 + product_categories.autocomplete.search_url = <%= url_for(:controller => :manage_products, :action => :search_categories).to_json %>
  6 + product_categories.autocomplete.select_url = <%= url_for(:controller => :manage_products, :action => :show_category_tree).to_json %>
  7 + product_categories.autocomplete.load('#product_category_id')
  8 +<% end %>
... ...
app/views/manage_products/_selected_category_tree.html.erb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +<%= categories_container selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true) %>
  2 +
... ...
app/views/manage_products/edit_category.html.erb
... ... @@ -16,7 +16,7 @@
16 16  
17 17 <h3><%= _('Edit category of this product:') %></h3>
18 18  
19   - <%= categories_container(selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true)) %>
  19 + <%= render 'manage_products/selected_category_tree' %>
20 20  
21 21 <div id='categories_selection_actionbar'>
22 22 <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %>
... ...
app/views/person_notifier/mailer/_comment.html.erb
... ... @@ -19,7 +19,7 @@
19 19 <span style="font-size: 12px;"><%= comment.title %></span><br/>
20 20 <% end %>
21 21 <span style="font-size: 10px;"><%= txt2html comment.body %></span><br/>
22   - <span style="font-size: 8px; color: #929292"><%= time_ago_as_sentence(comment.created_at) %></span>
  22 + <span style="font-size: 8px; color: #929292"><%= time_ago_in_words(comment.created_at) %></span>
23 23 <br style="clear: both;" />
24 24  
25 25 <% unless comment.replies.blank? %>
... ...
app/views/person_notifier/mailer/_create_article.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span>
8 8 <span style="font-size: 14px;"><%= _("has published on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span>
9   - <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  9 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span>
10 10 </p>
11 11 <p>
12 12 <span style="font-size: 14px;"><%= link_to(activity.params['name'], activity.params['url'], :style => "color: #333; font-weight: bold; text-decoration: none;") %></span>
... ...
app/views/person_notifier/mailer/_default_activity.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <td>
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
8   - <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_in_words(activity.created_at) %></span>
9 9 </p>
10 10 </td>
11 11 </tr>
... ...
app/views/person_notifier/mailer/_task.html.erb
... ... @@ -12,7 +12,7 @@
12 12 <span style="font-size: 14px">
13 13 <%= task_information(task) %>
14 14 </span>
15   - <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(task.created_at) %></span>
  15 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_in_words(task.created_at) %></span>
16 16 </div>
17 17 </td>
18 18 </tr>
... ...
app/views/person_notifier/mailer/_upload_image.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <td>
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
8   - <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span>
9 9 </p>
10 10 </td>
11 11 </tr>
... ...
app/views/profile/_comment.html.erb
... ... @@ -40,7 +40,7 @@
40 40 <%= txt2html comment.body %>
41 41 </div>
42 42 <div class="profile-activity-time">
43   - <%= time_ago_as_sentence(comment.created_at) %>
  43 + <%= time_ago_in_words(comment.created_at) %>
44 44 </div>
45 45 </div>
46 46  
... ...
app/views/profile/_create_article.html.erb
... ... @@ -12,7 +12,7 @@
12 12 <%= image_tag(activity.params['first_image']) unless activity.params['first_image'].blank? %><%= strip_tags(truncate(activity.params['lead'], :length => 1000, :ommision => '...')).gsub(/(\xC2\xA0|\s)+/, ' ').gsub(/^\s+/, '') unless activity.params['lead'].blank? %> <small><%= link_to(_('See more'), activity.params['url']) unless activity.get_lead.blank? %></small>
13 13 </div>
14 14 <%= content_tag(:p, link_to(_('See complete forum'), activity.get_url), :class => 'see-forum') if activity.target.is_a?(Forum) %>
15   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  15 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
16 16 <div class='profile-wall-actions'>
17 17 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
18 18 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :only_hide => true, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
... ...
app/views/profile/_default_activity.html.erb
... ... @@ -3,7 +3,7 @@
3 3 </div>
4 4 <div class='profile-activity-description'>
5 5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  6 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
7 7 <div class='profile-wall-actions'>
8 8 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
9 9 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
... ...
app/views/profile/_leave_scrap.html.erb
... ... @@ -3,7 +3,7 @@
3 3 </div>
4 4 <div class='profile-activity-description'>
5 5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  6 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
7 7 <div class='profile-wall-actions'>
8 8 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
9 9 </div>
... ...
app/views/profile/_profile_scrap.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
7 7 <p class='profile-activity-text'><%= txt2html scrap.content %></p>
8   - <p class='profile-activity-time'><%= time_ago_as_sentence(scrap.created_at) %></p>
  8 + <p class='profile-activity-time'><%= time_ago_in_words(scrap.created_at) %></p>
9 9 <div class='profile-wall-actions'>
10 10 <% if logged_in? && current_person.follows?(scrap.sender) %>
11 11 <span class='profile-activity-send-reply'>
... ... @@ -22,5 +22,5 @@
22 22 <% end %>
23 23 </ul>
24 24 <%= render :partial => 'profile_scrap_reply_form', :locals => { :scrap => scrap } %>
25   - <hr />
  25 + <hr />
26 26 </li>
... ...
app/views/profile/_profile_scraps.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
7 7 <p class='profile-activity-text'><%= txt2html scrap.content %></p>
8   - <p class='profile-activity-time'><%= time_ago_as_sentence(scrap.created_at) %></p>
  8 + <p class='profile-activity-time'><%= time_ago_in_words(scrap.created_at) %></p>
9 9 <div class='profile-wall-actions'>
10 10 <% if logged_in? && current_person.follows?(scrap.sender) %>
11 11 <span class='profile-activity-send-reply'>
... ...
app/views/profile/_upload_image.html.erb
... ... @@ -4,7 +4,7 @@
4 4 </div>
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
7   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  7 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
8 8 <div class='profile-wall-actions'>
9 9 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
10 10 </div>
... ...
app/views/shared/_content_item.html.erb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<div id="list-item">
  2 + <div class="item-info">
  3 + <div class="item-icon" >
  4 + <%= display_content_icon(content) %>
  5 + </div>
  6 + <span class="item-description">
  7 + <%= link_to(content.name, content.url) %>
  8 + </span>
  9 + <span class="item-date"><%= _("Published at: #{show_date(content.updated_at)}") %></span>
  10 + </div>
  11 +</div>
... ...
app/views/shared/_lead_and_body.html.erb
... ... @@ -19,17 +19,27 @@
19 19  
20 20 <div class='article-lead' id="article-lead-<%=lead_id.to_s%>">
21 21  
  22 + <% abstract_options = {:style => 'width: 100%; height: 200px;', :class => editor_type} %>
22 23 <% if f %>
23   - <%= labelled_form_field(_(abstract_label), f.text_area(abstract_method, :style => 'width: 100%; height: 200px;', :class => editor_type)) %>
  24 + <%= labelled_form_field(_(abstract_label), f.text_area(abstract_method, abstract_options)) %>
24 25 <% else %>
25   - <%= labelled_form_field(_(abstract_label), text_area(object, abstract_method, :style => 'width: 100%; height: 200px;', :class => editor_type)) %>
  26 + <% if @article.kind_of?(Article) %>
  27 + <%= labelled_form_field(_(abstract_label), text_area_tag("article[abstract]", @escaped_abstract, abstract_options)) %>
  28 + <% else %>
  29 + <%= labelled_form_field(_(abstract_label), text_area(object, abstract_method, abstract_options)) %>
  30 + <% end %>
26 31 <% end %>
27 32 </div>
28 33 <div style="margin-top: 10px;">
  34 + <% body_options = {:style => 'width: 100%; height: 400px;', :class => editor_type} %>
29 35 <% if f %>
30   - <%= labelled_form_field(_(body_label), f.text_area(body_method, :style => 'width: 100%; height: 400px;', :class => editor_type)) %>
  36 + <%= labelled_form_field(_(body_label), f.text_area(body_method, body_options)) %>
31 37 <% else %>
32   - <%= labelled_form_field(_(body_label), text_area(object, body_method, :style => 'width: 100%; height: 400px;', :class => editor_type)) %>
  38 + <% if @article.kind_of?(Article) %>
  39 + <%= labelled_form_field(_(body_label), text_area_tag("article[body]", @escaped_body, body_options)) %>
  40 + <% else %>
  41 + <%= labelled_form_field(_(body_label), text_area(object, body_method, body_options)) %>
  42 + <% end %>
33 43 <% end %>
34 44 </div>
35 45  
... ...
app/views/shared/content_list.html.erb
1   -<table class="<%= list_type %>-content">
2   - <tr>
3   - <th><%= _('Title') %></th>
4   - <th><%= _('Last update') %></th>
5   - </tr>
  1 +<ul class="<%= list_type %>-content">
6 2 <% contents.each do |content| %>
7   - <% if content.display_to?(user) %>
8   - <%= display_content_in_listing :content=>content, :list_type=>list_type, :recursive=>recursive %>
9   - <% end %>
  3 + <li class="<%= list_type %>-item">
  4 + <% if content.display_to?(user) %>
  5 + <%= render :partial => 'shared/content_item', :locals => { :content => content } %>
  6 + <% end %>
  7 + </li>
10 8 <% end %>
11   -</table>
  9 +</ul>
12 10  
13 11 <p><%= pagination_links contents, :param_name => 'npage', :page_links => true %></p>
... ...
app/views/tasks/_abuse_complaint_accept_details.html.erb
... ... @@ -2,7 +2,7 @@
2 2 <% task.abuse_reports.each do |abuse_report| %>
3 3 <div>
4 4 <strong style="word-wrap: break-word; display: block; padding-right: 40px">"<%= abuse_report.reason %>"</strong> <br />
5   - <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_as_sentence(abuse_report.created_at) }%></i> <br />
  5 + <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_in_words(abuse_report.created_at) }%></i> <br />
6 6 <% if !abuse_report.content.blank? %>
7 7 <button class="display-abuse-report-details" data-report="<%=abuse_report.id%>"><%=_('View details')%></button>
8 8 <div style='display: none' id=<%= 'abuse-report-details-'+abuse_report.id.to_s %> class="abuse-report-details">
... ...
config/initializers/noosfero_extensions.rb
1 1 require 'noosfero/role_assignment_ext'
2 2 require 'noosfero/action_tracker_ext'
  3 +require 'noosfero/vote_ext'
... ...
db/migrate/20140708123314_index_role_assignments_filtered_fields.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +class IndexRoleAssignmentsFilteredFields < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + add_index :role_assignments, [:accessor_id, :accessor_type]
  5 + add_index :role_assignments, [:accessor_id, :accessor_type, :role_id], name: :index_on_role_assigments_accessor_role
  6 + add_index :role_assignments, [:resource_id, :resource_type]
  7 + add_index :role_assignments, [:resource_id, :resource_type, :role_id], name: :index_on_role_assigments_resource_role
  8 + add_index :role_assignments, [:accessor_id, :accessor_type, :resource_id, :resource_type], name: :index_on_role_assigments_accessor_resource_role
  9 + add_index :profiles, [:type]
  10 + add_index :profiles, [:visible]
  11 + add_index :profiles, [:enabled]
  12 + add_index :profiles, [:validated]
  13 + end
  14 +
  15 +end
... ...
db/migrate/20150423203352_fix_tags_case_differences.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class FixTagsCaseDifferences < ActiveRecord::Migration
  2 + def up
  3 + tags = ActsAsTaggableOn::Tag.joins('LEFT JOIN tags as b on LOWER(tags.name) = b.name').where('b.id is null')
  4 + tags.find_each do |tag|
  5 + unless ActsAsTaggableOn::Tag.exists?(:name => tag.name.mb_chars.downcase)
  6 + ActsAsTaggableOn::Tag.create(:name => tag.name.mb_chars.downcase)
  7 + end
  8 + end
  9 +
  10 + execute("UPDATE taggings SET tag_id = new.id FROM taggings AS t INNER JOIN tags AS old ON t.tag_id = old.id INNER JOIN tags AS new ON LOWER(old.name) = new.name WHERE old.id != new.id AND taggings.id = t.id")
  11 +
  12 + execute("UPDATE tags SET taggings_count = (SELECT COUNT(*) FROM taggings WHERE taggings.tag_id = tags.id)")
  13 + execute("DELETE FROM tags WHERE taggings_count = 0")
  14 + end
  15 +
  16 + def down
  17 + say 'This migration is irreversible.'
  18 + end
  19 +end
... ...
db/migrate/20150529180110_add_date_format_to_environment.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddDateFormatToEnvironment < ActiveRecord::Migration
  2 + def up
  3 + add_column :environments, :date_format, :string, :default => 'month_name_with_year'
  4 + end
  5 +
  6 + def down
  7 + remove_column :environments, :date_format
  8 + end
  9 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20150525101430) do
  14 +ActiveRecord::Schema.define(:version => 20150602142030) do
15 15  
16 16 create_table "abuse_reports", :force => true do |t|
17 17 t.integer "reporter_id"
... ... @@ -321,17 +321,18 @@ ActiveRecord::Schema.define(:version =&gt; 20150525101430) do
321 321 t.text "design_data"
322 322 t.text "custom_header"
323 323 t.text "custom_footer"
324   - t.string "theme", :default => "default", :null => false
  324 + t.string "theme", :default => "default", :null => false
325 325 t.text "terms_of_use_acceptance_text"
326 326 t.datetime "created_at"
327 327 t.datetime "updated_at"
328   - t.integer "reports_lower_bound", :default => 0, :null => false
  328 + t.integer "reports_lower_bound", :default => 0, :null => false
329 329 t.string "redirection_after_login", :default => "keep_on_same_page"
330 330 t.text "signup_welcome_text"
331 331 t.string "languages"
332 332 t.string "default_language"
333 333 t.string "noreply_email"
334 334 t.string "redirection_after_signup", :default => "keep_on_same_page"
  335 + t.string "date_format", :default => "month_name_with_year"
335 336 end
336 337  
337 338 create_table "external_feeds", :force => true do |t|
... ... @@ -692,6 +693,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150525101430) do
692 693 t.integer "image_id"
693 694 t.boolean "spam", :default => false
694 695 t.integer "responsible_id"
  696 + t.integer "closed_by_id"
695 697 end
696 698  
697 699 add_index "tasks", ["requestor_id"], :name => "index_tasks_on_requestor_id"
... ...
features/approve_article.feature
... ... @@ -62,7 +62,8 @@ Feature: approve article
62 62 And I press "Spread this"
63 63 And I follow "Delete"
64 64 And I confirm the browser dialog
65   - When I am logged in as "joaosilva"
  65 + And I follow "Logout"
  66 + And I am logged in as "joaosilva"
66 67 And I go to sample-community's control panel
67 68 And I follow "Process requests"
68 69 And I choose "Reject"
... ...
features/article_visualization.feature 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +Feature: article visualization
  2 + As a user
  3 + I want to change view modes
  4 + In order to see articles in fullscreen or not in fullscreen
  5 +
  6 + Background:
  7 + Given the following users
  8 + | login | name |
  9 + | joaosilva | Joao Silva |
  10 + And "joaosilva" has no articles
  11 + And the following articles
  12 + | owner | name | body |
  13 + | joaosilva | Sample Article | This is an article |
  14 + And I am logged in as "joaosilva"
  15 +
  16 + @selenium
  17 + Scenario: viewing the article in fullscreen by default
  18 + Given I go to /joaosilva/sample-article?fullscreen=1
  19 + Then I should see "Exit full screen"
  20 +
  21 + @selenium
  22 + Scenario: viewing the article not in fullscreen by default
  23 + Given I go to /joaosilva/sample-article
  24 + Then I should see "Full screen"
  25 +
  26 + @selenium
  27 + Scenario: changing the view mode from not in fullscreen to fullscreen
  28 + Given I go to /joaosilva/sample-article
  29 + And I follow "Full screen"
  30 + Then I should see "Exit full screen"
... ...
features/balloon.feature
... ... @@ -41,19 +41,19 @@ Feature: balloon
41 41 @selenium
42 42 Scenario: I should not see trigger if not enabled on page
43 43 Given feature "show_balloon_with_profile_links_when_clicked" is disabled on environment
44   - When I go to /assets/people
  44 + When I go to /search/people
45 45 Then I should not see "Profile links"
46 46  
47 47 @selenium
48 48 Scenario: I should not see trigger by default on page
49 49 Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment
50   - When I go to /assets/communities
  50 + When I go to /search/communities
51 51 Then I should not see "Members"
52 52  
53 53 @selenium
54 54 Scenario: I should see balloon when clicked on page trigger
55 55 Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment
56   - And I go to /assets/communities
  56 + And I go to /search/communities
57 57 And display ".community-trigger"
58 58 When I follow "Profile links"
59 59 Then I should see "Members"
... ...
features/browse_enterprises.feature
... ... @@ -13,20 +13,20 @@ Scenario: show all enterprises
13 13 Given the following enterprises
14 14 | identifier | name |
15 15 | shop2 | Fruits Shop |
16   - Given I am on /assets/enterprises
  16 + Given I am on /search/enterprises
17 17 Then I should see "Enterprises"
18 18 And I should see "Shoes Shop"
19 19 And I should see "Fruits Shop"
20 20  
21 21 Scenario: show profile links button
22   - Given I am on /assets/enterprises
  22 + Given I am on /search/enterprises
23 23 Then I should see "Profile links" within "a.enterprise-trigger"
24 24 And I should not see "Members"
25 25 And I should not see "Agenda"
26 26  
27 27 @selenium-fixme
28 28 Scenario: show profile links when clicked
29   - Given I am on /assets/enterprises
  29 + Given I am on /search/enterprises
30 30 When I follow "Profile links"
31 31 Then I should see "Products" within "ul.menu-submenu-list"
32 32 And I should see "Members" within "ul.menu-submenu-list"
... ... @@ -34,7 +34,7 @@ Scenario: show profile links when clicked
34 34  
35 35 @selenium-fixme
36 36 Scenario: go to catalog when click on products link
37   - Given I am on /assets/enterprises
  37 + Given I am on /search/enterprises
38 38 When I follow "Profile links"
39 39 And I follow "Products" and wait
40 40 Then I should be exactly on /catalog/shop1
... ...
features/change_appearance.feature
... ... @@ -14,7 +14,7 @@ Feature: Change appearance
14 14 And I should not see an element ".box-4"
15 15 And I go to joaosilva's control panel
16 16 And I follow "Edit Appearance"
17   - And I follow "Left Top and Right"
  17 + And I follow "Top and Side Bars"
18 18 And I go to joaosilva's control panel
19 19 And I follow "Edit sideboxes"
20 20 And I should see an element ".box-4"
... ...
features/events.feature
... ... @@ -17,7 +17,7 @@ Feature: events
17 17 Then I should see "November 2009" within ".current-month"
18 18  
19 19 Scenario: go to next month in global agenda
20   - Given I am on /assets/events?year=2009&month=11
  20 + Given I am on /search/events?year=2009&month=11
21 21 When I follow "December"
22 22 Then I should see "December 2009" within ".current-month"
23 23  
... ... @@ -27,7 +27,7 @@ Feature: events
27 27 Then I should see "September 2009" within ".current-month"
28 28  
29 29 Scenario: go to previous month in global agenda
30   - Given I am on /assets/events?year=2009&month=11
  30 + Given I am on /search/events?year=2009&month=11
31 31 When I follow "October"
32 32 Then I should see "October 2009" within ".current-month"
33 33  
... ... @@ -43,7 +43,7 @@ Feature: events
43 43  
44 44 Scenario: go to specific day in global agenda
45 45 Given I am on the homepage
46   - When I am on /assets/events?year=2009&month=11&day=12
  46 + When I am on /search/events?year=2009&month=11&day=12
47 47 Then I should see "Events for November, 2009"
48 48  
49 49 Scenario: list events for specific day
... ... @@ -88,7 +88,7 @@ Feature: events
88 88 And the following events
89 89 | owner | name | start_date |
90 90 | josemanuel | Manuel Birthday | 2009-10-24 |
91   - When I am on /assets/events?year=2009&month=10&day=24
  91 + When I am on /search/events?year=2009&month=10&day=24
92 92 Then I should see "Another Conference"
93 93 And I should see "Manuel Birthday"
94 94  
... ... @@ -157,7 +157,7 @@ Feature: events
157 157 Then I should not see "New events" link
158 158  
159 159 Scenario: display environment name in global agenda
160   - When I am on /assets/events
  160 + When I am on /search/events
161 161 Then I should see "Colivre.net's Events"
162 162  
163 163 @selenium
... ...
features/profile_domain.feature
... ... @@ -21,9 +21,7 @@ Feature: domain for profile
21 21 Scenario: access profile control panel through profile blocks
22 22 Given I am logged in as "joaosilva"
23 23 When I go to joaosilva's homepage
24   - And I follow "Control panel" within ".profile-info-block"
25   - Then I should see "Joao Silva" within "span.control-panel-title"
26   - When I follow "Control panel" within ".profile-image-block"
  24 + And I follow "Control panel" within ".profile-image-block"
27 25 Then I should see "Joao Silva" within "span.control-panel-title"
28 26  
29 27 @selenium
... ...
features/profile_search.feature
... ... @@ -36,7 +36,7 @@ Feature: search inside a profile
36 36 | joaosilva | ProfileSearchBlock |
37 37 When I go to joaosilva's profile
38 38 And I fill in "q" with "bees" within ".profile-search-block"
39   - And I press "Search"
  39 + And I press "Search" within ".profile-search-block"
40 40 Then I should see "bees and butterflies" within ".main-block"
41 41  
42 42 Scenario: not display unpublished articles
... ...
features/register_enterprise.feature
... ... @@ -203,5 +203,5 @@ Feature: register enterprise
203 203  
204 204 Scenario: a user cant see button to register new enterprise if enterprise_registration disabled
205 205 Given feature "enterprise_registration" is disabled on environment
206   - When I am on /assets/enterprises
  206 + When I am on /search/enterprises
207 207 Then I should not see "New enterprise" link
... ...
features/search_enterprises.feature
... ... @@ -56,7 +56,7 @@ Feature: search enterprises
56 56 | owner | name | body | homepage |
57 57 | shop1 | Shoes home | This is the <i>homepage</i> of Shoes shop! It has a very long and pretty vague description, just so we can test wether the system will correctly create an excerpt of this text. We should probably talk about shoes. | true |
58 58 When I search enterprises for "shoes"
59   - And I choose the search filter "Full"
  59 + And I select "Full" from "display"
60 60 Then I should see "This is the homepage of" within ".search-enterprise-description"
61 61 And I should see "about sho..." within ".search-enterprise-description"
62 62  
... ... @@ -66,7 +66,7 @@ Feature: search enterprises
66 66 | identifier | name | description |
67 67 | shop4 | Clothes shop | This <b>clothes</b> shop also sells shoes! This too has a very long and pretty vague description, just so we can test wether the system will correctly create an excerpt of this text. Clothes are a really important part of our lives. |
68 68 When I search enterprises for "clothes"
69   - And I choose the search filter "Full"
  69 + And I select "Full" from "display"
70 70 And I should see "This clothes shop" within ".search-enterprise-description"
71 71 And I should see "really import..." within ".search-enterprise-description"
72 72  
... ...
features/step_definitions/noosfero_steps.rb
... ... @@ -94,7 +94,7 @@ Given /^the following blocks$/ do |table|
94 94 owner.boxes<< Box.new
95 95 owner.boxes.first.blocks << MainBlock.new
96 96 end
97   - box = owner.boxes.where(:position => 3).first
  97 + box = owner.boxes.first
98 98 klass.constantize.create!(item.merge(:box => box))
99 99 end
100 100 end
... ...
features/suggest_article.feature
... ... @@ -14,9 +14,12 @@ Feature: suggest article
14 14  
15 15 @selenium
16 16 Scenario: highlight an article before approval of a suggested article
17   - Given someone suggested the following article to be published
18   - | target | article_name | article_body | name | email |
19   - | sample-community | A suggested article | this is an article about whales | jose | jose@example.org |
  17 + Given I am on Sample Community's blog
  18 + And I follow "Suggest an article"
  19 + And I fill in "Title" with "Suggestion"
  20 + And I fill in "Your name" with "Some Guy"
  21 + And I fill in "Email" with "someguy@somewhere.com"
  22 + And I press "Save"
20 23 When I am logged in as "joaosilva"
21 24 And I go to sample-community's control panel
22 25 And I follow "Process requests"
... ...
lib/noosfero/plugin.rb
1 1 require_dependency 'noosfero'
  2 +require 'noosfero/plugin/parent_methods'
2 3  
3 4 class Noosfero::Plugin
4 5  
... ... @@ -14,13 +15,9 @@ class Noosfero::Plugin
14 15  
15 16 class << self
16 17  
17   - attr_writer :should_load
  18 + include Noosfero::Plugin::ParentMethods
18 19  
19   - # Called for each ActiveRecord class with parents
20   - # See http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/full_table_name_prefix
21   - def table_name_prefix
22   - @table_name_prefix ||= "#{name.to_s.underscore}_"
23   - end
  20 + attr_writer :should_load
24 21  
25 22 def should_load
26 23 @should_load.nil? && true || @boot
... ... @@ -92,8 +89,14 @@ class Noosfero::Plugin
92 89 end
93 90 end
94 91  
95   - def load_plugin(plugin_name)
96   - (plugin_name.to_s.camelize + 'Plugin').constantize
  92 + def load_plugin_identifier identifier
  93 + klass = identifier.to_s.camelize.constantize
  94 + klass = klass.const_get :Base if klass.class == Module
  95 + klass
  96 + end
  97 +
  98 + def load_plugin public_name
  99 + load_plugin_identifier "#{public_name.to_s.camelize}Plugin"
97 100 end
98 101  
99 102 # This is a generic method that initialize any possible filter defined by a
... ... @@ -135,7 +138,7 @@ class Noosfero::Plugin
135 138 filters = [filters]
136 139 end
137 140 filters.each do |plugin_filter|
138   - filter_method = (plugin.name.underscore.gsub('/','_') + '_' + plugin_filter[:method_name]).to_sym
  141 + filter_method = "#{plugin.identifier}_#{plugin_filter[:method_name]}".to_sym
139 142 controller_class.send(plugin_filter[:type], filter_method, (plugin_filter[:options] || {}))
140 143 controller_class.send(:define_method, filter_method) do
141 144 instance_exec(&plugin_filter[:block]) if environment.plugin_enabled?(plugin)
... ...
lib/noosfero/plugin/manager.rb
... ... @@ -76,7 +76,7 @@ class Noosfero::Plugin::Manager
76 76  
77 77 def enabled_plugins
78 78 @enabled_plugins ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin|
79   - plugin.constantize.new(context)
  79 + Noosfero::Plugin.load_plugin_identifier(plugin).new context
80 80 end
81 81 end
82 82  
... ...
lib/noosfero/plugin/parent_methods.rb 0 → 100644
... ... @@ -0,0 +1,62 @@
  1 +class Noosfero::Plugin
  2 +
  3 + # Plugins that are defined as modules should extend
  4 + # this module manually, for example:
  5 + # module MyPlugin
  6 + # extend Noosfero::Plugin::ParentMethods
  7 + # end
  8 + module ParentMethods
  9 +
  10 + def identifier
  11 + @identifier ||= (if self.parents.first.instance_of? Module then self.parents.first else self end).name.underscore
  12 + end
  13 +
  14 + def public_name
  15 + @public_name ||= self.identifier.gsub '_plugin', ''
  16 + end
  17 +
  18 + # Here the developer should specify the meta-informations that the plugin can
  19 + # inform.
  20 + def plugin_name
  21 + self.identifier.humanize
  22 + end
  23 + def plugin_description
  24 + _("No description informed.")
  25 + end
  26 +
  27 + # Called for each ActiveRecord model with parents
  28 + # See http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/full_table_name_prefix
  29 + def table_name_prefix
  30 + @table_name_prefix ||= "#{self.identifier}_"
  31 + end
  32 +
  33 + def public_path file = '', relative=false
  34 + File.join "#{if relative then '' else '/' end}plugins", public_name, file
  35 + end
  36 +
  37 + def root_path
  38 + Rails.root.join('plugins', public_name)
  39 + end
  40 +
  41 + def view_path
  42 + File.join(root_path,'views')
  43 + end
  44 +
  45 + def admin_url
  46 + {:controller => "#{self.identifier}_admin", :action => 'index'}
  47 + end
  48 +
  49 + def has_admin_url?
  50 + File.exists?(File.join(root_path, 'controllers', "#{self.identifier}_admin_controller.rb"))
  51 + end
  52 +
  53 + def controllers
  54 + @controllers ||= Dir.glob("#{self.root_path}/controllers/*/*").map do |controller_file|
  55 + next unless controller_file =~ /_controller.rb$/
  56 + controller = File.basename(controller_file).gsub(/.rb$/, '').camelize
  57 + end.compact
  58 + end
  59 +
  60 + end
  61 +
  62 +end
... ...
lib/noosfero/vote_ext.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +require_dependency 'models/vote'
  2 +
  3 +class Vote
  4 +
  5 + validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id], :if => :allow_duplicated_vote?
  6 +
  7 + def allow_duplicated_vote?
  8 + voter.present?
  9 + end
  10 +
  11 +end
... ...
lib/short_filename.rb
... ... @@ -1,11 +0,0 @@
1   -module ShortFilename
2   -
3   - def short_filename(filename, limit_chars = 43)
4   - return filename if filename.size <= limit_chars
5   - extname = File.extname(filename)
6   - basename = File.basename(filename,extname)
7   - str_complement = '(...)'
8   - return basename[0..(limit_chars - extname.size - str_complement.size - 1)] + str_complement + extname
9   - end
10   -
11   -end
plugins/comment_classification/views/comment_classification_plugin_myprofile/add_status.html.erb
... ... @@ -13,7 +13,7 @@
13 13 <ul>
14 14 <% @comment.comment_classification_plugin_comment_status_users.each do |relation| %>
15 15 <li>
16   - <%= _("<i>%{user}</i> added the status <i>%{status_name}</i> at <i>%{created_at}</i>.") % { :user => relation.profile.name, :status_name => relation.status.name, :created_at => time_ago_as_sentence(relation.created_at)} %>
  16 + <%= _("<i>%{user}</i> added the status <i>%{status_name}</i> at <i>%{created_at}</i>.") % { :user => relation.profile.name, :status_name => relation.status.name, :created_at => time_ago_in_words(relation.created_at)} %>
17 17 <% unless relation.reason.blank? %>
18 18 <p><%= _("<i>Reason:</i> %s") % relation.reason %></p>
19 19 <% end %>
... ...
plugins/context_content/views/blocks/context_content.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <%= instance_eval(&block.content_image(content)) if block.show_image %>
7 7 </div>
8 8 <% if block.show_name %>
9   - <div class="name"><%= short_filename(content.name, 30) %></div>
  9 + <div class="name"><%= content.name %></div>
10 10 <% end %>
11 11 </a>
12 12 </span>
... ...
plugins/custom_forms/views/custom_forms_plugin_profile/show.html.erb
... ... @@ -14,8 +14,8 @@
14 14  
15 15 <%= form_for :submission do |f| %>
16 16 <% if !user %>
17   - <%= required labelled_form_field _('Author name'), text_field_tag(:author_name, @submission.author_name) %>
18   - <%= required labelled_form_field _('Author email'), text_field_tag(:author_email, @submission.author_email) %>
  17 + <%= required labelled_form_field _('Name'), text_field_tag(:author_name, @submission.author_name) %>
  18 + <%= required labelled_form_field _('Email'), text_field_tag(:author_email, @submission.author_email) %>
19 19 <% end %>
20 20  
21 21 <%= render :partial => 'shared/form_submission', :locals => {:f => f} %>
... ...
plugins/metadata/lib/metadata_plugin.rb
... ... @@ -23,7 +23,7 @@ class MetadataPlugin &lt; Noosfero::Plugin
23 23 },
24 24 content_viewer: {
25 25 variable: proc do
26   - if profile and profile.home_page_id == @page.id
  26 + if profile and @page and profile.home_page_id == @page.id
27 27 @profile
28 28 elsif @page.respond_to? :encapsulated_file
29 29 @page.encapsulated_file
... ...
plugins/metadata/test/functional/content_viewer_controller_test.rb
... ... @@ -48,4 +48,13 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
48 48 assert_tag tag: 'meta', attributes: { property: 'og:image', content: /\/images\/x.png/ }
49 49 end
50 50  
  51 + should 'render not_found page properly' do
  52 + assert_equal false, Article.exists?(:slug => 'non-existing-page')
  53 + assert_nothing_raised do
  54 + get :view_page, profile: profile.identifier, page: [ 'non-existing-page' ]
  55 + assert_response 404 # not found
  56 + assert_template 'not_found'
  57 + end
  58 + end
  59 +
51 60 end
... ...
plugins/vote/lib/ext/vote.rb
... ... @@ -1,11 +0,0 @@
1   -require_dependency 'models/vote'
2   -
3   -class Vote
4   -
5   - validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id], :if => :allow_duplicated_vote?
6   -
7   - def allow_duplicated_vote?
8   - voter.present?
9   - end
10   -
11   -end
public/designs/icons/tango/style.css
... ... @@ -117,6 +117,107 @@
117 117 .icon-clock { background-image: url(Tango/16x16/actions/appointment.png) }
118 118 .icon-fullscreen { background-image: url(Tango/16x16/actions/view-fullscreen.png) }
119 119  
  120 +/******************BIG ICONS************************/
  121 +.bigicon-embed { background-image: url(Tango/scalable/apps/utilities-terminal.svg) }
  122 +.bigicon-edit { background-image: url(Tango/scalable/apps/text-editor.svg) }
  123 +.bigicon-undo { background-image: url(Tango/scalable/actions/edit-undo.svg) }
  124 +.bigicon-home { background-image: url(Tango/scalable/actions/go-home.svg) }
  125 +.bigicon-home-not { background-image: url(mod/scalable/actions/go-home-not.svg) }
  126 +.bigicon-new,
  127 +.bigicon-suggest { background-image: url(Tango/scalable/actions/filenew.svg) }
  128 +.bigicon-close { background-image: url(Tango/scalable/actions/gtk-cancel.svg) }
  129 +.bigicon-newfolder { background-image: url(Tango/scalable/actions/folder-new.svg) }
  130 +.bigicon-folder { background-image: url(Tango/scalable/places/folder.svg) }
  131 +.bigicon-parent-folder { background-image: url(Tango/scalable/places/folder_home.svg) }
  132 +.bigicon-newblog { background-image: url(mod/scalable/apps/text-editor.svg) }
  133 +.bigicon-blog { background-image: url(mod/scalable/apps/text-editor.svg) }
  134 +.bigicon-save { background-image: url(Tango/scalable/actions/filesave.svg) }
  135 +.bigicon-send { background-image: url(Tango/scalable/actions/stock_mail-forward.svg) }
  136 +.bigicon-cancel { background-image: url(Tango/scalable/actions/gtk-cancel.svg) }
  137 +.bigicon-person { background-image: url(Tango/scalable/apps/system-config-users.svg) }
  138 +.bigicon-product { background-image: url(Tango/scalable/mimetypes/package.svg) }
  139 +.bigicon-delete { background-image: url(Tango/scalable/places/user-trash.svg) }
  140 +.bigicon-back { background-image: url(Tango/scalable/actions/back.svg) }
  141 +.bigicon-next { background-image: url(Tango/scalable/actions/go-next.svg) }
  142 +.bigicon-add { background-image: url(Tango/scalable/actions/add.svg) }
  143 +.bigicon-remove { background-image: url(Tango/scalable/actions/gtk-remove.svg) }
  144 +.bigicon-more { background-image: url(Tango/scalable/actions/add.svg) }
  145 +.bigicon-up { background-image: url(Tango/scalable/actions/go-up.svg) }
  146 +.bigicon-down { background-image: url(Tango/scalable/actions/go-down.svg) }
  147 +.bigicon-left { background-image: url(Tango/scalable/actions/go-previous.svg) }
  148 +.bigicon-right { background-image: url(Tango/scalable/actions/go-next.svg) }
  149 +.bigicon-up-disabled { background-image: url(Tango/scalable/actions/go-up.svg); opacity: 0.25; filter:alpha(opacity=25); }
  150 +.bigicon-down-disabled { background-image: url(Tango/scalable/actions/go-down.svg); opacity: 0.25; filter:alpha(opacity=25); }
  151 +.bigicon-left-disabled { background-image: url(Tango/scalable/actions/go-previous.svg); opacity: 0.25; filter:alpha(opacity=25); }
  152 +.bigicon-right-disabled { background-image: url(Tango/scalable/actions/go-next.svg); opacity: 0.25; filter:alpha(opacity=25); }
  153 +.bigicon-up-red { background-image: url(mod/scalable/actions/go-up-red.svg) }
  154 +.bigicon-forward { background-image: url(Tango/scalable/actions/go-next.svg) }
  155 +.bigicon-search { background-image: url(Tango/scalable/actions/search.svg) }
  156 +.bigicon-ok { background-image: url(Tango/scalable/actions/media-playback-start.svg) }
  157 +.bigicon-login { background-image: url(mod/scalable/actions/log-in.svg) }
  158 +.bigicon-help { background-image: url(Tango/scalable/apps/gnome-help.svg) }
  159 +.bigicon-help32on { background-image: url(Tango/scalable/apps/gnome-help.svg) }
  160 +.bigicon-help32off { background-image: url(mod/scalable/apps/gnome-help-red.svg) }
  161 +.bigicon-spread { background-image: url(mod/scalable/actions/spread.svg) }
  162 +.bigicon-todo { background-image: url(Tango/scalable/actions/stock_paste.svg) }
  163 +.bigicon-eyes { background-image: url(Tango/scalable/actions/find.svg) }
  164 +.bigicon-menu-home { background-image: url(Tango/scalable/actions/go-home.svg) }
  165 +.bigicon-menu-product { background-image: url(Tango/scalable/mimetypes/package.svg) }
  166 +.bigicon-menu-enterprise { background-image: url(Tango/scalable/actions/go-home.svg) }
  167 +.bigicon-menu-community { background-image: url(Tango/scalable/apps/system-config-users.svg) }
  168 +.bigicon-menu-ctrl-panel { background-image: url(Tango/scalable/categories/preferences-desktop.svg) }
  169 +.bigicon-menu-admin { background-image: url(Tango/scalable/categories/preferences-system.svg) }
  170 +.bigicon-menu-my-groups { background-image: url(Tango/scalable/apps/system-config-users.svg) }
  171 +.bigicon-menu-login { background-image: url(mod/scalable/actions/log-in.svg) }
  172 +.bigicon-menu-logout { background-image: url(mod/scalable/actions/log-out.svg) }
  173 +.bigicon-menu-search { background-image: url(Tango/scalable/actions/search.svg) }
  174 +.bigicon-menu-events { background-image: url(Tango/scalable/mimetypes/stock_calendar.svg) }
  175 +.bigicon-event { background-image: url(Tango/scalable/mimetypes/stock_calendar.svg) }
  176 +.bigicon-newevent { background-image: url(Tango/scalable/mimetypes/stock_calendar.svg) }
  177 +.bigicon-menu-articles { background-image: url(Tango/scalable/apps/text-editor.svg) }
  178 +.bigicon-menu-people { background-image: url(mod/scalable/apps/user.svg) }
  179 +.bigicon-menu-mail { background-image: url(Tango/scalable/apps/email.svg) }
  180 +.bigicon-upload-file { background-image: url(Tango/scalable/actions/filesave.svg) }
  181 +.bigicon-newupload-file { background-image: url(Tango/scalable/actions/filesave.svg) }
  182 +.bigicon-slideshow { background-image: url(Tango/scalable/mimetypes/x-office-presentation.svg) }
  183 +.bigicon-photos { background-image: url(Tango/scalable/devices/camera-photo.svg) }
  184 +.bigicon-vertical-toggle { background-image: url(Tango/scalable/actions/mail-send-receive.svg) }
  185 +.bigicon-text-html { background-image: url(Tango/scalable/mimetypes/text-html.svg) }
  186 +.bigicon-text-plain { background-image: url(Tango/scalable/mimetypes/text-x-generic.svg) }
  187 +.bigicon-image-svg-xml { background-image: url(Tango/scalable/mimetypes/image-x-generic.svg) }
  188 +.bigicon-application-octet-stream { background-image: url(Tango/scalable/mimetypes/binary.svg) }
  189 +.bigicon-application-x-gzip { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-x-gzip.svg) }
  190 +.bigicon-application-postscript { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-postscript.svg) }
  191 +.bigicon-application-pdf { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-pdf.svg) }
  192 +.bigicon-application-ogg { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-ogg.svg) }
  193 +.bigicon-video, .icon-video-mpeg { background-image: url(Tango/scalable/mimetypes/video-x-generic.svg) }
  194 +.bigicon-application-vnd-oasis-opendocument-text { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-vnd.oasis.opendocument.text.svg) }
  195 +.bigicon-application-vnd-oasis-opendocument-spreadsheet { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-vnd.oasis.opendocument.spreadsheet.svg) }
  196 +.bigicon-application-vnd-oasis-opendocument-presentation { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-vnd.oasis.opendocument.presentation.svg) }
  197 +.bigicon-welcome-page { background-image: url(mod/scalable/mimetypes/welcome-page.svg) }
  198 +.bigicon-blocks { background-image: url(mod/scalable/mimetypes/blocks.svg) }
  199 +.bigicon-header-footer { background-image: url(mod/scalable/mimetypes/header-footer.svg) }
  200 +.bigicon-appearance { background-image: url(Tango/scalable/apps/preferences-desktop-wallpaper.svg) }
  201 +.bigicon-media-pause { background-image: url(Tango/scalable/actions/media-playback-pause.svg) }
  202 +.bigicon-media-play { background-image: url(Tango/scalable/actions/media-playback-start.svg) }
  203 +.bigicon-media-prev { background-image: url(Tango/scalable/actions/media-skip-backward.svg) }
  204 +.bigicon-media-next { background-image: url(Tango/scalable/actions/media-skip-forward.svg) }
  205 +.bigicon-lock { background-image: url(Tango/scalable/actions/lock.svg) }
  206 +.bigicon-chat { background-image: url(Tango/scalable/apps/internet-group-chat.svg); background-repeat: no-repeat }
  207 +.bigicon-reply { background-image: url(Tango/scalable/actions/mail-reply-sender.svg) }
  208 +.bigicon-newforum { background-image: url(Tango/scalable/apps/internet-group-chat.svg) }
  209 +.bigicon-forum { background-image: url(Tango/scalable/apps/system-users.svg) }
  210 +.bigicon-gallery { background-image: url(Tango/scalable/mimetypes/image-x-generic.svg) }
  211 +.bigicon-newgallery { background-image: url(Tango/scalable/mimetypes/image-x-generic.svg) }
  212 +.bigicon-locale { background-image: url(Tango/scalable/apps/preferences-desktop-locale.svg) }
  213 +.bigicon-user-removed { background-image: url(Tango/scalable/actions/gtk-cancel.svg) }
  214 +.bigicon-user-unknown { background-image: url(Tango/scalable/status/dialog-error.svg) }
  215 +.bigicon-alert { background-image: url(Tango/scalable/status/dialog-warning.svg) }
  216 +.bigicon-clone { background-image: url(Tango/scalable/actions/edit-copy.svg) }
  217 +.bigicon-activate-user { background-image: url(Tango/scalable/emblems/emblem-system.svg) }
  218 +.bigicon-deactivate-user { background-image: url(Tango/scalable/emblems/emblem-unreadable.svg) }
  219 +.bigicon-clock { background-image: url(Tango/scalable/actions/appointment.svg) }
  220 +
120 221 /******************LARGE ICONS********************/
121 222 .image-gallery-item .folder { background-image: url(mod/96x96/places/folder.png) }
122 223 .image-gallery-item .gallery { background-image: url(mod/96x96/mimetypes/image-x-generic.png) }
... ...
public/designs/themes/base/style.css
... ... @@ -1401,3 +1401,17 @@ table.profile th {
1401 1401 table#recaptcha_table tr:hover td {
1402 1402 background-color: #fff;
1403 1403 }
  1404 +
  1405 +/* product cateogories */
  1406 +#categories-container #product_category_id {
  1407 + font-size: 18px;
  1408 + width: 100%;
  1409 + margin-bottom: 8px;
  1410 +}
  1411 +#categories-container #product_category_id:focus {
  1412 + outline: none;
  1413 + border-color: green;
  1414 + box-shadow: 0 0 10px green;
  1415 + color:#333;
  1416 +}
  1417 +
... ...
public/images/icons-app/image-loading-bigicon.png 0 → 100644

3.24 KB

public/javascripts/application.js
... ... @@ -1230,7 +1230,10 @@ window.isHidden = function isHidden() { return (typeof(document.hidden) != &#39;unde
1230 1230  
1231 1231 function $_GET(id){
1232 1232 var a = new RegExp(id+"=([^&#=]*)");
1233   - return decodeURIComponent(a.exec(window.location.search)[1]);
  1233 + var result_of_search = a.exec(window.location.search)
  1234 + if(result_of_search != null){
  1235 + return decodeURIComponent(result_of_search[1]);
  1236 + }
1234 1237 }
1235 1238  
1236 1239 var fullwidth=false;
... ... @@ -1258,4 +1261,3 @@ function fullscreenPageLoad(itemId){
1258 1261 }
1259 1262 });
1260 1263 }
1261   -
... ...
public/javascripts/media-panel.js
1   -var file_id = 1;
2   -
3   -jQuery('.view-all-media').on('click', '.pagination a', function(event) {
4   - jQuery.ajax({
5   - url: this.href,
6   - beforeSend: function(){jQuery('.view-all-media').addClass('fetching')},
7   - complete: function() {jQuery('.view-all-media').removeClass('fetching')},
8   - dataType: 'script'
  1 +(function($) {
  2 + "use strict";
  3 +
  4 + var file_id = 1;
  5 +
  6 + $('.view-all-media').on('click', '.pagination a', function(event) {
  7 + $.ajax({
  8 + url: this.href,
  9 + beforeSend: function(){$('.view-all-media').addClass('fetching')},
  10 + complete: function() {$('.view-all-media').removeClass('fetching')},
  11 + dataType: 'script'
  12 + });
  13 + return false;
9 14 });
10   - return false;
11   -});
12   -
13   -jQuery('#file').fileupload({
14   - add: function(e, data){
15   - data.files[0].id = file_id;
16   - file_id++;
17   - data.context = jQuery(tmpl("template-upload", data.files[0]));
18   - jQuery('#media-upload-form').append(data.context);
19   - data.submit();
20   - },
21   - progress: function (e, data) {
22   - if (jQuery('#hide-uploads').data('bootstraped') == false) {
23   - jQuery('#hide-uploads').show();
24   - jQuery('#hide-uploads').data('bootstraped', true);
25   - }
26   - if (data.context) {
27   - progress = parseInt(data.loaded / data.total * 100, 10);
28   - data.context.find('.bar').css('width', progress + '%');
29   - data.context.find('.percentage').text(progress + '%');
30   - }
31   - },
32   - fail: function(e, data){
33   - var file_id = '#file-'+data.files[0].id;
34   - jQuery(file_id).find('.progress .bar').addClass('error');
35   - jQuery(file_id).append("<div class='error-message'>" + data.jqXHR.responseText + "</div>")
36   - }
37   -});
38   -
39   -jQuery('#hide-uploads').click(function(){
40   - jQuery('#hide-uploads').hide();
41   - jQuery('#show-uploads').show();
42   - jQuery('.upload').slideUp();
43   - return false;
44   -});
45   -
46   -jQuery('#show-uploads').click(function(){
47   - jQuery('#hide-uploads').show();
48   - jQuery('#show-uploads').hide();
49   - jQuery('.upload').slideDown();
50   - return false;
51   -});
52   -
53   -function loadPublishedMedia() {
54   - var parent_id = jQuery('#published-media #parent_id').val();
55   - var q = jQuery('#published-media #q').val();
56   - var url = jQuery('#published-media').data('url');
57   -
58   - jQuery('#published-media .items').addClass('fetching');
59   - jQuery.ajax({
60   - url: url,
61   - data: {'parent_id': parent_id, 'q': q},
62   - dataType: 'html',
63   - success: function(response) {
64   - jQuery("#published-media .items").html(response);
65   - jQuery('#published-media .items').removeClass('fetching');
66   - updateViewAllLinks();
  15 +
  16 +
  17 + $('#file').fileupload({
  18 + add: function(e, data){
  19 + data.files[0].id = file_id;
  20 + file_id++;
  21 + data.context = $(tmpl("template-upload", data.files[0]));
  22 + $('#media-upload-form').append(data.context);
  23 + data.submit();
  24 + },
  25 + progress: function (e, data) {
  26 + if ($('#hide-uploads').data('bootstraped') == false) {
  27 + $('#hide-uploads').show();
  28 + $('#hide-uploads').data('bootstraped', true);
  29 + }
  30 + if (data.context) {
  31 + var progress = parseInt(data.loaded / data.total * 100, 10);
  32 + data.context.find('.bar').css('width', progress + '%');
  33 + data.context.find('.percentage').text(progress + '%');
  34 + }
67 35 },
68   - error: function(response, textStatus, xhr) {
69   - console.log(response);
70   - console.log(textStatus);
  36 + fail: function(e, data){
  37 + var file_id = '#file-'+data.files[0].id;
  38 + $(file_id).find('.progress .bar').addClass('error');
  39 + $(file_id).append("<div class='error-message'>" + data.jqXHR.responseText + "</div>")
71 40 }
72 41 });
73   -}
74   -
75   -function updateViewAllLinks() {
76   - var parent_id = jQuery('#published-media #parent_id').val();
77   - var q = jQuery('#published-media #q').val();
78   - jQuery('#published-media .view-all').each(function(){
79   - var key = jQuery(this).data('key');
80   - var params = {parent_id: parent_id, q: q, key: key}
81   - var href = jQuery(this).attr('href');
82   - href = href.replace(/\?.*/, '?'+jQuery.param(params));
83   - jQuery(this).attr('href', href);
  42 +
  43 +
  44 + $('#hide-uploads').click(function(){
  45 + $('#hide-uploads').hide();
  46 + $('#show-uploads').show();
  47 + $('.upload').slideUp();
  48 + return false;
  49 + });
  50 +
  51 +
  52 + $('#show-uploads').click(function(){
  53 + $('#hide-uploads').show();
  54 + $('#show-uploads').hide();
  55 + $('.upload').slideDown();
  56 + return false;
84 57 });
85   -}
86   -
87   -jQuery('#published-media #parent_id').change(function(){ loadPublishedMedia() });
88   -
89   -jQuery("#published-media #q").typeWatch({
90   - callback: function (value) { loadPublishedMedia() },
91   - wait: 750,
92   - highlight: true,
93   - captureLength: 2
94   -});
95   -
96   -jQuery("#published-media #q").bind('notext', function(){ loadPublishedMedia() });
97   -
98   -jQuery("#new-folder-dialog").submit(function( event ) {
99   - var name = jQuery('#new_folder').val();
100   - var parent_id = jQuery("#new-folder-dialog #parent_id").val();
101   - jQuery.ajax({
102   - url: this.action,
103   - type: 'POST',
104   - data: {
105   - 'parent_id': parent_id,
106   - 'article': {'name': name, 'published': true},
107   - 'type': jQuery('input[name=folder_type]:checked').val() },
108   - dataType: 'json',
109   - beforeSend: function(){jQuery("#new-folder-dialog").addClass('fetching')},
110   - success: function(response) {
111   - var option_selected = "<option value='"+ response.id +"' selected='selected'>"+ response.full_name +"</options>"
112   - var option = "<option value='"+ response.id +"'>"+ response.full_name +"</options>"
113   - jQuery('#media-upload-form #parent_id').append(option_selected);
114   - jQuery('#published-media #parent_id').append(option);
115   - jQuery('#new_folder').val('');
116   - },
117   - error: function(response, textStatus, xhr) {
118   - console.log(response);
119   - console.log(textStatus);
120   - },
121   - complete: function(response){
122   - jQuery("#new-folder-dialog").removeClass('fetching');
123   - jQuery("#new-folder-dialog").dialog('close');
124   - }
  58 +
  59 +
  60 + function loadPublishedMedia() {
  61 + var parent_id = $('#published-media #parent_id').val();
  62 + var q = $('#published-media #q').val();
  63 + var url = $('#published-media').data('url');
  64 +
  65 + $('#published-media .items').addClass('fetching');
  66 + $.ajax({
  67 + url: url,
  68 + data: {'parent_id': parent_id, 'q': q},
  69 + dataType: 'html',
  70 + success: function(response) {
  71 + $("#published-media .items").html(response);
  72 + $('#published-media .items').removeClass('fetching');
  73 + updateViewAllLinks();
  74 + },
  75 + error: function(response, textStatus, xhr) {
  76 + console.log(response);
  77 + console.log(textStatus);
  78 + }
  79 + });
  80 + }
  81 + // make it global for usage in media_upload.js.erb
  82 + window.loadPublishedMedia = loadPublishedMedia;
  83 +
  84 +
  85 + function updateViewAllLinks() {
  86 + var parent_id = $('#published-media #parent_id').val();
  87 + var q = $('#published-media #q').val();
  88 + $('#published-media .view-all').each(function(){
  89 + var key = $(this).data('key');
  90 + var params = {parent_id: parent_id, q: q, key: key}
  91 + var href = $(this).attr('href');
  92 + href = href.replace(/\?.*/, '?'+$.param(params));
  93 + $(this).attr('href', href);
  94 + });
  95 + }
  96 +
  97 +
  98 + $('#published-media #parent_id').change(function(){
  99 + loadPublishedMedia()
  100 + });
  101 +
  102 +
  103 + // Using a immediate function to make timer variable only visible for the keyup event
  104 + (function() {
  105 + var timer = null;
  106 +
  107 + $("#published-media #q").keyup(function() {
  108 + if(this.value.length > 2) {
  109 + timer = setTimeout(loadPublishedMedia, 750);
  110 + }
  111 + }).keydown(function() {
  112 + clearTimeout(timer);
  113 + });
  114 + }) ();
  115 +
  116 +
  117 + $("#published-media #q").bind('notext', function(){
  118 + loadPublishedMedia()
  119 + });
  120 +
  121 +
  122 + $("#new-folder-dialog").submit(function( event ) {
  123 + var name = $('#new_folder').val();
  124 + var parent_id = $("#new-folder-dialog #parent_id").val();
  125 + $.ajax({
  126 + url: this.action,
  127 + type: 'POST',
  128 + data: {
  129 + 'parent_id': parent_id,
  130 + 'article': {'name': name, 'published': true},
  131 + 'type': $('input[name=folder_type]:checked').val() },
  132 + dataType: 'json',
  133 + beforeSend: function(){$("#new-folder-dialog").addClass('fetching')},
  134 + success: function(response) {
  135 + var option_selected = "<option value='"+ response.id +"' selected='selected'>"+ response.full_name +"</options>"
  136 + var option = "<option value='"+ response.id +"'>"+ response.full_name +"</options>"
  137 + $('#media-upload-form #parent_id').append(option_selected);
  138 + $('#published-media #parent_id').append(option);
  139 + $('#new_folder').val('');
  140 + },
  141 + error: function(response, textStatus, xhr) {
  142 + console.log(response);
  143 + console.log(textStatus);
  144 + },
  145 + complete: function(response){
  146 + $("#new-folder-dialog").removeClass('fetching');
  147 + $("#new-folder-dialog").dialog('close');
  148 + }
  149 + });
  150 + return false;
  151 + });
  152 +
  153 + $('.icon-vertical-toggle').click(function(){
  154 + $('#content').toggleClass('show-media-panel');
  155 + return false;
125 156 });
126   - return false;
127   -});
128   -
129   -jQuery('.text-editor-sidebar .header .icon-vertical-toggle').click(function(){
130   - jQuery('#content').toggleClass('show-media-panel');
131   - return false;
132   -});
133   -
134   -jQuery('#new-folder-button').click(function(){
135   - jQuery('#new-folder-dialog').dialog({modal: true});
136   - return false;
137   -});
  157 +
  158 +
  159 + $('#new-folder-button').click(function(){
  160 + $('#new-folder-dialog').dialog({modal: true});
  161 + return false;
  162 + });
  163 +
  164 +}) (jQuery);
... ...
public/javascripts/product_categories.js 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +product_categories = {
  2 +
  3 + autocomplete: {
  4 + search_url: '',
  5 + select_url: '',
  6 +
  7 + load: function(elem) {
  8 + elem = jQuery(elem)
  9 +
  10 + elem.autocomplete({
  11 + minLength: 3,
  12 + selectFirst: true,
  13 +
  14 + //define callback to retrieve results
  15 + source: function(req, add) {
  16 + //pass request to server
  17 + //The alt attribute contains the wordpress callback action
  18 + var params = { term: req.term };
  19 + jQuery.getJSON(product_categories.autocomplete.search_url, params, function(data) {
  20 + add(data);
  21 + });
  22 + },
  23 +
  24 + focus: function( event, ui ) {
  25 + jQuery(this).val(ui.item.label);
  26 + return false;
  27 + },
  28 +
  29 + select: function(e, ui) {
  30 + jQuery('#categories-container').load(product_categories.autocomplete.select_url, {category_id: ui.item.value})
  31 +
  32 + jQuery(this).val("")
  33 + },
  34 +
  35 + });
  36 +
  37 + },
  38 + },
  39 +
  40 +};
... ...
public/stylesheets/application.css
... ... @@ -1560,6 +1560,32 @@ div.article-body p img {
1560 1560 #content .blog-post .read-more a {
1561 1561 margin: 0 10px;
1562 1562 }
  1563 +
  1564 +#content #article .blog-posts .blog-post .article-compact-abstract{
  1565 + position: relative;
  1566 + float:left;
  1567 + margin-left: 10px;
  1568 + width: 100%;
  1569 + word-wrap: break-word;
  1570 +}
  1571 +
  1572 +#content #article .blog-posts .blog-post .article-compact-image{
  1573 + position:relative;
  1574 + float:left;
  1575 + width: 27%;
  1576 + display: table-cell;
  1577 + vertical-align: middle;
  1578 + text-align: center;
  1579 + margin-top: 15px;
  1580 +}
  1581 +
  1582 +#content #article .blog-posts .blog-post .article-compact-abstract-with-image{
  1583 + position: relative;
  1584 + float:left;
  1585 + margin-left: 10px;
  1586 + width: 70%;
  1587 + word-wrap: break-word;
  1588 +}
1563 1589 /* NOT PUBLISHED BLOG POSTS */
1564 1590  
1565 1591 .blog-post.not-published {
... ... @@ -3829,6 +3855,11 @@ table.cms-articles .icon:hover {
3829 3855  
3830 3856 /* Folders */
3831 3857  
  3858 +.article-body ul.folder-content {
  3859 + list-style-type: none;
  3860 + padding: 0;
  3861 +}
  3862 +
3832 3863 .folder-content .folder-item img {
3833 3864 vertical-align: middle;
3834 3865 position: relative;
... ... @@ -3894,6 +3925,62 @@ table.cms-articles .icon:hover {
3894 3925 right: auto;
3895 3926 left: auto;
3896 3927 }
  3928 +
  3929 +/**************Folder Style**********************/
  3930 +
  3931 +.list-item{
  3932 + font-family: arial;
  3933 + color: #172738;
  3934 +}
  3935 +
  3936 +div.folder-description {
  3937 + padding-bottom: 15px;
  3938 +}
  3939 +
  3940 +.list-item h2{
  3941 + border-bottom:1px solid #ccc;
  3942 + margin:0px;
  3943 +}
  3944 +
  3945 +.item-info{
  3946 + border-top: 1px solid #ccc;
  3947 + line-height: 25px;
  3948 + padding:25px 20px;
  3949 +}
  3950 +
  3951 +.item-info a{
  3952 + text-decoration: none !important;
  3953 + font-size: 16px;
  3954 + font-weight: bold;
  3955 +}
  3956 +
  3957 +.item-icon a {
  3958 + float: left;
  3959 + width: 50px;
  3960 + height: 50px;
  3961 + background-repeat: no-repeat;
  3962 + background-position: center center;
  3963 +}
  3964 +
  3965 +span.item-type {
  3966 + font-size: 12px;
  3967 +}
  3968 +
  3969 +.item-description{
  3970 + display: block;
  3971 + position:relative;
  3972 + margin-left: 15%;
  3973 + padding-left: 10px;
  3974 +}
  3975 +
  3976 +.item-date{
  3977 + display:block;
  3978 + position:relative;
  3979 + font-size: 12px;
  3980 + margin-left: 15%;
  3981 + padding-left: 10px;
  3982 +}
  3983 +
3897 3984 /************* enterprise homepage style *****************/
3898 3985  
3899 3986 div.event-info {
... ...
test/functional/admin_panel_controller_test.rb
... ... @@ -130,6 +130,19 @@ class AdminPanelControllerTest &lt; ActionController::TestCase
130 130 assert_equal "This <strong>is</strong> my new environment", Environment.default.message_for_disabled_enterprise
131 131 end
132 132  
  133 + should 'save site article date format option' do
  134 + post :site_info, :environment => { :date_format => "numbers_with_year" }
  135 + assert_redirected_to :action => 'index'
  136 +
  137 + assert_equal "numbers_with_year", Environment.default.date_format
  138 + end
  139 +
  140 + should 'dont save site article date format option when a invalid option is passed' do
  141 + post :site_info, :environment => { :date_format => "invalid_format" }
  142 +
  143 + assert_not_equal "invalid_format", Environment.default.date_format
  144 + end
  145 +
133 146 should 'set portal community' do
134 147 e = Environment.default
135 148 @controller.stubs(:environment).returns(e)
... ...
test/functional/application_controller_test.rb
... ... @@ -484,7 +484,7 @@ class ApplicationControllerTest &lt; ActionController::TestCase
484 484 should 'change postgresql schema' do
485 485 uses_host 'schema1.com'
486 486 Noosfero::MultiTenancy.expects(:on?).returns(true)
487   - Noosfero::MultiTenancy.expects(:mapping).returns({ 'schema1.com' => 'schema1' })
  487 + Noosfero::MultiTenancy.expects(:mapping).returns({ 'schema1.com' => 'schema1' }).at_least_once
488 488 exception = assert_raise(ActiveRecord::StatementInvalid) { get :index }
489 489 assert_match /SET search_path TO schema1/, exception.message
490 490 end
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -275,7 +275,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
275 275  
276 276 get :view_page, :profile => 'test_profile', :page => [ 'my-intranet' ]
277 277  
278   - assert_template "profile/_private_profile"
  278 + assert_template "shared/access_denied"
279 279 end
280 280  
281 281 should 'not give access to private articles if logged in but not member' do
... ... @@ -1540,12 +1540,12 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1540 1540 should 'use context method in extra toolbar actions on article from plugins' do
1541 1541 class Plugin1 < Noosfero::Plugin
1542 1542 def article_extra_toolbar_buttons(article)
1543   - if current_person.public?
  1543 + if profile.public?
1544 1544 {:title => 'some_title', :icon => 'some_icon', :url => '/someurl'}
1545 1545 else
1546 1546 {:title => 'another_title', :icon => 'another_icon', :url => '/anotherurl'}
1547 1547 end
1548   - end
  1548 + end
1549 1549 end
1550 1550 Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
1551 1551  
... ... @@ -1560,4 +1560,31 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1560 1560 assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :href => "/anotherurl" }}
1561 1561 end
1562 1562  
  1563 + should 'show lead,image and title in compact blog visualization' do
  1564 + community = Community.create(:name => 'test-community')
  1565 + community.add_member(@profile)
  1566 + community.save!
  1567 +
  1568 + blog = community.articles.find_by_name("Blog")
  1569 + blog.visualization_format = 'compact'
  1570 + blog.save!
  1571 +
  1572 + article = TinyMceArticle.create(:name => 'Article to be shared with images',
  1573 + :body => 'This article should be shared with all social networks',
  1574 + :profile => @profile,
  1575 + :published => false,
  1576 + :abstract => "teste teste teste",
  1577 + :show_to_followers => true,
  1578 + :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')} )
  1579 + article.parent = blog
  1580 + article.save!
  1581 +
  1582 + login_as(@profile.identifier)
  1583 +
  1584 +
  1585 + get :view_page, :profile => community.identifier, "page" => 'blog'
  1586 +
  1587 + assert_tag :tag => 'div', :attributes => { :class => 'article-compact-image' }
  1588 + assert_tag :tag => 'div', :attributes => { :class => 'article-compact-abstract-with-image' }
  1589 + end
1563 1590 end
... ...
test/functional/organizations_controller_test.rb
... ... @@ -86,22 +86,22 @@ class OrganizationsControllerTest &lt; ActionController::TestCase
86 86  
87 87 should 'activate organization profile' do
88 88 organization = fast_create(Organization, :visible => false, :environment_id => environment.id)
89   - assert organization.disabled?
  89 + assert !organization.visible?
90 90  
91 91 get :activate, {:id => organization.id}
92 92 organization.reload
93 93  
94   - assert organization.enabled?
  94 + assert organization.visible
95 95 end
96 96  
97 97 should 'deactivate organization profile' do
98 98 organization = fast_create(Organization, :visible => true, :environment_id => environment.id)
99   - assert organization.enabled?
  99 + assert organization.visible
100 100  
101 101 get :deactivate, {:id => organization.id}
102 102 organization.reload
103 103  
104   - assert organization.disabled?
  104 + assert !organization.visible
105 105 end
106 106  
107 107 should 'destroy organization profile' do
... ...
test/functional/profile_controller_test.rb
... ... @@ -508,11 +508,15 @@ class ProfileControllerTest &lt; ActionController::TestCase
508 508 end
509 509  
510 510 should 'show description of person' do
  511 + environment = Environment.default
  512 + environment.custom_person_fields = {:description => { :active => true, :required => false, :signup => false }}
  513 + environment.save!
  514 + environment.reload
511 515 login_as(@profile.identifier)
512   - @profile.description = 'Person\'s description'
513   - @profile.save
  516 + @profile.description = 'Person description'
  517 + @profile.save!
514 518 get :index, :profile => @profile.identifier
515   - assert_tag :tag => 'div', :attributes => { :class => 'public-profile-description' }, :content => /Person\'s description/
  519 + assert_tag :tag => 'div', :attributes => { :class => 'public-profile-description' }, :content => /Person description/
516 520 end
517 521  
518 522 should 'not show description of orgarnization if not filled' do
... ...
test/integration/routing_test.rb
... ... @@ -135,7 +135,7 @@ class RoutingTest &lt; ActionController::IntegrationTest
135 135 end
136 136  
137 137 def test_assets_routing
138   - assert_routing('/assets/my-asset/a/b/c', :controller => 'search', :action => 'assets', :asset => 'my-asset', :category_path => 'a/b/c')
  138 + assert_routing('/search/assets/a/b/c', :controller => 'search', :action => 'assets', :category_path => 'a/b/c')
139 139 end
140 140  
141 141 def test_content_view_with_dot
... ...
test/test_helper.rb
... ... @@ -262,10 +262,6 @@ module NoosferoTestHelper
262 262 arg
263 263 end
264 264  
265   - def show_date(date)
266   - date.to_s
267   - end
268   -
269 265 def strip_tags(html)
270 266 html.gsub(/<[^>]+>/, '')
271 267 end
... ...
test/unit/application_helper_test.rb
... ... @@ -564,18 +564,6 @@ class ApplicationHelperTest &lt; ActionView::TestCase
564 564 assert_equal environment.theme, current_theme
565 565 end
566 566  
567   - should 'trunc to 15 chars the big filename' do
568   - assert_equal 'AGENDA(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3',15)
569   - end
570   -
571   - should 'trunc to default limit the big filename' do
572   - assert_equal 'AGENDA_CULTURA_-_FESTA_DE_VAQUEIRO(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3')
573   - end
574   -
575   - should 'does not trunc short filename' do
576   - assert_equal 'filename.mp3', short_filename('filename.mp3')
577   - end
578   -
579 567 should 'return nil when :show_balloon_with_profile_links_when_clicked is not enabled in environment' do
580 568 env = Environment.default
581 569 env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(false)
... ...
test/unit/blog_test.rb
... ... @@ -161,7 +161,16 @@ class BlogTest &lt; ActiveSupport::TestCase
161 161 assert_equal 'short', p.blog.visualization_format
162 162 end
163 163  
164   - should 'allow only full and short as visualization_format' do
  164 + should 'update visualization_format setting to compact' do
  165 + p = create_user('testuser').person
  166 + p.articles << build(Blog, :profile => p, :name => 'Blog test')
  167 + blog = p.blog
  168 + blog.visualization_format = 'compact'
  169 + assert blog.save!
  170 + assert_equal 'compact', p.blog.visualization_format
  171 + end
  172 +
  173 + should 'allow only full, short or compact as visualization_format' do
165 174 blog = build(Blog, :name => 'blog')
166 175 blog.visualization_format = 'wrong_format'
167 176 blog.valid?
... ... @@ -174,6 +183,10 @@ class BlogTest &lt; ActiveSupport::TestCase
174 183 blog.visualization_format = 'full'
175 184 blog.valid?
176 185 assert !blog.errors[:visualization_format.to_s].present?
  186 +
  187 + blog.visualization_format = 'compact'
  188 + blog.valid?
  189 + assert !blog.errors[:visualization_format.to_s].present?
177 190 end
178 191  
179 192 should 'have posts' do
... ...
test/unit/content_viewer_helper_test.rb
... ... @@ -18,7 +18,7 @@ class ContentViewerHelperTest &lt; ActionView::TestCase
18 18 result = article_title(post)
19 19 assert_tag_in_string result, :tag => 'span', :content => show_date(post.published_at)
20 20 end
21   -
  21 +
22 22 should 'display published-at for forum posts' do
23 23 forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id)
24 24 post = TextileArticle.create!(:name => 'post test', :profile => profile, :parent => forum)
... ... @@ -112,6 +112,42 @@ class ContentViewerHelperTest &lt; ActionView::TestCase
112 112 assert_match 'bt-bookmark.gif', addthis_image_tag
113 113 end
114 114  
  115 + should 'show date with mm/dd/yyyy' do
  116 + Environment.any_instance.stubs(:date_format).returns('numbers_with_year')
  117 + article = TextileArticle.new(:name => 'post for test', :body => 'post for test', :profile => profile)
  118 + article.published_at = Time.zone.local(2007, 2, 1, 15, 30, 45)
  119 + article.save!
  120 + result = show_with_right_format_date article
  121 + assert_match /2\/1\/2007/, result
  122 + end
  123 +
  124 + should 'show date with mm/dd' do
  125 + Environment.any_instance.stubs(:date_format).returns('numbers')
  126 + article = TextileArticle.new(:name => 'post for test', :body => 'post for test', :profile => profile)
  127 + article.published_at = Time.zone.local(2007, 2, 1, 15, 30, 45)
  128 + article.save!
  129 + result = show_with_right_format_date article
  130 + assert_match /2\/1/, result
  131 + end
  132 +
  133 + should 'show date with month name' do
  134 + Environment.any_instance.stubs(:date_format).returns('month_name')
  135 + article = TextileArticle.new(:name => 'post for test', :body => 'post for test', :profile => profile)
  136 + article.published_at = Time.zone.local(2007, 2, 1, 15, 30, 45)
  137 + article.save!
  138 + result = show_with_right_format_date article
  139 + assert_match /February 1/, result
  140 + end
  141 +
  142 + should 'show date with month name and year' do
  143 + Environment.any_instance.stubs(:date_format).returns('month_name_with_year')
  144 + article = TextileArticle.new(:name => 'post for test', :body => 'post for test', :profile => profile)
  145 + article.published_at = Time.zone.local(2007, 2, 1, 15, 30, 45)
  146 + article.save!
  147 + result = show_with_right_format_date article
  148 + assert_match /February 1, 2007/, result
  149 + end
  150 +
115 151 protected
116 152 include NoosferoTestHelper
117 153 include ActionView::Helpers::TextHelper
... ...
test/unit/dates_helper_test.rb
... ... @@ -146,4 +146,9 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
146 146 assert_equal Date.new(Date.today.year, Date.today.month, 1), build_date('', '')
147 147 end
148 148  
  149 + should 'show how long it has passed since a specific date' do
  150 + date = Time.zone.now
  151 + assert_equal show_date(date, false, false, true), time_ago_in_words(date)
  152 + end
  153 +
149 154 end
... ...
test/unit/environment_test.rb
... ... @@ -1703,4 +1703,32 @@ class EnvironmentTest &lt; ActiveSupport::TestCase
1703 1703 assert !e.has_license?
1704 1704 end
1705 1705  
  1706 + should 'validates_inclusion_of date format' do
  1707 + environment = fast_create(Environment)
  1708 +
  1709 + environment.date_format = "invalid_format"
  1710 + environment.valid?
  1711 + assert environment.errors[:date_format.to_s].present?
  1712 +
  1713 + environment.date_format = "numbers_with_year"
  1714 + environment.valid?
  1715 + assert !environment.errors[:date_format.to_s].present?
  1716 +
  1717 + environment.date_format = "numbers"
  1718 + environment.valid?
  1719 + assert !environment.errors[:date_format.to_s].present?
  1720 +
  1721 + environment.date_format = "month_name_with_year"
  1722 + environment.valid?
  1723 + assert !environment.errors[:date_format.to_s].present?
  1724 +
  1725 + environment.date_format = "month_name"
  1726 + environment.valid?
  1727 + assert !environment.errors[:date_format.to_s].present?
  1728 +
  1729 + environment.date_format = "past_time"
  1730 + environment.valid?
  1731 + assert !environment.errors[:date_format.to_s].present?
  1732 + end
  1733 +
1706 1734 end
... ...
test/unit/events_helper_test.rb
... ... @@ -8,27 +8,13 @@ class EventsHelperTest &lt; ActiveSupport::TestCase
8 8 user = create_user('userwithevents').person
9 9 stubs(:user).returns(user)
10 10  
11   - expects(:show_date_month).returns('')
12   - expects(:_).with('Events for %s').returns('').once
13   - expects(:_).with(' to ').returns('').twice
14   - expects(:_).with('Place: ').returns('').twice
15   - expects(:_).with('No events for this month').returns('').never
16   -
17   - event1 = mock;
18   - event1.expects(:display_to?).with(anything).returns(true).once;
19   - event1.expects(:start_date).returns(Date.today).once
20   - event1.expects(:end_date).returns(Date.today + 1.day).twice
21   - event1.expects(:name).returns('Event 1').once
22   - event1.expects(:url).returns({}).once
23   - event1.expects(:address).returns('The Shire').times(3)
24   -
25   - event2 = mock;
26   - event2.expects(:display_to?).with(anything).returns(true).once
27   - event2.expects(:start_date).returns(Date.today).once
28   - event2.expects(:end_date).returns(Date.today + 1.day).twice
29   - event2.expects(:name).returns('Event 2').once
30   - event2.expects(:url).returns({}).once
31   - event2.expects(:address).returns('Valfenda').times(3)
  11 + event1 = Event.new(name: "Event 1", start_date: Date.today, end_date: (Date.today + 1.day), address: 'The Shire')
  12 + event1.profile = user
  13 + event1.save
  14 +
  15 + event2 = Event.new(name: 'Event 2', start_date: Date.today, end_date: (Date.today + 1.day), address: 'Valfenda')
  16 + event2.profile = user
  17 + event2.save
32 18  
33 19 result = list_events(Date.today, [event1, event2])
34 20  
... ...
test/unit/folder_helper_test.rb
... ... @@ -89,27 +89,14 @@ class FolderHelperTest &lt; ActionView::TestCase
89 89 assert_not_includes result, article
90 90 end
91 91  
92   - should 'list subitems as HTML content' do
  92 + should 'display the proper content icon' do
93 93 profile = create_user('folder-owner').person
94 94 folder = fast_create(Folder, {:name => 'Parent Folder', :profile_id => profile.id})
95 95 article1 = fast_create(Article, {:name => 'Article1', :parent_id => folder.id, :profile_id => profile.id, :updated_at => DateTime.now })
96 96 article2 = fast_create(Article, {:name => 'Article2', :parent_id => folder.id, :profile_id => profile.id, :updated_at => DateTime.now })
97   - self.stubs(:params).returns({:npage => nil})
98   -
99   - contents = folder.children.order('updated_at DESC').paginate(:per_page => 10, :page => params[:npage])
100   - expects(:user).returns(profile).at_least_once
101   - expects(:list_type).returns(:folder).at_least_once
102   - expects(:recursive).returns(false).at_least_once
103   - expects(:pagination_links).with(anything, anything).returns('')
104   - list = render 'shared/content_list', binding
105   - expects(:render).with(:file => 'shared/content_list',
106   - :locals => { :contents => contents, :recursive => false, :list_type => :folder }
107   - ).returns(list)
108   -
109   - result = list_contents(:contents=>contents)
110   -
111   - assert_tag_in_string result, :tag => 'td', :descendant => { :tag => 'a', :attributes => { :href => /.*\/folder-owner\/my-article-[0-9]*(\?|$)/ } }, :content => /Article1/
112   - assert_tag_in_string result, :tag => 'td', :descendant => { :tag => 'a', :attributes => { :href => /.*\/folder-owner\/my-article-[0-9]*(\?|$)/ } }, :content => /Article2/
  97 +
  98 + assert_tag_in_string display_content_icon(article1), :tag => 'a', :attributes => { :href => /.*\/folder-owner\/my-article-[0-9]*(\?|$)/ }
  99 + assert_tag_in_string display_content_icon(article2), :tag => 'a', :attributes => { :href => /.*\/folder-owner\/my-article-[0-9]*(\?|$)/ }
113 100 end
114 101  
115 102 should 'explictly advise if empty' do
... ...
test/unit/forum_helper_test.rb
... ... @@ -7,6 +7,7 @@ class ForumHelperTest &lt; ActiveSupport::TestCase
7 7 include ContentViewerHelper
8 8 include ActionView::Helpers::AssetTagHelper
9 9 include ApplicationHelper
  10 + include ActionView::Helpers::DateHelper
10 11  
11 12 def setup
12 13 @environment = Environment.default
... ... @@ -41,7 +42,7 @@ class ForumHelperTest &lt; ActiveSupport::TestCase
41 42 some_post = create(TextileArticle, :name => 'First post', :profile => profile, :parent => forum, :published => true, :author => author)
42 43 assert some_post.comments.empty?
43 44 out = last_topic_update(some_post)
44   - assert_match some_post.updated_at.to_s, out
  45 + assert_match time_ago_in_words(some_post.updated_at), out
45 46 assert_match /forum test author/, out
46 47 end
47 48  
... ... @@ -53,10 +54,11 @@ class ForumHelperTest &lt; ActiveSupport::TestCase
53 54 c = Comment.last
54 55 assert_equal 2, some_post.comments.count
55 56 out = last_topic_update(some_post)
56   - assert_match c.created_at.to_s, out
  57 + result = time_ago_in_words(c.created_at)
  58 + assert_match result, out
57 59 assert_match 'a2', out
58 60  
59   - assert_match(/#{Regexp.escape(c.created_at.to_s)} by <a href='[^']+'>a2<\/a>/, last_topic_update(some_post))
  61 + assert_match(/#{result} by <a href='[^']+'>a2<\/a>/, last_topic_update(some_post))
60 62 end
61 63  
62 64 should "return last comment author's name from unauthenticated user" do
... ... @@ -64,18 +66,15 @@ class ForumHelperTest &lt; ActiveSupport::TestCase
64 66 some_post.comments << build(Comment, :name => 'John', :email => 'lenon@example.com', :title => 'test', :body => 'test')
65 67 c = Comment.last
66 68 out = last_topic_update(some_post)
67   - assert_match "#{c.created_at.to_s} by John", out
  69 + result = time_ago_in_words(c.created_at)
  70 + assert_match "#{result} by John", out
68 71 assert_match 'John', out
69 72  
70   - assert_match(/#{Regexp.escape(c.created_at.to_s)} by John/m, last_topic_update(some_post))
  73 + assert_match(/#{result} by John/m, last_topic_update(some_post))
71 74 end
72 75  
73 76 protected
74 77  
75 78 include NoosferoTestHelper
76 79  
77   - def time_ago_as_sentence(t = Time.now)
78   - t.to_s
79   - end
80   -
81 80 end
... ...
test/unit/plugin_test.rb
... ... @@ -23,7 +23,7 @@ class PluginTest &lt; ActiveSupport::TestCase
23 23 end
24 24  
25 25 should 'returns empty hash for class method extra_blocks by default if no blocks are defined on plugin' do
26   -
  26 +
27 27 class SomePlugin1 < Noosfero::Plugin
28 28 end
29 29  
... ...
test/unit/short_filename_test.rb
... ... @@ -1,20 +0,0 @@
1   -require_relative "../test_helper"
2   -
3   -class NoosferoFilenamesTest < ActiveSupport::TestCase
4   -
5   - include ShortFilename
6   -
7   - should 'trunc to 15 chars the big filename' do
8   - assert_equal 'AGENDA(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3',15)
9   - end
10   -
11   - should 'trunc to default limit the big filename' do
12   - assert_equal 'AGENDA_CULTURA_-_FESTA_DE_VAQUEIRO(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3')
13   - end
14   -
15   - should 'does not trunc short filename' do
16   - assert_equal 'filename.mp3', short_filename('filename.mp3')
17   - end
18   -
19   -end
20   -
vendor/plugins/access_control/lib/permission_check.rb
... ... @@ -26,7 +26,7 @@ module PermissionCheck
26 26 end
27 27  
28 28 def render_access_denied(c)
29   - if c.respond_to?(:render_access_denied)
  29 + if c.respond_to?(:render_access_denied, true)
30 30 c.send(:render_access_denied)
31 31 else
32 32 c.send(:render, :template => access_denied_template_path, :status => 403)
... ...