Commit 0531c6a234fa8cf1abc7ad890d8e24d572d61d98

Authored by Leandro Santos
1 parent 02798bcc

merging with master

Showing 355 changed files with 38615 additions and 5958 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 355 files displayed.

Gemfile
... ... @@ -3,8 +3,6 @@ gem 'rails', '~> 3.2.21'
3 3 gem 'minitest', '~> 3.2.0'
4 4 gem 'fast_gettext', '~> 0.6.8'
5 5 gem 'acts-as-taggable-on', '~> 3.0.2'
6   -gem 'prototype-rails', '~> 3.2.1'
7   -gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
8 6 gem 'rails_autolink', '~> 1.1.5'
9 7 gem 'pg', '~> 0.13.2'
10 8 gem 'rmagick', '~> 2.13.1'
... ... @@ -13,8 +11,7 @@ gem 'will_paginate', '~> 3.0.3'
13 11 gem 'ruby-feedparser', '~> 0.7'
14 12 gem 'daemons', '~> 1.1.5'
15 13 gem 'thin', '~> 1.3.1'
16   -gem 'hpricot', '~> 0.8.6'
17   -gem 'nokogiri', '~> 1.6.0'
  14 +gem 'nokogiri', '~> 1.5.5'
18 15 gem 'rake', :require => false
19 16 gem 'grape', '~> 0.2.1'
20 17 gem 'rest-client', '~> 1.6.7'
... ... @@ -24,8 +21,7 @@ gem 'locale', '~> 2.0.5'
24 21  
25 22 gem 'whenever', :require => false
26 23  
27   -# FIXME list here all actual dependencies (i.e. the ones in debian/control),
28   -# with their GEM names (not the Debian package names)
  24 +gem 'eita-jrails', path: 'vendor/plugins/eita-jrails'
29 25  
30 26 group :production do
31 27 gem 'dalli', '~> 2.7.0'
... ... @@ -45,6 +41,9 @@ group :cucumber do
45 41 gem 'selenium-webdriver', '~> 2.39.0'
46 42 end
47 43  
  44 +# Requires custom dependencies
  45 +eval(File.read('config/Gemfile'), binding) rescue nil
  46 +
48 47 # include gemfiles from enabled plugins
49 48 # plugins in baseplugins/ are not included on purpose. They should not have any
50 49 # dependencies.
... ...
INSTALL.md
... ... @@ -21,7 +21,7 @@ Noosfero is written in Ruby with the "[Rails framework](http://www.rubyonrails.o
21 21 You need to install some packages Noosfero depends on. On Debian GNU/Linux or Debian-based systems, all of these packages are available through the Debian archive. You can install them with the following command:
22 22  
23 23 # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 \
24   - libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libhpricot-ruby \
  24 + libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby \
25 25 libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin \
26 26 tango-icon-theme
27 27  
... ... @@ -40,7 +40,6 @@ On other systems, they may or may not be available through your regular package
40 40 * Daemons - http://daemons.rubyforge.org
41 41 * Thin: http://code.macournoyer.com/thin
42 42 * tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library
43   -* Hpricot: http://hpricot.com
44 43  
45 44 If you manage to install Noosfero successfully on other systems than Debian,
46 45 please feel free to contact the Noosfero development mailing with the
... ...
INSTALL.multitenancy.md
... ... @@ -26,7 +26,7 @@ The file config/database.yml must follow a structure in order to achieve multite
26 26  
27 27 Each "hosted" environment must have an entry like this:
28 28  
29   - env1_production:
  29 + env1_production: &DEFAULT
30 30 adapter: postgresql
31 31 encoding: unicode
32 32 database: noosfero
... ... @@ -61,7 +61,7 @@ The "hosted" environments define, besides the `schema_search_path`, a list of do
61 61 You must also tell the application which is the default environment.
62 62  
63 63 production:
64   - env1_production
  64 + <<: *DEFAULT
65 65  
66 66 On the example above there are only three hosted environments, but it can be more than three. The schemas `env2` and `env3` must already exist in the same database of the hosting environment. As postgres user, you can create them typing:
67 67  
... ...
SECURITY.md 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +# Noosfero security
  2 +
  3 +## Reporting security issues in Noosfero
  4 +
  5 +Security vulnerabilities should be reported via an email to
  6 +noosfero-security@listas.softwarelivre.org, which ia a private mailing list.
  7 +Reported problems will be published after fixes are available.
  8 +
  9 +The members of the mailing list are people who provide Noosfero (Noosfero
  10 +committers, mainly).
... ...
app/controllers/admin/admin_panel_controller.rb
... ... @@ -87,6 +87,6 @@ class AdminPanelController &lt; AdminController
87 87 scope = scope.order('name ASC')
88 88  
89 89 @q = params[:q]
90   - @collection = find_by_contents(:organizations, scope, @q, {:per_page => 10, :page => params[:npage]})[:results]
  90 + @collection = find_by_contents(:organizations, environment, scope, @q, {:per_page => 10, :page => params[:npage]})[:results]
91 91 end
92 92 end
... ...
app/controllers/application_controller.rb
... ... @@ -33,6 +33,7 @@ class ApplicationController &lt; ActionController::Base
33 33 unless environment.access_control_allow_methods.blank?
34 34 response.headers["Access-Control-Allow-Methods"] = environment.access_control_allow_methods
35 35 end
  36 + response.headers["Access-Control-Allow-Credentials"] = 'true'
36 37 elsif environment.restrict_to_access_control_origins
37 38 render_access_denied _('Origin not in allowed.')
38 39 end
... ... @@ -64,15 +65,7 @@ class ApplicationController &lt; ActionController::Base
64 65 helper :document
65 66 helper :language
66 67  
67   - def self.no_design_blocks
68   - @no_design_blocks = true
69   - end
70   - def self.uses_design_blocks?
71   - !@no_design_blocks
72   - end
73   - def uses_design_blocks?
74   - !@no_design_blocks && self.class.uses_design_blocks?
75   - end
  68 + include DesignHelper
76 69  
77 70 # Be sure to include AuthenticationSystem in Application Controller instead
78 71 include AuthenticatedSystem
... ...
app/controllers/public/chat_controller.rb
... ... @@ -6,6 +6,7 @@ class ChatController &lt; PublicController
6 6 def start_session
7 7 login = user.jid
8 8 password = current_user.crypted_password
  9 + session[:chat] ||= {:rooms => []}
9 10 begin
10 11 jid, sid, rid = RubyBOSH.initialize_session(login, password, "http://#{environment.default_hostname}/http-bind",
11 12 :wait => 30, :hold => 1, :window => 5)
... ... @@ -16,6 +17,31 @@ class ChatController &lt; PublicController
16 17 end
17 18 end
18 19  
  20 + def toggle
  21 + session[:chat][:status] = session[:chat][:status] == 'opened' ? 'closed' : 'opened'
  22 + render :nothing => true
  23 + end
  24 +
  25 + def tab
  26 + session[:chat][:tab_id] = params[:tab_id]
  27 + render :nothing => true
  28 + end
  29 +
  30 + def join
  31 + session[:chat][:rooms] << params[:room_id]
  32 + session[:chat][:rooms].uniq!
  33 + render :nothing => true
  34 + end
  35 +
  36 + def leave
  37 + session[:chat][:rooms].delete(params[:room_id])
  38 + render :nothing => true
  39 + end
  40 +
  41 + def my_session
  42 + render :text => session[:chat].to_json, :layout => false
  43 + end
  44 +
19 45 def avatar
20 46 profile = environment.profiles.find_by_identifier(params[:id])
21 47 filename, mimetype = profile_icon(profile, :minor, true)
... ... @@ -51,18 +77,28 @@ class ChatController &lt; PublicController
51 77 messages = ChatMessage.where('(to_id=:other and from_id=:me) or (to_id=:me and from_id=:other)', {:me => user.id, :other => other.id})
52 78 end
53 79  
54   - messages = messages.order('created_at DESC').includes(:to, :from).limit(20)
  80 + messages = messages.order('created_at DESC').includes(:to, :from).offset(params[:offset]).limit(20)
55 81 messages_json = messages.map do |message|
56 82 {
57 83 :body => message.body,
58   - :to => {:id => message.to.identifier, :name => message.to.name, :type => message.to.type},
59   - :from => {:id => message.from.identifier, :name => message.from.name, :type => message.from.type},
  84 + :to => {:id => message.to.identifier, :name => message.to.name},
  85 + :from => {:id => message.from.identifier, :name => message.from.name},
60 86 :created_at => message.created_at
61 87 }
62 88 end
63 89 render :json => messages_json.reverse
64 90 end
65 91  
  92 + def recent_conversations
  93 + conversations_order = ActiveRecord::Base.connection.execute("select profiles.identifier from profiles inner join (select distinct r.id as id, MAX(r.created_at) as created_at from (select from_id, to_id, created_at, (case when from_id=#{user.id} then to_id else from_id end) as id from chat_messages where from_id=#{user.id} or to_id=#{user.id}) as r group by id order by created_at desc, id) as t on profiles.id=t.id order by t.created_at desc").entries.map {|e| e['identifier']}
  94 + render :json => {:order => conversations_order.reverse, :domain => environment.default_hostname.gsub('.','-')}.to_json
  95 + end
  96 +
  97 + #TODO Ideally this is done through roster table on ejabberd.
  98 + def roster_groups
  99 + render :text => user.memberships.map {|m| {:jid => m.jid, :name => m.name}}.to_json
  100 + end
  101 +
66 102 protected
67 103  
68 104 def check_environment_feature
... ...
app/controllers/public/contact_controller.rb
1 1 class ContactController < PublicController
2 2  
3 3 needs_profile
  4 + before_filter :allow_access_to_page
4 5  
5 6 def new
6 7 @contact = build_contact
... ...
app/controllers/public/events_controller.rb
1 1 class EventsController < PublicController
2 2  
3 3 needs_profile
  4 + before_filter :allow_access_to_page
4 5  
5 6 def events
6 7 @events = []
... ...
app/controllers/public/home_controller.rb
... ... @@ -2,13 +2,13 @@ class HomeController &lt; PublicController
2 2  
3 3 def index
4 4 @has_news = false
5   - if environment.enabled?('use_portal_community') && environment.portal_community
  5 + if environment.portal_enabled
6 6 @has_news = true
7 7 @news_cache_key = environment.portal_news_cache_key(FastGettext.locale)
8 8 if !read_fragment(@news_cache_key)
9 9 portal_community = environment.portal_community
10   - @highlighted_news = portal_community.news(2, true)
11   - @portal_news = portal_community.news(7, true) - @highlighted_news
  10 + @highlighted_news = portal_community.news(environment.highlighted_news_amount, true)
  11 + @portal_news = portal_community.news(environment.portal_news_amount, true).offset(environment.highlighted_news_amount)
12 12 @area_news = environment.portal_folders
13 13 end
14 14 end
... ...
app/controllers/public/profile_controller.rb
... ... @@ -16,13 +16,7 @@ class ProfileController &lt; PublicController
16 16 @activities = @profile.activities.paginate(:per_page => 15, :page => params[:page])
17 17 end
18 18 @tags = profile.article_tags
19   - unless profile.display_info_to?(user)
20   - if profile.visible?
21   - private_profile
22   - else
23   - invisible_profile
24   - end
25   - end
  19 + allow_access_to_page
26 20 end
27 21  
28 22 def tags
... ... @@ -399,17 +393,6 @@ class ProfileController &lt; PublicController
399 393 end
400 394 end
401 395  
402   - def private_profile
403   - private_profile_partial_parameters
404   - render :action => 'index', :status => 403
405   - end
406   -
407   - def invisible_profile
408   - unless profile.is_template?
409   - render_access_denied(_("This profile is inaccessible. You don't have the permission to view the content here."), _("Oops ... you cannot go ahead here"))
410   - end
411   - end
412   -
413 396 def per_page
414 397 Noosfero::Constants::PROFILE_PER_PAGE
415 398 end
... ...
app/controllers/public_controller.rb
1 1 class PublicController < ApplicationController
  2 + protected
  3 +
  4 + def allow_access_to_page
  5 + unless profile.display_info_to?(user)
  6 + if profile.visible?
  7 + private_profile
  8 + else
  9 + invisible_profile
  10 + end
  11 + end
  12 + end
  13 +
  14 + def private_profile
  15 + private_profile_partial_parameters
  16 + render :template => 'shared/access_denied.html.erb', :status => 403
  17 + end
  18 +
  19 + def invisible_profile
  20 + unless profile.is_template?
  21 + render_access_denied(_("This profile is inaccessible. You don't have the permission to view the content here."), _("Oops ... you cannot go ahead here"))
  22 + end
  23 + end
2 24 end
... ...
app/helpers/application_helper.rb
... ... @@ -8,11 +8,7 @@ module ApplicationHelper
8 8  
9 9 include PermissionNameHelper
10 10  
11   - include LightboxHelper
12   -
13   - include ThickboxHelper
14   -
15   - include ColorboxHelper
  11 + include ModalHelper
16 12  
17 13 include BoxesHelper
18 14  
... ... @@ -46,6 +42,8 @@ module ApplicationHelper
46 42  
47 43 include CatalogHelper
48 44  
  45 + include PluginsHelper
  46 +
49 47 def locale
50 48 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale
51 49 end
... ... @@ -649,8 +647,8 @@ module ApplicationHelper
649 647 ' onfocus="if(this.value==\''+s+'\'){this.value=\'\'} this.form.className=\'focus-in\'"'+
650 648 ' onblur="if(/^\s*$/.test(this.value)){this.value=\''+s+'\'} this.form.className=\'focus-out\'">'+
651 649 '</form>'
652   - else #opt == 'lightbox_link' is default
653   - lightbox_link_to '<span class="icon-menu-search"></span>'+ _('Search'), {
  650 + else
  651 + modal_link_to '<span class="icon-menu-search"></span>'+ _('Search'), {
654 652 :controller => 'search',
655 653 :action => 'popup',
656 654 :category_path => (@category ? @category.explode_path : nil)},
... ... @@ -1048,7 +1046,7 @@ module ApplicationHelper
1048 1046 {s_('contents|Most commented') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_comments'})}}
1049 1047 ]
1050 1048 if logged_in?
1051   - links.push(_('New content') => colorbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
  1049 + links.push(_('New content') => modal_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
1052 1050 end
1053 1051  
1054 1052 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') +
... ... @@ -1408,16 +1406,16 @@ module ApplicationHelper
1408 1406 end
1409 1407  
1410 1408 def convert_macro(html, source)
1411   - doc = Hpricot(html)
  1409 + doc = Nokogiri::HTML.fragment html
1412 1410 #TODO This way is more efficient but do not support macro inside of
1413 1411 # macro. You must parse them from the inside-out in order to enable
1414 1412 # that.
1415   - doc.search('.macro').each do |macro|
  1413 + doc.css('.macro').each do |macro|
1416 1414 macro_name = macro['data-macro']
1417 1415 result = @plugins.parse_macro(macro_name, macro, source)
1418 1416 macro.inner_html = result.kind_of?(Proc) ? self.instance_exec(&result) : result
1419 1417 end
1420   - doc.html
  1418 + doc.to_html
1421 1419 end
1422 1420  
1423 1421 def default_folder_for_image_upload(profile)
... ...
app/helpers/article_helper.rb
1 1 module ArticleHelper
2 2  
3   - include PrototypeHelper
4 3 include TokenHelper
5 4  
6 5 def article_reported_version(article)
... ... @@ -35,7 +34,7 @@ module ArticleHelper
35 34 'div',
36 35 check_box(:article, :notify_comments) +
37 36 content_tag('label', _('I want to receive a notification of each comment written by e-mail'), :for => 'article_notify_comments') +
38   - observe_field(:article_accept_comments, :function => "$('article_notify_comments').disabled = ! $('article_accept_comments').checked;$('article_moderate_comments').disabled = ! $('article_accept_comments').checked")
  37 + observe_field(:article_accept_comments, :function => "jQuery('#article_notify_comments')[0].disabled = ! jQuery('#article_accept_comments')[0].checked;jQuery('#article_moderate_comments')[0].disabled = ! jQuery('#article_accept_comments')[0].checked")
39 38 ) +
40 39  
41 40 content_tag(
... ...
app/helpers/boxes_helper.rb
... ... @@ -38,8 +38,12 @@ module BoxesHelper
38 38 end
39 39 end
40 40  
  41 + def boxes_limit holder
  42 + controller.send(:custom_design)[:boxes_limit] || holder.boxes_limit(controller.send(:custom_design)[:layout_template])
  43 + end
  44 +
41 45 def display_boxes(holder, main_content)
42   - boxes = holder.boxes.with_position.first(holder.boxes_limit)
  46 + boxes = holder.boxes.with_position.first(boxes_limit(holder))
43 47 content = boxes.reverse.map { |item| display_box(item, main_content) }.join("\n")
44 48 content = main_content if (content.blank?)
45 49  
... ... @@ -65,11 +69,13 @@ module BoxesHelper
65 69 end
66 70  
67 71 def display_box_content(box, main_content)
68   - context = { :article => @page, :request_path => request.path, :locale => locale, :params => request.params, :user => user }
69   - box_decorator.select_blocks(box.blocks.includes(:box), context).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box)
  72 + context = { :article => @page, :request_path => request.path, :locale => locale, :params => request.params, :user => user, :controller => controller }
  73 + box_decorator.select_blocks(box, box.blocks.includes(:box), context).map do |item|
  74 + display_block item, main_content
  75 + end.join("\n") + box_decorator.block_target(box)
70 76 end
71 77  
72   - def select_blocks(arr, context)
  78 + def select_blocks box, arr, context
73 79 arr
74 80 end
75 81  
... ... @@ -150,8 +156,22 @@ module BoxesHelper
150 156 def self.block_edit_buttons(block)
151 157 ''
152 158 end
153   - def self.select_blocks(arr, context)
154   - arr.select { |block| block.visible?(context) }
  159 + def self.select_blocks box, arr, context
  160 + arr = arr.select{ |block| block.visible? context }
  161 +
  162 + custom_design = context[:controller].send(:custom_design)
  163 + inserts = [custom_design[:insert]].flatten.compact
  164 + inserts.each do |insert_opts|
  165 + next unless box.position == insert_opts[:box]
  166 + position, block = insert_opts[:position], insert_opts[:block]
  167 + block = block.new box: box if block.is_a? Class
  168 +
  169 + if not insert_opts[:uniq] or not box.blocks.map(&:class).include? block.klass
  170 + arr = arr.insert position, block
  171 + end
  172 + end
  173 +
  174 + arr
155 175 end
156 176 end
157 177  
... ... @@ -211,7 +231,7 @@ module BoxesHelper
211 231 end
212 232  
213 233 if block.editable?
214   - buttons << colorbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
  234 + buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
215 235 end
216 236  
217 237 if !block.main?
... ... @@ -221,7 +241,7 @@ module BoxesHelper
221 241 end
222 242  
223 243 if block.respond_to?(:help)
224   - buttons << thickbox_inline_popup_icon(:help, _('Help on this block'), {}, "help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help, :style => 'margin-bottom: 1em;') + thickbox_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}")
  244 + buttons << modal_inline_icon(:help, _('Help on this block'), {}, "#help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help, :style => 'margin-bottom: 1em;') + modal_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}")
225 245 end
226 246  
227 247 if block.embedable?
... ...
app/helpers/chat_helper.rb
... ... @@ -6,8 +6,9 @@ module ChatHelper
6 6 ['icon-menu-busy', _('Busy'), 'chat-busy'],
7 7 ['icon-menu-offline', _('Sign out of chat'), 'chat-disconnect'],
8 8 ]
  9 + avatar = profile_image(user, :portrait, :class => 'avatar')
9 10 content_tag('span',
10   - link_to(content_tag('span', user.name) + ui_icon('ui-icon-triangle-1-s'),
  11 + link_to(avatar + content_tag('span', user.name) + ui_icon('ui-icon-triangle-1-s'),
11 12 '#',
12 13 :onclick => 'toggleMenu(this); return false',
13 14 :class => icon_class + ' simplemenu-trigger'
... ...
app/helpers/colorbox_helper.rb
... ... @@ -1,25 +0,0 @@
1   -module ColorboxHelper
2   -
3   - def colorbox_close_button(text, options = {})
4   - button(:close, text, '#', colorbox_options(options, :close))
5   - end
6   -
7   - def colorbox_button(type, label, url, options = {})
8   - button(type, label, url, colorbox_options(options))
9   - end
10   -
11   - def colorbox_icon_button(type, label, url, options = {})
12   - icon_button(type, label, url, colorbox_options(options))
13   - end
14   -
15   - # options must be an HTML options hash as passed to link_to etc.
16   - #
17   - # returns a new hash with colorbox class added. Keeps existing classes.
18   - def colorbox_options(options, type=nil)
19   - the_class = 'colorbox'
20   - the_class += "-#{type.to_s}" unless type.nil?
21   - the_class << " #{options[:class]}" if options.has_key?(:class)
22   - options.merge(:class => the_class)
23   - end
24   -
25   -end
app/helpers/comment_helper.rb
... ... @@ -65,7 +65,7 @@ module CommentHelper
65 65  
66 66 def link_for_edit(comment)
67 67 if comment.can_be_updated_by?(user)
68   - {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'colorbox')}
  68 + {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'modal')}
69 69 end
70 70 end
71 71  
... ...
app/helpers/dates_helper.rb
... ... @@ -2,24 +2,14 @@ require &#39;noosfero/i18n&#39;
2 2  
3 3 module DatesHelper
4 4  
5   - # FIXME Date#strftime should translate this for us !!!!
6   - MONTHS = [
7   - N_('January'),
8   - N_('February'),
9   - N_('March'),
10   - N_('April'),
11   - N_('May'),
12   - N_('June'),
13   - N_('July'),
14   - N_('August'),
15   - N_('September'),
16   - N_('October'),
17   - N_('November'),
18   - N_('December')
19   - ]
20   -
21   - def month_name(n)
22   - _(MONTHS[n-1])
  5 + MONTHS = I18n.t('date.month_names')
  6 +
  7 + def month_name(n, abbreviated = false)
  8 + if abbreviated
  9 + I18n.t('date.abbr_month_names')[n]
  10 + else
  11 + MONTHS[n]
  12 + end
23 13 end
24 14  
25 15 # formats a date for displaying.
... ... @@ -91,15 +81,7 @@ module DatesHelper
91 81 _(date.strftime("%a"))
92 82 else
93 83 # FIXME Date#strftime should translate this for us !!!!
94   - _([
95   - N_('Sunday'),
96   - N_('Monday'),
97   - N_('Tuesday'),
98   - N_('Wednesday'),
99   - N_('Thursday'),
100   - N_('Friday'),
101   - N_('Saturday'),
102   - ][date.wday])
  84 + I18n.t('date.day_names')[date.wday]
103 85 end
104 86 end
105 87  
... ... @@ -111,7 +93,7 @@ module DatesHelper
111 93 date = date << 1
112 94 end
113 95 if opts[:only_month]
114   - _('%{month}') % {:month => month_name(date.month.to_i) }
  96 + _('%{month}') % { :month => month_name(date.month.to_i) }
115 97 else
116 98 _('%{month} %{year}') % { :year => date.year, :month => month_name(date.month.to_i) }
117 99 end
... ... @@ -156,7 +138,7 @@ module DatesHelper
156 138 else
157 139 order = [:day, :month, :year]
158 140 end
159   - date_select(object, method, html_options.merge(options.merge(:include_blank => true, :order => order, :use_month_names => MONTHS.map {|item| gettext(item)})))
  141 + date_select(object, method, html_options.merge(options.merge(:include_blank => true, :order => order, :use_month_names => MONTHS)))
160 142 end
161 143  
162 144 end
... ...
app/helpers/design_helper.rb 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +module DesignHelper
  2 +
  3 + extend ActiveSupport::Concern
  4 +
  5 + included do
  6 + extend ClassMethods
  7 + include InstanceMethods
  8 + before_filter :load_custom_design if self.respond_to? :before_filter
  9 + end
  10 +
  11 + module ClassMethods
  12 +
  13 + def no_design_blocks
  14 + @no_design_blocks = true
  15 + end
  16 +
  17 + def use_custom_design options = {}
  18 + @custom_design = options
  19 + end
  20 +
  21 + def custom_design
  22 + @custom_design ||= {}
  23 + end
  24 +
  25 + def uses_design_blocks?
  26 + !@no_design_blocks
  27 + end
  28 +
  29 + end
  30 +
  31 + module InstanceMethods
  32 +
  33 + protected
  34 +
  35 + def uses_design_blocks?
  36 + !@no_design_blocks && self.class.uses_design_blocks?
  37 + end
  38 +
  39 + def load_custom_design
  40 + # see also: LayoutHelper#body_classes
  41 + @layout_template = self.class.custom_design[:layout_template]
  42 + end
  43 +
  44 + def custom_design
  45 + @custom_design || self.class.custom_design
  46 + end
  47 +
  48 + end
  49 +
  50 +end
... ...
app/helpers/lightbox_helper.rb
... ... @@ -1,36 +0,0 @@
1   -module LightboxHelper
2   -
3   - def lightbox_link_to(text, url, options = {})
4   - link_to(text, url, lightbox_options(options))
5   - end
6   -
7   - def lightbox_close_button(text, options = {})
8   - button(:close, text, '#', lightbox_options(options, 'lbAction').merge(:rel => 'deactivate'))
9   - end
10   -
11   - def lightbox_button(type, label, url, options = {})
12   - button(type, label, url, lightbox_options(options))
13   - end
14   -
15   - def lightbox_icon_button(type, label, url, options = {})
16   - icon_button(type, label, url, lightbox_options(options))
17   - end
18   -
19   - # options must be an HTML options hash as passed to link_to etc.
20   - #
21   - # returns a new hash with lightbox class added. Keeps existing classes.
22   - def lightbox_options(options, lightbox_type = 'lbOn')
23   - the_class = lightbox_type
24   - the_class << " #{options[:class]}" if options.has_key?(:class)
25   - options.merge(:class => the_class)
26   - end
27   -
28   - def lightbox?
29   - request.xhr?
30   - end
31   -
32   - def lightbox_remote_button(type, label, url, options = {})
33   - button(type, label, url, lightbox_options(options, 'remote-lbOn'))
34   - end
35   -
36   -end
app/helpers/manage_products_helper.rb
... ... @@ -137,7 +137,7 @@ module ManageProductsHelper
137 137 ui_button_to_remote(label,
138 138 {:update => "product-#{field}",
139 139 :url => { :controller => 'manage_products', :action => "edit", :id => product.id, :field => field },
140   - :complete => "$('edit-product-button-ui-#{field}').hide()",
  140 + :complete => "jQuery('#edit-product-button-ui-#{field}').hide()",
141 141 :method => :get,
142 142 :loading => "loading_for_button('##{id}')"},
143 143 options)
... ...
app/helpers/modal_helper.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +module ModalHelper
  2 +
  3 + def modal_inline_link_to title, url, selector, options = {}
  4 + link_to title, url, modal_options(options.merge(:inline => selector))
  5 + end
  6 +
  7 + def modal_inline_icon type, title, url, selector, options = {}
  8 + icon_button type, title, url, modal_options(options.merge(:inline => selector))
  9 + end
  10 +
  11 + def modal_link_to title, url, options = {}
  12 + link_to title, url, modal_options(options)
  13 + end
  14 +
  15 + def modal_close_link text, options = {}
  16 + link_to text, '#', modal_options(options, :close)
  17 + end
  18 +
  19 + def modal_close_button(text, options = {})
  20 + button :close, text, '#', modal_options(options, :close).merge(:rel => 'deactivate')
  21 + end
  22 +
  23 + def modal_button(type, label, url, options = {})
  24 + button type, label, url, modal_options(options)
  25 + end
  26 +
  27 + def modal_icon_button(type, label, url, options = {})
  28 + icon_button type, label, url, modal_options(options)
  29 + end
  30 +
  31 + # options must be an HTML options hash as passed to link_to etc.
  32 + #
  33 + # returns a new hash with modal class added. Keeps existing classes.
  34 + def modal_options(options, type=nil)
  35 + inline_selector = options.delete :inline
  36 + options[:onclick] = "return noosfero.modal.inline('#{inline_selector}')" if inline_selector
  37 +
  38 + classes = if inline_selector then '' else 'modal-toggle' end
  39 + classes += " modal-#{type.to_s}" if type.present?
  40 + classes << " #{options[:class]}" if options.has_key? :class
  41 + options.merge!(:class => classes)
  42 +
  43 + options
  44 + end
  45 +
  46 +end
... ...
app/helpers/plugins_helper.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +module PluginsHelper
  2 +
  3 + def plugins_product_tabs
  4 + @plugins.dispatch(:product_tabs, @product).map do |tab|
  5 + {:title => tab[:title], :id => tab[:id], :content => instance_eval(&tab[:content])}
  6 + end
  7 + end
  8 +
  9 +end
... ...
app/helpers/thickbox_helper.rb
... ... @@ -1,11 +0,0 @@
1   -module ThickboxHelper
2   - def thickbox_inline_popup_link(title, url, id, options = {})
3   - link_to(title, url_for(url) + "#TB_inline?height=300&width=500&inlineId=#{id}&modal=true", {:class => 'thickbox'}.merge(options))
4   - end
5   - def thickbox_inline_popup_icon(type, title, url, id, options = {})
6   - icon_button(type, title, url_for(url) + "#TB_inline?height=300&width=500&inlineId=#{id}&modal=true", {:class => "thickbox"}.merge(options))
7   - end
8   - def thickbox_close_button(title)
9   - button_to_function(:close, title, 'tb_remove();')
10   - end
11   -end
app/models/article.rb
1   -require 'hpricot'
2 1  
3 2 class Article < ActiveRecord::Base
4 3  
... ... @@ -400,6 +399,10 @@ class Article &lt; ActiveRecord::Base
400 399 {}
401 400 end
402 401  
  402 + def alternate_languages
  403 + self.translations.map(&:language)
  404 + end
  405 +
403 406 scope :native_translations, :conditions => { :translation_of_id => nil }
404 407  
405 408 def translatable?
... ... @@ -713,7 +716,7 @@ class Article &lt; ActiveRecord::Base
713 716 end
714 717  
715 718 def first_paragraph
716   - paragraphs = Hpricot(to_html).search('p')
  719 + paragraphs = Nokogiri::HTML.fragment(to_html).css('p')
717 720 paragraphs.empty? ? '' : paragraphs.first.to_html
718 721 end
719 722  
... ... @@ -735,8 +738,8 @@ class Article &lt; ActiveRecord::Base
735 738  
736 739 def body_images_paths
737 740 require 'uri'
738   - Hpricot(self.body.to_s).search('img[@src]').collect do |i|
739   - (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i.attributes['src'])).to_s : i.attributes['src']
  741 + Nokogiri::HTML.fragment(self.body.to_s).css('img[src]').collect do |i|
  742 + (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i['src'])).to_s : i['src']
740 743 end
741 744 end
742 745  
... ... @@ -773,11 +776,11 @@ class Article &lt; ActiveRecord::Base
773 776 end
774 777  
775 778 def first_image
776   - img = Hpricot(self.lead.to_s).search('img[@src]').first || Hpricot(self.body.to_s).search('img').first
777   - img.nil? ? '' : img.attributes['src']
  779 + img = Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first || Nokogiri::HTML.fragment(self.body.to_s).search('img').first
  780 + img.nil? ? '' : img['src']
778 781 end
779 782  
780   - delegate :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true
  783 + delegate :lat, :lng, :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true
781 784  
782 785 def has_macro?
783 786 true
... ...
app/models/blog_archives_block.rb
... ... @@ -36,8 +36,7 @@ class BlogArchivesBlock &lt; Block
36 36 results << content_tag('li', content_tag('strong', "#{year} (#{count})"))
37 37 results << "<ul class='#{year}-archive'>"
38 38 posts.except(:order).count(:all, :conditions => ['EXTRACT(YEAR FROM published_at)=?', year], :group => 'EXTRACT(MONTH FROM published_at)').sort_by {|month, count| -month.to_i}.each do |month, count|
39   - month_name = gettext(MONTHS[month.to_i - 1])
40   - results << content_tag('li', link_to("#{month_name} (#{count})", owner_blog.url.merge(:year => year, :month => month)))
  39 + results << content_tag('li', link_to("#{month_name(month.to_i)} (#{count})", owner_blog.url.merge(:year => year, :month => month)))
41 40 end
42 41 results << "</ul>"
43 42 end
... ...
app/models/box.rb
... ... @@ -14,8 +14,8 @@ class Box &lt; ActiveRecord::Base
14 14 end
15 15  
16 16 def acceptable_blocks
17   - blocks_classes = central? ? Box.acceptable_center_blocks + plugins.dispatch(:extra_blocks, :type => owner.class, :position => 1) : Box.acceptable_side_blocks + plugins.dispatch(:extra_blocks, :type => owner.class, :position => [2, 3])
18   - to_css_class_name(blocks_classes)
  17 + blocks_classes = if central? then Box.acceptable_center_blocks + plugins.dispatch(:extra_blocks, :type => owner.class, :position => 1) else Box.acceptable_side_blocks + plugins.dispatch(:extra_blocks, :type => owner.class, :position => [2, 3]) end
  18 + to_css_selector blocks_classes
19 19 end
20 20  
21 21 def central?
... ... @@ -74,8 +74,8 @@ class Box &lt; ActiveRecord::Base
74 74  
75 75 private
76 76  
77   - def to_css_class_name(blocks_classes)
78   - blocks_classes.map{ |block_class| block_class.name.to_css_class }
  77 + def to_css_selector(blocks_classes)
  78 + blocks_classes.map{ |block_class| ".#{block_class.name.to_css_class}" }.join(',')
79 79 end
80 80  
81 81 end
... ...
app/models/enterprise.rb
... ... @@ -19,7 +19,8 @@ class Enterprise &lt; Organization
19 19 has_many :inputs, :through => :products
20 20 has_many :production_costs, :as => :owner
21 21  
22   - has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people'
  22 + has_many :favorite_enterprise_people
  23 + has_many :fans, through: :favorite_enterprise_people, source: :person
23 24  
24 25 def product_categories
25 26 ProductCategory.by_enterprise(self)
... ...
app/models/environment.rb
... ... @@ -3,7 +3,7 @@
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, :disabled_blocks, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound, :noreply_email, :signup_welcome_screen_body, :members_whitelist_enabled, :members_whitelist
  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
7 7  
8 8 has_many :users
9 9  
... ... @@ -268,9 +268,12 @@ class Environment &lt; ActiveRecord::Base
268 268 settings_items :description, :type => String, :default => '<div style="text-align: center"><a href="http://noosfero.org/"><img src="/images/noosfero-network.png" alt="Noosfero"/></a></div>'
269 269 settings_items :local_docs, :type => Array, :default => []
270 270 settings_items :news_amount_by_folder, :type => Integer, :default => 4
  271 + settings_items :highlighted_news_amount, :type => Integer, :default => 2
  272 + settings_items :portal_news_amount, :type => Integer, :default => 5
271 273 settings_items :help_message_to_add_enterprise, :type => String, :default => ''
272 274 settings_items :tip_message_enterprise_activation_question, :type => String, :default => ''
273 275  
  276 + settings_items :currency_iso_unit, :type => String, :default => 'USD'
274 277 settings_items :currency_unit, :type => String, :default => '$'
275 278 settings_items :currency_separator, :type => String, :default => '.'
276 279 settings_items :currency_delimiter, :type => String, :default => ','
... ... @@ -292,8 +295,6 @@ class Environment &lt; ActiveRecord::Base
292 295  
293 296 settings_items :enabled_plugins, :type => Array, :default => Noosfero::Plugin.available_plugin_names
294 297  
295   - settings_items :disabled_blocks, :type => Array, :default => []
296   -
297 298 settings_items :search_hints, :type => Hash, :default => {}
298 299  
299 300 # Set to return http forbidden to host not on the allow origin list bellow
... ... @@ -359,10 +360,6 @@ class Environment &lt; ActiveRecord::Base
359 360 enabled_plugins.include?(plugin.to_s)
360 361 end
361 362  
362   - def block_disabled?(block)
363   - disabled_blocks.include?(block.to_s)
364   - end
365   -
366 363 # enables the features identified by <tt>features</tt>, which is expected to
367 364 # be an Enumarable object containing the identifiers of the desired features.
368 365 # Passing <tt>nil</tt> is the same as passing an empty Array.
... ...
app/models/event.rb
... ... @@ -141,6 +141,10 @@ class Event &lt; Article
141 141 result
142 142 end
143 143  
  144 + def duration
  145 + ((self.end_date || self.start_date) - self.start_date).to_i
  146 + end
  147 +
144 148 def lead
145 149 content_tag('div',
146 150 show_period(start_date, end_date),
... ...
app/models/external_feed.rb
... ... @@ -14,9 +14,9 @@ class ExternalFeed &lt; ActiveRecord::Base
14 14  
15 15 def add_item(title, link, date, content)
16 16 return if content.blank?
17   - doc = Hpricot(content)
18   - doc.search('*').each do |p|
19   - if p.instance_of? Hpricot::Elem
  17 + doc = Nokogiri::HTML.fragment content
  18 + doc.css('*').each do |p|
  19 + if p.instance_of? Nokogiri::XML::Element
20 20 p.remove_attribute 'style'
21 21 p.remove_attribute 'class'
22 22 end
... ... @@ -26,10 +26,10 @@ class ExternalFeed &lt; ActiveRecord::Base
26 26 article = TinyMceArticle.new
27 27 article.name = title
28 28 article.profile = blog.profile
29   - article.body = content
30   - article.published_at = date
31   - article.source = link
32   - article.profile = blog.profile
  29 + article.body = content
  30 + article.published_at = date
  31 + article.source = link
  32 + article.profile = blog.profile
33 33 article.parent = blog
34 34 article.author_name = self.feed_title
35 35 unless blog.children.exists?(:slug => article.slug)
... ...
app/models/favorite_enterprise_person.rb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +class FavoriteEnterprisePerson < ActiveRecord::Base
  2 +
  3 + self.table_name = :favorite_enteprises_people
  4 +
  5 + belongs_to :enterprise
  6 + belongs_to :person
  7 +
  8 +end
... ...
app/models/forum.rb
... ... @@ -54,7 +54,7 @@ class Forum &lt; Folder
54 54  
55 55 def first_paragraph
56 56 return '' if body.blank?
57   - paragraphs = Hpricot(body).search('p')
  57 + paragraphs = Nokogiri::HTML.fragment(body).css('p')
58 58 paragraphs.empty? ? '' : paragraphs.first.to_html
59 59 end
60 60  
... ...
app/models/input.rb
1 1 class Input < ActiveRecord::Base
2 2  
3   - attr_accessible :product, :product_category, :product_category_id, :amount_used, :unit_id, :price_per_unit, :relevant_to_price
  3 + attr_accessible :product, :product_id, :product_category, :product_category_id,
  4 + :amount_used, :unit_id, :price_per_unit, :relevant_to_price, :is_from_solidarity_economy
4 5  
5 6 belongs_to :product
6 7 belongs_to :product_category
... ...
app/models/product.rb
... ... @@ -10,7 +10,8 @@ class Product &lt; ActiveRecord::Base
10 10 :display => %w[full map]
11 11 }
12 12  
13   - attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list
  13 + attr_accessible :name, :product_category, :profile, :profile_id, :enterprise,
  14 + :highlighted, :price, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list
14 15  
15 16 def self.default_search_display
16 17 'full'
... ... @@ -236,7 +237,7 @@ class Product &lt; ActiveRecord::Base
236 237  
237 238 def percentage_from_solidarity_economy
238 239 se_i = t_i = 0
239   - self.inputs(true).each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy }
  240 + self.inputs.each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy }
240 241 t_i = 1 if t_i == 0 # avoid division by 0
241 242 p = case (se_i.to_f/t_i)*100
242 243 when 0 then [0, '']
... ...
app/models/text_article.rb
1 1 require 'noosfero/translatable_content'
2 2  
3   -# a base class for all text article types.
  3 +# a base class for all text article types.
4 4 class TextArticle < Article
5 5  
6 6 xss_terminate :only => [ :name ], :on => 'validation'
... ... @@ -26,10 +26,10 @@ class TextArticle &lt; Article
26 26 before_save :set_relative_path
27 27  
28 28 def set_relative_path
29   - parsed = Hpricot(self.body.to_s)
30   - parsed.search('img[@src]').map { |i| change_element_path(i, 'src') }
31   - parsed.search('a[@href]').map { |i| change_element_path(i, 'href') }
32   - self.body = parsed.to_s
  29 + parsed = Nokogiri::HTML.fragment(self.body.to_s)
  30 + parsed.css('img[src]').each { |i| change_element_path(i, 'src') }
  31 + parsed.css('a[href]').each { |i| change_element_path(i, 'href') }
  32 + self.body = parsed.to_html
33 33 end
34 34  
35 35 def change_element_path(el, attribute)
... ...
app/models/user.rb
1 1 require 'digest/sha1'
2 2 require 'user_activation_job'
3   -require 'securerandom'
4 3  
5 4 # User models the system users, and is generated by the acts_as_authenticated
6 5 # Rails generator.
... ... @@ -55,7 +54,7 @@ class User &lt; ActiveRecord::Base
55 54  
56 55 user.person = p
57 56 end
58   - if user.environment.enabled?('skip_new_user_email_confirmation')
  57 + if user.environment.enabled?('skip_new_user_email_confirmation')
59 58 if user.environment.enabled?('admin_must_approve_new_users')
60 59 create_moderate_task
61 60 else
... ... @@ -103,6 +102,7 @@ class User &lt; ActiveRecord::Base
103 102 validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?})
104 103 validates_uniqueness_of :login, :email, :case_sensitive => false, :scope => :environment_id
105 104 before_save :encrypt_password
  105 + before_save :normalize_email, if: proc{ |u| u.email.present? }
106 106 validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?})
107 107  
108 108 validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('{fn} must be checked in order to signup.').fix_i18n
... ... @@ -115,6 +115,10 @@ class User &lt; ActiveRecord::Base
115 115 u && u.authenticated?(password) ? u : nil
116 116 end
117 117  
  118 + def register_login
  119 + self.update_attribute :last_login_at, Time.now
  120 + end
  121 +
118 122 #FIXME make this test
119 123 def generate_private_token!
120 124 self.private_token = SecureRandom.hex
... ... @@ -345,6 +349,11 @@ class User &lt; ActiveRecord::Base
345 349 end
346 350  
347 351 protected
  352 +
  353 + def normalize_email
  354 + self.email = self.email.squish.downcase
  355 + end
  356 +
348 357 # before filter
349 358 def encrypt_password
350 359 return if password.blank?
... ...
app/views/account/_login_form.html.erb
1 1 <%= labelled_form_for :user,
2 2 :url => { :controller => 'account', :action => (params[:enterprise_code] ? 'activate_enterprise' : 'login') } do |f| %>
3 3  
4   -<%= f.text_field :login,
5   - :id => ( lightbox? ? 'lightbox_' : '' ) + 'user_login',
6   - :onchange => 'this.value = convToValidLogin( this.value )' %>
  4 +<%= f.text_field :login, :id => 'user_login', :onchange => 'this.value = convToValidLogin( this.value )' %>
7 5  
8   -<%= f.password_field :password,
9   - :id => ( lightbox? ? 'lightbox_' : '' ) + 'user_password' %>
  6 +<%= f.password_field :password, :id => 'user_password' %>
10 7  
11 8 <% if params[:enterprise_code] %>
12 9 <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %>
... ... @@ -16,7 +13,7 @@
16 13  
17 14 <% button_bar do %>
18 15 <%= submit_button( 'login', _('Log in') )%>
19   - <%= lightbox_close_button(_('Cancel')) if lightbox? %>
  16 + <%= modal_close_button _('Cancel') if request.xhr? %>
20 17 <% end %>
21 18  
22 19 <% end %>
... ...
app/views/account/activate_enterprise.html.erb
... ... @@ -7,8 +7,8 @@
7 7 <p><%= _('Do you have a personal user account in the system?') %></p>
8 8  
9 9 <div id="enterprise-activation-create-user-or-login-button">
10   - <%= button_to_function 'login', _('Yes'), "$('enterprise-activation-create-user-form').hide(); $('enterprise-activation-login-form').show()" %>
11   - <%= button_to_function 'add', _('No'), "$('enterprise-activation-login-form').hide(); $('enterprise-activation-create-user-form').show()" %>
  10 + <%= button_to_function 'login', _('Yes'), "jQuery('#enterprise-activation-create-user-form').hide(); jQuery('#enterprise-activation-login-form').show()" %>
  11 + <%= button_to_function 'add', _('No'), "jQuery('#enterprise-activation-login-form').hide(); jQuery('#enterprise-activation-create-user-form').show()" %>
12 12 </div>
13 13  
14 14 <div id="enterprise-activation-create-user-form" style="display: none">
... ...
app/views/account/index_anonymous.html.erb
1 1 <h1><%= _('Identify yourself') %></h1>
2 2  
3 3 <p>
4   -<%= lightbox_link_to _('Login.'), { :controller => 'account', :action => 'login_popup' } %>
  4 +<%= modal_link_to _('Login.'), { :controller => 'account', :action => 'login_popup' } %>
5 5  
6 6 <%= _('You need to login to be able to use all the features in this environment.') %>
7 7 </p>
... ...
app/views/account/login.html.erb
... ... @@ -3,7 +3,7 @@
3 3 <h2><%= _('Login') %></h2>
4 4  
5 5 <% @user ||= User.new %>
6   -<% is_thickbox ||= false %>
  6 +<% is_popin ||= false %>
7 7  
8 8 <%= @message %>
9 9  
... ... @@ -17,8 +17,8 @@
17 17  
18 18 <% button_bar do %>
19 19 <%= submit_button( 'login', _('Log in') )%>
20   - <% if is_thickbox %>
21   - <%= thickbox_close_button(_('Cancel')) %>
  20 + <% if is_popin %>
  21 + <%= modal_close_button(_('Cancel')) %>
22 22 <% end %>
23 23 <% end %>
24 24  
... ...
app/views/account/logout_popup.html.erb
... ... @@ -2,6 +2,6 @@
2 2 <p>
3 3 <% button_bar do %>
4 4 <%= button :ok, _('Yes'), { :controller => 'account', :action => 'logout' } %>
5   - <%= lightbox_close_button _('No, I want to stay.') %>
  5 + <%= modal_close_button _('No, I want to stay.') %>
6 6 <% end %>
7 7 </p>
... ...
app/views/admin_panel/set_portal_community.html.erb
... ... @@ -18,7 +18,7 @@
18 18 <%= button 'ok', _('Enable'), {:action => 'manage_portal_community', :activate => 1} %>
19 19 <% end %>
20 20 <%= button 'folder', _('Select Portal Folders'), {:action => 'set_portal_folders'} %>
21   - <%= button 'edit', _('Define Amount by Folder'), {:action => 'set_portal_news_amount'} %>
  21 + <%= button 'edit', _('Define news amount on portal'), {:action => 'set_portal_news_amount'} %>
22 22 <%= button 'delete', _('Remove'), { :action => 'unset_portal_community'} %>
23 23 <% end %>
24 24 <% end %>
... ...
app/views/admin_panel/set_portal_news_amount.html.erb
1   -<h1><%= _('News amount by folder') %></h1>
  1 +<h1><%= _('News amount on portal') %></h1>
2 2  
3 3 <%= labelled_form_for :environment do |f| %>
4 4  
5   - <%= labelled_form_field _('Number of news'), select(:environment, :news_amount_by_folder, (1..10).to_a) %>
  5 + <%= labelled_form_field _('Number of highlighted news'), select(:environment, :highlighted_news_amount, (0..10).to_a) %>
  6 + <%= labelled_form_field _('Number of portal news'), select(:environment, :portal_news_amount, (0..10).to_a) %>
  7 + <%= labelled_form_field _('Number of news by folder'), select(:environment, :news_amount_by_folder, (1..10).to_a) %>
6 8  
7 9 <% button_bar do %>
8 10 <%= submit_button(:save, _('Save')) %>
... ...
app/views/box_organizer/edit.html.erb
... ... @@ -27,7 +27,7 @@
27 27  
28 28 <% button_bar do %>
29 29 <%= submit_button(:save, _('Save')) %>
30   - <%= colorbox_close_button(_('Cancel')) %>
  30 + <%= modal_close_button(_('Cancel')) %>
31 31 <% end %>
32 32  
33 33 <% end %>
... ...
app/views/box_organizer/move_block.rjs
... ... @@ -6,3 +6,4 @@ page.replace_html(to, display_updated_box(@target_box))
6 6  
7 7 page.visual_effect(:highlight, from)
8 8 page.visual_effect(:highlight, to) unless (from == to)
  9 +
... ...
app/views/cms/_blog.html.erb
... ... @@ -10,7 +10,8 @@
10 10  
11 11 <script type="text/javascript">
12 12 function submit_button(index) {
13   - return $("article_slug").form.select("input.submit")[index];
  13 + var form = $($("#article_slug")[0].form)
  14 + return form.find("input[type=submit]")[index];
14 15 }
15 16 function warn_value_change() {
16 17 show_warning('article-formitem', "slug-change-confirmation");
... ... @@ -23,7 +24,7 @@
23 24 hide_warning('slug-change-confirmation');
24 25 }
25 26 function no_change() {
26   - $("article_slug").value = $("old_article_slug").value;
  27 + jQuery("#article_slug").val(jQuery("#old_article_slug").val());
27 28 enable_button(submit_button(0));
28 29 enable_button(submit_button(1));
29 30 hide_warning('slug-change-confirmation');
... ... @@ -78,7 +79,7 @@
78 79 <div id='fetch-external-feed'>
79 80 <% enabled = @article.external_feed && @article.external_feed.enabled %>
80 81 <% only_once = @article.external_feed ? @article.external_feed.only_once : true %>
81   - <%= labelled_check_box(_('Fetch posts from an external feed'), 'article[external_feed_builder][enabled]', 'true', enabled, {:onchange => "$('external-feed-options').toggle()"}) %>
  82 + <%= labelled_check_box(_('Fetch posts from an external feed'), 'article[external_feed_builder][enabled]', 'true', enabled, {:onchange => "jQuery('#external-feed-options').toggle()"}) %>
82 83 <div id='external-feed-options' style="display: <%= enabled ? 'block' : 'none' %>">
83 84 <%= efeed.hidden_field(:id) %>
84 85 <%= labelled_form_field( _('Feed address'), efeed.text_field(:address) ) %>
... ...
app/views/cms/_upload_file.html.erb
1 1 <p><%= file_field_tag('uploaded_files[]', :size => size) %></p>
2   -<%= javascript_tag("$('uploaded_files').scrollTop = $('uploaded_files').scrollHeight") %>
  2 +<%= javascript_tag("jQuery('#uploaded_files')[0].scrollTop = jQuery('#uploaded_files')[0].scrollHeight") %>
... ...
app/views/cms/edit.html.erb
... ... @@ -28,7 +28,7 @@
28 28 <% end %>
29 29  
30 30 <div style='float: right'>
31   - <%= lightbox_button :help, _('Why categorize?'), :action => 'why_categorize' %>
  31 + <%= modal_button :help, _('Why categorize?'), :action => 'why_categorize' %>
32 32 </div>
33 33  
34 34 <%= select_categories(:article, _('Categorize your article')) %>
... ...
app/views/cms/select_article_type.html.erb
... ... @@ -15,6 +15,6 @@
15 15 </ul>
16 16 <br style="clear:both" />
17 17  
18   -<%= colorbox_close_button(_('Cancel')) %>
  18 +<%= modal_close_button(_('Cancel')) %>
19 19  
20 20 </div>
... ...
app/views/cms/view.html.erb
... ... @@ -17,7 +17,7 @@
17 17 <% button_bar(:style => 'margin-bottom: 1em;') do %>
18 18 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
19 19  
20   - <%= colorbox_button('new', _('New content'), :action => 'new', :parent_id => parent_id, :cms => true) %>
  20 + <%= modal_button('new', _('New content'), :action => 'new', :parent_id => parent_id, :cms => true) %>
21 21 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor', :action => "index") %>
22 22 <% end %>
23 23  
... ...
app/views/cms/why_categorize.html.erb
... ... @@ -5,5 +5,5 @@
5 5 </p>
6 6  
7 7 <% button_bar do %>
8   - <%= lightbox_close_button _('Close') %>
  8 + <%= modal_close_button _('Close') %>
9 9 <% end %>
... ...
app/views/comment/_comment_form.html.erb
... ... @@ -10,7 +10,7 @@
10 10 <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %>
11 11 <% button_bar do %>
12 12 <%= button_to_function :add, _('Confirm'), "return false", :id => "confirm-captcha" %>
13   - <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close()" %>
  13 + <%= button_to_function :cancel, _('Cancel'), "noosfero.modal.close()" %>
14 14 <% end %>
15 15 </div>
16 16  
... ... @@ -31,10 +31,10 @@ function check_captcha(button, confirm_action) {
31 31 return true;
32 32 <% else %>
33 33 jQuery('#recaptcha-container').show();
34   - jQuery.colorbox({ html: jQuery('#recaptcha-container').html(), maxWidth : '600px', maxHeight : '300px' });
  34 + noosfero.modal.inline('#recaptcha-container', {maxWidth :'600px', maxHeight : '300px' });
35 35 jQuery('#confirm-captcha').unbind('click');
36 36 jQuery('#confirm-captcha').bind('click', function() {
37   - jQuery.colorbox.close();
  37 + noosfero.modal.close();
38 38 button.form.recaptcha_response_field.value = jQuery('#recaptcha_response_field').val();
39 39 button.form.recaptcha_challenge_field.value = jQuery('#recaptcha_challenge_field').val();
40 40 button.form.confirm.value = 'true';
... ... @@ -88,7 +88,7 @@ function check_captcha(button, confirm_action) {
88 88 <% if !edition_mode %>
89 89 <%= button :cancel, _('Cancel'), '', :id => 'cancel-comment' %>
90 90 <% else %>
91   - <%= button :cancel, _('Cancel'), '#', :onclick => "jQuery.colorbox.close();" %>
  91 + <%= button :cancel, _('Cancel'), '#', :onclick => "noosfero.modal.close();" %>
92 92 <% end %>
93 93 <% end %>
94 94 <% end %>
... ...
app/views/content_viewer/_article_toolbar.html.erb
... ... @@ -29,14 +29,14 @@
29 29 <%= expirable_button @page, :locale, content, url %>
30 30 <% end %>
31 31  
32   - <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) unless remove_content_button(:new, @page) %>
  32 + <%= modal_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) unless remove_content_button(:new, @page) %>
33 33 <% end %>
34 34  
35 35 <% if @page.accept_uploads? && @page.allow_create?(user) %>
36 36 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) unless remove_content_button(:upload, @page)%>
37 37 <% end %>
38 38  
39   - <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest, @page) %>
  39 + <% if !@page.allow_create?(user) && profile.organization? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest, @page) %>
40 40 <% content = content_tag( 'span', _('Suggest an article') ) %>
41 41 <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}) %>
42 42 <% options = {:id => 'suggest-article-link'} %>
... ...
app/views/content_viewer/_comment_form.html.erb
... ... @@ -7,10 +7,10 @@ function submit_comment_form(button) {
7 7 return true;
8 8 <% else %>
9 9 jQuery('#recaptcha-container').show();
10   - jQuery.colorbox({ inline : true, href : '#recaptcha-container', maxWidth : '600px', maxHeight : '300px' });
  10 + noosfero.modal.inline('#recaptcha-container', {maxWidth :'600px', maxHeight : '300px' });
11 11 jQuery('#confirm-captcha').unbind('click');
12 12 jQuery('#confirm-captcha').bind('click', function() {
13   - jQuery.colorbox.close();
  13 + noosfero.modal.close();
14 14 button.form.recaptcha_response_field.value = jQuery('#recaptcha_response_field').val();
15 15 button.form.recaptcha_challenge_field.value = jQuery('#recaptcha_challenge_field').val();
16 16 button.form.confirm.value = 'true';
... ... @@ -38,7 +38,7 @@ function submit_comment_form(button) {
38 38 <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %>
39 39 <% button_bar do %>
40 40 <%= button_to_function :add, _('Confirm'), "return false", :id => "confirm-captcha" %>
41   - <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close()" %>
  41 + <%= button_to_function :cancel, _('Cancel'), "noosfero.modal.close()" %>
42 42 <% end %>
43 43 </div>
44 44  
... ...
app/views/events/_month.html.erb
... ... @@ -13,8 +13,8 @@
13 13 date.day,
14 14 :url => {:action => 'events_by_day', :year => date.year, :month => date.month, :day => date.day, :category_id => @category_id},
15 15 :update => 'events-of-the-day',
16   - :loading => "$('events-of-the-day').addClassName('loading')",
17   - :complete => "$('events-of-the-day').removeClassName('loading')"
  16 + :loading => "jQuery('#events-of-the-day').addClass('loading')",
  17 + :complete => "jQuery('#events-of-the-day').removeClass('loading')"
18 18 ) :
19 19 date.day
20 20 %>
... ...
app/views/invite/_select_address_book.html.erb
... ... @@ -12,16 +12,16 @@
12 12  
13 13 <script type="text/javascript">
14 14 function hide_invite_friend_login_password() {
15   - $('invite-friends-login-password').hide();
  15 + jQuery('#invite-friends-login-password').hide();
16 16 }
17 17 function show_invite_friend_login_password(option) {
18 18 if (option == 'hotmail') {
19   - $('hotmail_username_tip').show();
  19 + jQuery('#hotmail_username_tip').show();
20 20 } else {
21   - $('hotmail_username_tip').hide();
  21 + jQuery('#hotmail_username_tip').hide();
22 22 }
23   - $('invite-friends-login-password').show();
24   - $('login').focus();
  23 + jQuery('#invite-friends-login-password').show();
  24 + jQuery('#login').focus();
25 25 }
26 26 </script>
27 27 <div id='invite-friends-login-password' <%= "style='display: none;'" if (@import_from == 'manual') %>>
... ...
app/views/invite/select_friends.html.erb
... ... @@ -24,8 +24,8 @@
24 24 </div>
25 25 <% if @import_from != 'manual' %>
26 26 <div>
27   - <%= link_to_function _('Check all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = true; });" %>
28   - <%= link_to_function _('Uncheck all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = false; });" %>
  27 + <%= link_to_function _('Check all'), "jQuery('input.contact_to_invite').each(function(index,checkbox) { checkbox.checked = true; });" %>
  28 + <%= link_to_function _('Uncheck all'), "jQuery('input.contact_to_invite').each(function(index,checkbox) { checkbox.checked = false; });" %>
29 29 <div id='contacts-list'></div>
30 30 </div>
31 31 <% end -%>
... ...
app/views/layouts/_javascript.html.erb
1   -<%= javascript_include_tag 'prototype.js', 'effects.js', 'dragdrop.js', 'controls.js',
2   -'jquery-2.1.1.min', 'jquery-migrate-1.2.1',
3   -'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox',
4   -'jquery-ui-1.10.4/js/jquery-ui-1.10.4.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate',
5   -'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', 'jquery.typewatch', 'jquery.textchange',
6   -'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow', 'select-or-die/_src/selectordie',
7   -'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'application.js', 'rails.js', 'inputosaurus.js', :cache => 'cache/application' %>
  1 +<%= javascript_include_tag 'jquery-2.1.1.min', 'jquery-migrate-1.2.1', 'jrails', 'rails.js',
  2 + 'jquery.cycle.all.min.js', 'jquery.colorbox-min.js',
  3 + 'jquery-ui-1.10.4/js/jquery-ui-1.10.4.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate',
  4 + 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', 'jquery.typewatch', 'jquery.textchange',
  5 + 'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'inputosaurus.js', 'select-or-die/_src/selectordie',
  6 + # noosfero libraries
  7 + 'application.js', 'modal.js',
  8 + 'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow',
  9 + :cache => 'cache/application' %>
8 10  
9 11 <% language = FastGettext.locale %>
10 12 <% %w{messages methods}.each do |type| %>
... ...
app/views/layouts/_user.html.erb
... ... @@ -7,11 +7,11 @@
7 7 </span>
8 8 <% else %>
9 9 <span class='not-logged-in'>
10   - <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %>
  10 + <%= _("<span class='login'>%s</span>") % modal_inline_link_to('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, '#inlineLoginBox', :id => 'link_login') %>
11 11 <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_exec(&content) }.join("") %>
12 12  
13 13 <div id='inlineLoginBox' style='display: none;'>
14   - <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
  14 + <%= render :file => 'account/login', :locals => { :is_popin => true } %>
15 15 </div>
16 16  
17 17 <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
... ...
app/views/layouts/application-ng.html.erb
... ... @@ -7,11 +7,6 @@
7 7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
8 8 <meta name="description" content="<%= @environment.name %>" />
9 9  
10   - <!-- Twitter Card -->
11   - <meta name="twitter:card" value="summary">
12   - <meta name="twitter:title" content="<%= h page_title %>">
13   - <meta name="twitter:description" content="<%= meta_description_tag(@page) %>">
14   -
15 10 <!-- site root -->
16 11 <meta property="noosfero:root" content="<%= Noosfero.root %>"/>
17 12  
... ... @@ -23,7 +18,7 @@
23 18 <%= yield :head %>
24 19 <%=
25 20 @plugins.dispatch(:head_ending).map do |content|
26   - if content.respond_to?(:call) then instance_exec(&content).html_safe else content.html_safe end
  21 + if content.respond_to?(:call) then instance_exec(&content).to_s.html_safe else content.to_s.html_safe end
27 22 end.join("\n")
28 23 %>
29 24  
... ... @@ -37,7 +32,7 @@
37 32  
38 33 <%=
39 34 @plugins.dispatch(:body_beginning).map do |content|
40   - if content.respond_to?(:call) then instance_exec(&content).html_safe else content.html_safe end
  35 + if content.respond_to?(:call) then instance_exec(&content).to_s.html_safe else content.to_s.html_safe end
41 36 end.join("\n")
42 37 %>
43 38  
... ...
app/views/manage_products/_categories_for_selection.html.erb
1 1 <%= select_for_categories(categories, level) %>
2 2  
3 3 <%= javascript_tag do %>
4   - jQuery('#categories_container_wrapper').scrollTo('100%', 1000)
5   - $('selected_category_id').value = <%= @category && @category.id %>
6   - $('hierarchy_navigation').update('<%= escape_javascript(hierarchy_category_navigation(@category, :make_links => true)) %>')
7   - toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, $('save_and_continue'))
  4 + jQuery(document).ready(function() {
  5 + jQuery('#categories_container_wrapper').scrollTo('100%', 1000)
  6 + jQuery('#selected_category_id').val(<%= @category.id rescue nil %>)
  7 + jQuery('#hierarchy_navigation').html(<%= hierarchy_category_navigation(@category, :make_links => true).to_json %>)
  8 + toggleDisabled(<%= (!!(@category && @category.accept_products?)).to_json %>, jQuery('#save_and_continue'))
  9 + });
8 10 <% end %>
... ...
app/views/manage_products/_display_name.html.erb
... ... @@ -3,7 +3,7 @@
3 3 <%= edit_product_link_to_remote(@product, 'name', _('Edit name and unit'), :title => _('Click here to edit the name of your product and the unit')) %>
4 4 </div>
5 5 <%= javascript_tag do %>
6   - $$('#display-product-category .hierarchy-category')[0].update('<%=
  6 + jQuery('#display-product-category .hierarchy-category').first().html('<%=
7 7 escape_javascript(hierarchy_category_navigation(
8 8 @product.product_category,
9 9 :make_links => false,
... ...
app/views/manage_products/new.html.erb
... ... @@ -26,5 +26,5 @@
26 26 <% end %>
27 27  
28 28 <%= javascript_tag do %>
29   - toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, $('save_and_continue'))
  29 + toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, jQuery('#save_and_continue')[0])
30 30 <% end %>
... ...
app/views/manage_products/show.html.erb
... ... @@ -24,6 +24,8 @@
24 24 <br style='clear: both'/>
25 25  
26 26 <% unless !@allowed_user && (@product.description.blank? && @product.inputs.empty? && !@product.price_described? ) %>
  27 + <% plugins_tabs = plugins_product_tabs %>
  28 +
27 29 <div class='ui-tabs' id='product-<%= @product.id %>-tabs'>
28 30 <ul>
29 31 <% if !@product.description.blank? || @allowed_user %>
... ... @@ -35,19 +37,32 @@
35 37 <% if @product.price_described? || @allowed_user %>
36 38 <li class='tab'><a href='#product-price-details'><%= _('Price composition') %></a></li>
37 39 <% end %>
  40 +
  41 + <% plugins_tabs.each do |tab| %>
  42 + <li class='tab'><a href='#<%=tab[:id]%>'><%= tab[:title] %></a></li>
  43 + <% end %>
  44 +
38 45 </ul>
  46 +
39 47 <div id='product-description'>
40 48 <%= render :partial => 'manage_products/display_description' %>
41 49 </div>
  50 +
42 51 <div id='product-inputs'>
43 52 <%= render :partial => 'manage_products/display_inputs' %>
44 53 </div>
  54 +
45 55 <% if @product.price_described? || @allowed_user %>
46 56 <div id='product-price-details'>
47 57 <%= render :partial => 'manage_products/display_price_details' %>
48 58 <%= render :partial => 'manage_products/price_details_button' %>
49 59 </div>
50 60 <% end %>
  61 +
  62 + <% plugins_tabs.each do |tab| %>
  63 + <div id='<%=tab[:id]%>'><%= raw tab[:content] %></div>
  64 + <% end %>
  65 +
51 66 </div>
52 67 <% end %>
53 68  
... ...
app/views/maps/_google_map.js.erb
... ... @@ -9,7 +9,7 @@ var mapZoom = 15;
9 9 var delay_autocomplete = 500;
10 10  
11 11 function pointToAddress(latlng) {
12   - $('location-fields').addClassName("loading");
  12 + jQuery('#location-fields').addClass("loading");
13 13  
14 14 if (latlng == null)
15 15 return;
... ... @@ -22,11 +22,11 @@ function pointToAddress(latlng) {
22 22  
23 23 var place = results[0];
24 24  
25   - $('location-fields').removeClassName("loading");
  25 + jQuery('#location-fields').removeClass("loading");
26 26  
27 27 var position = marker.getPosition();
28   - $('profile_data_lat').value = position.lat();
29   - $('profile_data_lng').value = position.lng();
  28 + jQuery('#profile_data_lat').val(position.lat());
  29 + jQuery('#profile_data_lng').val(position.lng());
30 30  
31 31 form = jQuery('#location-form')[0];
32 32 form.lat = marker.getPosition().lat();
... ... @@ -85,26 +85,26 @@ function pointToAddress(latlng) {
85 85 }
86 86  
87 87 if (country_code)
88   - $('profile_data_country').value = country_code;
  88 + jQuery('#profile_data_country').val(country_code);
89 89 if (state)
90   - $('profile_data_state').value = state;
  90 + jQuery('#profile_data_state').val(state);
91 91 if (city)
92   - $('profile_data_city').value = city;
  92 + jQuery('#profile_data_city').val(city);
93 93 if (zip_code)
94   - $('profile_data_zip_code').value = zip_code;
  94 + jQuery('#profile_data_zip_code').val(zip_code);
95 95 if (address)
96   - $('profile_data_address').value = address;
  96 + jQuery('#profile_data_address').val(address);
97 97  
98 98 map.setCenter(marker.getPosition());
99 99 });
100 100 }
101 101  
102 102 function addressToPoint() {
103   - $('location-fields').addClassName("loading");
  103 + jQuery('#location-fields').addClass("loading");
104 104  
105   - var country_option = $('profile_data_country').value;
106   - var address = $('profile_data_address').value + ", " + $('profile_data_zip_code').value + ", "
107   - + $('profile_data_city').value+ ", " + $('profile_data_state').value + ", " + country_option;
  105 + var country_option = jQuery('#profile_data_country').val();
  106 + var address = jQuery('#profile_data_address').val() + ", " + jQuery('#profile_data_zip_code').val() + ", "
  107 + + jQuery('#profile_data_city').val() + ", " + jQuery('#profile_data_state').val() + ", " + country_option;
108 108  
109 109 if (geocoder) {
110 110 geocoder.geocode({ 'address': address}, function(results, status) {
... ... @@ -113,12 +113,12 @@ function addressToPoint() {
113 113 marker.setPosition(results[0].geometry.location);
114 114 pointToAddress(marker.getPosition());
115 115  
116   - $('profile_data_lat').value = results[0].geometry.location.lat();
117   - $('profile_data_lng').value = results[0].geometry.location.lng();
118   - $('location-fields').removeClassName("loading");
  116 + jQuery('#profile_data_lat').val(results[0].geometry.location.lat());
  117 + jQuery('#profile_data_lng').val(results[0].geometry.location.lng());
  118 + jQuery('#location-fields').removeClass("loading");
119 119 enable_save();
120 120 } else {
121   - $('location-fields').removeClassName("loading");
  121 + jQuery('#location-fields').removeClass("loading");
122 122 alert('<%=_("Address not found, reason:")%>' + statusErrorMessage(status));
123 123 }
124 124 });
... ... @@ -175,7 +175,6 @@ function initializeMap() {
175 175  
176 176 }
177 177  
178   -jQuery.noConflict();
179 178 jQuery(document).ready(function () {
180 179  
181 180 initializeMap();
... ... @@ -198,7 +197,7 @@ jQuery(document).ready(function () {
198 197 source: "../maps/search_city",
199 198 minLength: 3,
200 199 delay: delay_autocomplete,
201   - select: function( event, ui ) { $('profile_data_state').value =( ui.item ? ui.item.category : this.value ); }
  200 + select: function( event, ui ) { jQuery('#profile_data_state').val( ui.item ? ui.item.category : this.value ); }
202 201 });
203 202  
204 203 jQuery("#profile_data_state").autocomplete({
... ...
app/views/profile/_profile_scrap.html.erb
... ... @@ -9,7 +9,7 @@
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'>
12   - <%= link_to_function s_('profile|Comment'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);$('reply_content_#{scrap.id}').value='';$('reply_content_#{scrap.id}').focus();return false", :class => "profile-send-reply" %>
  12 + <%= link_to_function s_('profile|Comment'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);jQuery('#reply_content_#{scrap.id}').val('');jQuery('#reply_content_#{scrap.id}').focus();return false", :class => "profile-send-reply" %>
13 13 </span>
14 14 <% end %>
15 15 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_scrap, :scrap_id => scrap.id, :view => params[:view]), _('Are you sure you want to remove this scrap and all its replies?')]) if logged_in? && user.can_control_scrap?(scrap) %>
... ...
app/views/profile/_profile_scraps.html.erb
... ... @@ -9,7 +9,7 @@
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'>
12   - <%= link_to_function s_('profile|Comment'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);$('reply_content_#{scrap.id}').value='';$('reply_content_#{scrap.id}').focus();return false", :class => "profile-send-reply" %>
  12 + <%= link_to_function s_('profile|Comment'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);jQuery('#reply_content_#{scrap.id}').val('');jQuery('#reply_content_#{scrap.id}').focus();return false", :class => "profile-send-reply" %>
13 13 </span>
14 14 <% end %>
15 15 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_scrap, :scrap_id => scrap.id, :view => params[:view]), _('Are you sure you want to remove this scrap and all its replies?')]) if logged_in? && user.can_control_scrap?(scrap) %>
... ...
app/views/profile/_profile_wall.html.erb
1 1 <h3><%= _("%s's wall") % @profile.name %></h3>
2 2 <div id='leave_scrap'>
3 3 <%= flash[:error] %>
4   - <%= form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "$('leave_scrap_content').value=''", :complete => "jQuery('#leave_scrap_form').removeClass('loading').find('*').attr('disabled', false)", :loading => "jQuery('#leave_scrap_form').addClass('loading').find('*').attr('disabled', true)", :html => {:id => 'leave_scrap_form' } do %>
  4 + <%= form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "jQuery('#leave_scrap_content').val('')", :complete => "jQuery('#leave_scrap_form').removeClass('loading').find('*').attr('disabled', false)", :loading => "jQuery('#leave_scrap_form').addClass('loading').find('*').attr('disabled', true)", :html => {:id => 'leave_scrap_form' } do %>
5 5 <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2, :class => 'autogrow' %>
6 6 <%= submit_button :new, _('Share') %>
7 7 <% end %>
... ...
app/views/profile/join.html.erb
... ... @@ -9,7 +9,7 @@
9 9 <%= hidden_field_tag(:confirmation, 1) %>
10 10 <%= submit_button(:ok, _("Yes, I want to join.") % profile.name) %>
11 11 <% if logged_in? && request.xhr? %>
12   - <%= lightbox_close_button(_("No, I don't want")) %>
  12 + <%= modal_close_button _("No, I don't want") %>
13 13 <% else %>
14 14 <%= button(:cancel, _("No, I don't want."), profile.url) %>
15 15 <% end %>
... ...
app/views/profile/leave.html.erb
... ... @@ -9,7 +9,7 @@
9 9 <%= hidden_field_tag(:back_to, @back_to) %>
10 10 <%= submit_button(:ok, _("Yes, I want to leave.") % profile.name) %>
11 11 <% if logged_in? && request.xhr? %>
12   - <%= lightbox_close_button(_("No, I don't want")) %>
  12 + <%= modal_close_button _("No, I don't want") %>
13 13 <% else %>
14 14 <%= button(:cancel, _("No, I don't want."), profile.url) %>
15 15 <% end %>
... ...
app/views/profile/report_abuse.html.erb
... ... @@ -9,7 +9,7 @@
9 9 <% end %>
10 10  
11 11 <%= submit_button(:send, _('Report profile'), :style => 'float: left; cursor: pointer;', :id => 'report-abuse-submit-button', :onclick => "jQuery('#form-submit-loading').show()") %>
12   - <%= button(:cancel, _('Cancel'), {}, :style => 'float: left; padding-top: 0px; padding-bottom: 0px;', :onclick => 'jQuery.colorbox.close(); return false;')%>
  12 + <%= button(:cancel, _('Cancel'), {}, :style => 'float: left; padding-top: 0px; padding-bottom: 0px;', :onclick => 'noosfero.modal.close(); return false;')%>
13 13 <div id="form-submit-loading" class="small-loading" style="width: 16px; height: 16px; margin-top: 3px; float: left; display: none;"></div>
14 14 <% end %>
15 15  
... ... @@ -30,7 +30,7 @@
30 30 success: function(data, status, ajax){
31 31 if ( !data.ok ) display_notice(data.error.message);
32 32 else {
33   - $.colorbox.close();
  33 + noosfero.modal.close();
34 34 display_notice(data.message);
35 35 window.location.reload();
36 36 }
... ...
app/views/profile_editor/_organization.html.erb
... ... @@ -19,7 +19,7 @@
19 19 <% if @environment.enabled?('enable_organization_url_change') %>
20 20 <script type="text/javascript">
21 21 function submit_button() {
22   - return $("profile-data").select("input.submit")[0];
  22 + return jQuery("#profile-data").find("input.submit")[0];
23 23 }
24 24 function warn_value_change() {
25 25 show_warning('profile-identifier-formitem', "identifier-change-confirmation");
... ... @@ -30,7 +30,7 @@
30 30 hide_warning('identifier-change-confirmation');
31 31 }
32 32 function no_change() {
33   - $("profile_data_identifier").value = $("old_profile_identifier").value;
  33 + jQuery("#profile_data_identifier").val(jQuery("#old_profile_identifier").val());
34 34 enable_button(submit_button());
35 35 hide_warning('identifier-change-confirmation');
36 36 }
... ...
app/views/profile_members/_add_admins.html.erb
1 1 <h2><%= _('Add admins to %s') % profile.name %></h2>
2 2  
3   -<%= form_remote_tag :url => {:action => 'find_users', :profile => profile.identifier, :scope => 'new_admins'}, :update => 'users-list', :loading => '$("users-list").addClassName("loading")', :complete => '$("users-list").removeClassName("loading")' do %>
  3 +<%= form_remote_tag :url => {:action => 'find_users', :profile => profile.identifier, :scope => 'new_admins'}, :update => 'users-list', :loading => 'jQuery("#users-list").addClass("loading")', :complete => 'jQuery("#users-list").removeClass("loading")' do %>
4 4 <%= text_field_tag('query', '', :autocomplete => 'off') %>
5 5 <%= submit_tag(_('Search')) %>
6 6 <% end %>
7 7  
8   -<%= observe_field('query', :url => {:action => 'find_users', :profile => profile.identifier, :scope => 'new_admins'}, :update => 'users-list', :frequency => 1, :with => 'query', :condition => '$("query").value.length > 2', :loading => '$("users-list").addClassName("loading")', :complete => '$("users-list").removeClassName("loading")') %>
9   -<%= observe_field('query', :frequency => 1, :condition => '$("query").value.length <= 2', :function => '$("users-list").update($("empty-query").innerHTML)') %>
  8 +<%= observe_field('query', :url => {:action => 'find_users', :profile => profile.identifier, :scope => 'new_admins'}, :update => 'users-list', :frequency => 1, :with => 'query', :condition => 'jQuery("#query").val().length > 2', :loading => 'jQuery("#users-list").addClass("loading")', :complete => 'jQuery("#users-list").removeClass("loading")') %>
  9 +<%= observe_field('query', :frequency => 1, :condition => 'jQuery("#query").val().length <= 2', :function => 'jQuery("#users-list").html(jQuery("#empty-query").html())') %>
10 10  
11 11 <div id="users-list">
12 12 <%= render :partial => 'find_users' %>
... ... @@ -21,10 +21,10 @@
21 21 </div>
22 22 <%= drop_receiving_element('members-list',
23 23 :url => {:action => 'add_admin', :profile => profile.identifier, :leaving_admin => @person},
24   - :before => '$("tr-" + element.id).hide()',
25   - :loading => '$("members-list").addClassName("loading")',
  24 + :before => 'jQuery("#tr-" + element.id).hide()',
  25 + :loading => 'jQuery("#members-list").addClass("loading")',
26 26 :update => 'members-list',
27   - :success => '$("tr-" + element.id).hide(); $(element.id).show();',
28   - :complete => '$("members-list").removeClassName("loading")') %>
  27 + :success => 'jQuery("#tr-" + element.id).hide(); jQuery("#"+element.id).show();',
  28 + :complete => 'jQuery("#members-list").removeClass("loading")') %>
29 29  
30 30 <br style="clear:both" />
... ...
app/views/profile_members/_members_list.html.erb
... ... @@ -17,9 +17,9 @@
17 17 <%= button_without_text :edit, _('Edit'), :action => 'change_role', :id => m %>
18 18 <%= button_to_remote_without_text(:remove, _('Remove'),
19 19 :update => 'members-list',
20   - :loading => "$('members-list').addClassName('loading')",
21   - :success => "$('tr-#{m.identifier}').show()",
22   - :complete => "$('members-list').removeClassName('loading')",
  20 + :loading => "jQuery('#members-list').addClass('loading')",
  21 + :success => "jQuery('#tr-#{m.identifier}').show()",
  22 + :complete => "jQuery('#members-list').removeClass('loading')",
23 23 :url => { :id => m }.merge(remove_action)) if m != user %>
24 24 </div>
25 25 </td>
... ...
app/views/profile_themes/add_css.html.erb
... ... @@ -5,7 +5,7 @@
5 5  
6 6 <% button_bar do %>
7 7 <%= submit_button(:add, _('Add')) %>
8   - <%= lightbox_close_button(_('Cancel')) %>
  8 + <%= modal_close_button _('Cancel') %>
9 9 <% end %>
10 10  
11 11 <% end %>
... ...
app/views/profile_themes/edit.html.erb
... ... @@ -16,7 +16,7 @@
16 16 <% end %>
17 17 </ul>
18 18 <% button_bar do %>
19   - <%= lightbox_button(:add, _('New CSS'), :action => 'add_css', :id => @theme.id) %>
  19 + <%= modal_button :add, _('New CSS'), :action => 'add_css', :id => @theme.id %>
20 20 <% end %>
21 21 </div>
22 22  
... ... @@ -25,10 +25,10 @@
25 25 <ul>
26 26 <% for image in @image_files %>
27 27 <li><%= image_tag("/user_themes/#{@theme.id}/images/#{image}") %></li>
28   - <% end %>
  28 + <% end %>
29 29 </ul>
30 30 <% button_bar do %>
31   - <%= lightbox_button(:add, _('Add image'), :action => 'add_image', :id => @theme.id) %>
  31 + <%= modal_button :add, _('Add image'), :action => 'add_image', :id => @theme.id %>
32 32 <% end %>
33 33 </div>
34 34  
... ...
app/views/profile_themes/index.html.erb
... ... @@ -42,7 +42,7 @@
42 42  
43 43 <% button_bar do %>
44 44 <% if environment.enabled?('user_themes') %>
45   - <%= lightbox_button(:add, _('New theme ...'), :action => 'new') %>
  45 + <%= modal_button :add, _('New theme ...'), :action => 'new' %>
46 46 <% end %>
47 47 <%= button(:back, _('Back'), :controller => 'profile_editor', :action => 'index') %>
48 48 <% end %>
... ...
app/views/shared/logged_in/xmpp_chat.html.erb
... ... @@ -12,33 +12,27 @@
12 12 var $presence = '<%= current_user.last_chat_status %>';
13 13 </script>
14 14  
  15 +
  16 + <div id="chat-label">
  17 + <span class="right-arrow">&#9654;</span>
  18 + <span class="title"><%= _('Chat') %></span>
  19 + </div>
  20 +
15 21 <div id='chat'>
16 22 <div id='buddy-list'>
17 23 <div class='toolbar'>
18 24 <div id='user-status'>
19   - <%= profile_image(user, :portrait, :class => 'avatar') %>
20 25 <%= user_status_menu('icon-menu-offline', _('Offline')) %>
21 26 </div>
22   - <a href="#" class="back"><%= _('Close') %></a>
23 27 <div class='dialog-error' style='display: none'></div>
24 28 </div>
25 29  
26   - <div id="friends">
27   - <div class="status-group">
28   - <div class='title-bar'><a href="#"><h1 class='title'><%= _("Online") %>&nbsp;(<span id='friends-online'>0</span>)</h1></a></div>
29   - <ul class='buddy-list online'></ul>
30   - </div>
31   -
32   - <div class="status-group">
33   - <div class='title-bar'><a href="#"><h1 class='title'><%= _("Offline") %>&nbsp;(<span id='friends-offline'>0</span>)</h1></a></div>
34   - <ul class='buddy-list offline'></ul>
35   - </div>
36   - </div>
  30 + <div class='body'>
  31 + <%= text_field_tag(:query, '', :placeholder => _('Search...'), :class => 'search') %>
37 32  
38   - <div id="rooms">
39   - <div class="status-group">
40   - <div class='title-bar'><a href="#"><h1 class='title'><%= _("Groups") %>&nbsp;(<span id='groups-online'>0</span>)</h1></a></div>
41   - <ul class="buddy-list room-list"></ul>
  33 + <div class='buddies'>
  34 + <ul class='online'></ul>
  35 + <ul class='offline'></ul>
42 36 </div>
43 37 </div>
44 38 </div>
... ... @@ -47,37 +41,37 @@
47 41 <div id='conversations'></div>
48 42 </div>
49 43  
50   - <div id="chat-templates">
  44 + <div id="chat-templates" style="display: none;">
51 45  
52   - <div class="conversation-template">
53   - <div class='conversation' style="display: none;">
54   - <div class="header">
55   - <span class="chat-target">
56   - <img class="avatar">
57   - <span class="other-name"></span>
58   - </span>
59   - <a href="#" class="back"><%= _('Back') %></a>
60   - </div>
61   - <div class='history'></div>
62   - <div class='input-div'>
63   - <div class='icon-chat'></div>
64   - <textarea class='input'></textarea>
65   - </div>
  46 + <div class="conversation">
  47 + <div class="conversation-header">
  48 + <span class="chat-target">
  49 + <img class="avatar">
  50 + <span class="other-name"></span>
  51 + </span>
  52 + </div>
  53 + <div class='history'></div>
  54 + <div class='input-div'>
  55 + <div class='icon-chat'></div>
  56 + <textarea class='input'></textarea>
66 57 </div>
67 58 </div>
68 59  
  60 + <a class='join room-action'><%= _('Join room') %></a>
  61 + <a class='leave room-action' style="display: none"><%= _('Leave room') %></a>
  62 +
69 63 <div class="buddy-item">
70 64 <li class='%{presence_status}'>
71 65 <a id='%{jid_id}' class='icon-menu-%{presence_status}-11' href='#'>
  66 + <span class="unread-messages"></span>
72 67 %{avatar}
73 68 <span class="name">%{name}</span>
74   - <span class="unread-messages icon-chat"></span>
75 69 </a>
76 70 </li>
77 71 </div>
78 72  
79 73 <div class="occupant-list-template">
80   - <div class="occupants">
  74 + <div class="occupants room-action">
81 75 <a href="#" class="up"><%= _('Online') %>&nbsp;(<span class="occupants-online">0</span>)</a>
82 76 <ul class='occupant-list'></ul>
83 77 </div>
... ... @@ -86,20 +80,20 @@
86 80 <div class="occupant-item">
87 81 <li class='%{presence_status}'>
88 82 <a data-id='%{jid_id}' class='icon-menu-%{presence_status}-11' href='#'>
  83 + <span class="unread-messages"></span>
89 84 %{avatar}
90   - <span class="name">%{name}</span>
  85 + <span class="name">%{name}<span>
91 86 </a>
92 87 </li>
93 88 </div>
94 89  
95 90 <div class="message">
96 91 <div data-who="%{who}" class="message %{who}">
97   - <div class="author">
98   - %{avatar}
99   - <h5 class="%{who}-name">%{name}</h5>
100   - </div>
101 92 <div class="content">
102 93 <span class="time" title="%{time}"></span>
  94 + <div class="author">
  95 + %{avatar}
  96 + </div>
103 97 <p>%{message}</p>
104 98 </div>
105 99 </div>
... ... @@ -111,3 +105,7 @@
111 105  
112 106 </div>
113 107 </div>
  108 + <a href='#' id='chat-online-users-title' onclick='return false;'>
  109 + <div class='header'><i class='icon-chat'></i><span><%= _("Friends in chat (<span class='amount_of_friends'>%{amount}</span>)") %></span></div>
  110 + </a>
  111 +</div>
... ...
app/views/shared/profile_actions/xmpp_chat.html.erb
... ... @@ -1,5 +0,0 @@
1   -<% if profile.members.include?(user) %>
2   - <li>
3   - <%= button_to_function(:chat, _('Enter chat room'), "open_chat_window(this, '##{profile.full_jid}')") %>
4   - </li>
5   -<% end %>
app/views/shared/user_menu.html.erb
... ... @@ -20,7 +20,7 @@
20 20 </li>
21 21  
22 22 <li>
23   - <%= lightbox_link_to('<span class="icon-new"></span>' + _('New article'), '/myprofile/{login}/cms/new') %>
  23 + <%= modal_link_to '<span class="icon-new"></span>' + _('New article'), '/myprofile/{login}/cms/new' %>
24 24 </li>
25 25  
26 26 <li id='manage-enterprises-link-template' style='display: none'><a href='/myprofile/{identifier}'><span class="icon-menu-enterprise"></span><%= _('Manage %s') % '{name}' %></a></li>
... ... @@ -58,9 +58,9 @@
58 58 <% if theme_option( :menu_login ) == 'full_form' %>
59 59 <%= render :file => 'account/login_block' %>
60 60 <% else %>
61   - <%= thickbox_inline_popup_link('<span class="icon-menu-login"></span>'+ _('Login'), login_url, 'inlineLoginBox', :id => 'link_login') %>
  61 + <%= modal_inline_link_to('<span class="icon-menu-login"></span>'+ _('Login'), login_url, '#inlineLoginBox', :id => 'link_login') %>
62 62 <div id='inlineLoginBox' style='display: none;'>
63   - <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
  63 + <%= render :file => 'account/login', :locals => { :is_popin => true } %>
64 64 </div>
65 65 <% end %>
66 66 <% end %>
... ...
app/views/shared/usermenu/xmpp_chat.html.erb
... ... @@ -1 +0,0 @@
1   -<%= link_to('<i class="icon-chat"></i><span class="unread-messages"></span>&nbsp;<strong>' + _('Open chat') +'</strong>', '#', :id => 'openchat', :onclick => 'open_chat_window(this)') %>
config/application.rb
1 1 require File.expand_path('../boot', __FILE__)
2 2  
3 3 require 'rails/all'
  4 +require 'active_support/dependencies'
4 5  
5 6 # FIXME this silences the warnings about Rails 2.3-style plugins under
6 7 # vendor/plugins, which are deprecated. Hiding those warnings makes it easier
... ...
config/database.yml.multitenancy
1 1 # Refer to INSTALL.multitenancy for more information on Multitenancy support
2   -env1_production:
  2 +env1_production: &DEFAULT
3 3 adapter: postgresql
4 4 encoding: unicode
5 5 database: noosfero
... ... @@ -30,4 +30,4 @@ env3_production:
30 30 - env3.net
31 31  
32 32 production:
33   - env1_production
  33 + <<: *DEFAULT
... ...
config/noosfero.yml.dist
... ... @@ -9,6 +9,7 @@ development:
9 9 googlemaps_initial_zoom: 4
10 10 exception_recipients: [admin@example.com]
11 11 max_upload_size: 5MB
  12 + hours_until_user_activation_check: 72
12 13  
13 14 test:
14 15  
... ...
config/schedule.rb
... ... @@ -25,6 +25,6 @@ every 1.day do
25 25 runner "SearchTerm.calculate_scores"
26 26 end
27 27  
28   -every 90.days do
  28 +every 30.days do
29 29 runner "ProfileSuggestion.generate_all_profile_suggestions"
30 30 end
... ...
db/migrate/20120820120000_index_parent_id_from_all_tables.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +class IndexParentIdFromAllTables < ActiveRecord::Migration
  2 + def self.up
  3 + add_index :article_versions, :parent_id
  4 + add_index :categories, :parent_id
  5 + add_index :images, :parent_id
  6 + add_index :tags, :parent_id
  7 + add_index :thumbnails, :parent_id
  8 + end
  9 +
  10 + def self.down
  11 + remove_index :article_versions, :parent_id
  12 + remove_index :categories, :parent_id
  13 + remove_index :images, :parent_id
  14 + remove_index :tags, :parent_id
  15 + remove_index :thumbnails, :parent_id
  16 + end
  17 +end
... ...
db/migrate/20120820142056_add_ancestry_to_categories.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class AddAncestryToCategories < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :categories, :ancestry, :text
  4 +
  5 + Category.build_ancestry
  6 + end
  7 +
  8 + def self.down
  9 + remove_column :categories, :ancestry
  10 + end
  11 +end
... ...
db/migrate/20140519113821_add_last_login_at_to_user.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddLastLoginAtToUser < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :users, :last_login_at, :datetime
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :users, :last_login_at
  8 + end
  9 +end
... ...
db/migrate/20140709212646_add_spam_comments_counter_cache_to_articles.rb
... ... @@ -3,7 +3,7 @@ class AddSpamCommentsCounterCacheToArticles &lt; ActiveRecord::Migration
3 3 add_column :articles, :spam_comments_count, :integer, :default => 0
4 4 add_column :article_versions, :spam_comments_count, :integer, :default => 0
5 5  
6   - execute("SELECT comments.source_id as source_id, count(comments.id) as comments_count FROM comments LEFT OUTER JOIN articles ON articles.id = source_id WHERE comments.source_type = 'Article' AND comments.spam = 't' GROUP BY comments.source_id;").each do |data|
  6 + execute("SELECT comments.source_id as source_id, count(comments.id) as comments_count FROM comments LEFT OUTER JOIN articles ON articles.id = source_id WHERE comments.source_type = 'Article' AND comments.spam = true GROUP BY comments.source_id;").each do |data|
7 7 execute("UPDATE articles SET spam_comments_count = '#{data['comments_count']}' WHERE id = #{data['source_id']}")
8 8 end
9 9 end
... ...
db/migrate/20150112233715_normalize_users_email.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class NormalizeUsersEmail < ActiveRecord::Migration
  2 + def up
  3 + User.find_each do |u|
  4 + u.update_column :email, u.send(:normalize_email)
  5 + end
  6 + end
  7 +
  8 + def down
  9 + say "this migration can't be reverted"
  10 + end
  11 +end
... ...
db/schema.rb
... ... @@ -101,6 +101,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
101 101 end
102 102  
103 103 add_index "article_versions", ["article_id"], :name => "index_article_versions_on_article_id"
  104 + add_index "article_versions", ["parent_id"], :name => "index_article_versions_on_parent_id"
104 105 add_index "article_versions", ["path", "profile_id"], :name => "index_article_versions_on_path_and_profile_id"
105 106 add_index "article_versions", ["path"], :name => "index_article_versions_on_path"
106 107 add_index "article_versions", ["published_at", "id"], :name => "index_article_versions_on_published_at_and_id"
... ... @@ -217,8 +218,11 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
217 218 t.string "acronym"
218 219 t.string "abbreviation"
219 220 t.string "display_color", :limit => 6
  221 + t.text "ancestry"
220 222 end
221 223  
  224 + add_index "categories", ["parent_id"], :name => "index_categories_on_parent_id"
  225 +
222 226 create_table "categories_profiles", :id => false, :force => true do |t|
223 227 t.integer "profile_id"
224 228 t.integer "category_id"
... ... @@ -237,6 +241,14 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
237 241 t.datetime "updated_at"
238 242 end
239 243  
  244 + create_table "chat_messages", :force => true do |t|
  245 + t.integer "to_id"
  246 + t.integer "from_id"
  247 + t.string "body"
  248 + t.datetime "created_at", :null => false
  249 + t.datetime "updated_at", :null => false
  250 + end
  251 +
240 252 create_table "comments", :force => true do |t|
241 253 t.string "title"
242 254 t.text "body"
... ... @@ -251,6 +263,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
251 263 t.string "source_type"
252 264 t.string "user_agent"
253 265 t.string "referrer"
  266 + t.text "setting"
  267 + t.integer "paragraph_id"
254 268 end
255 269  
256 270 add_index "comments", ["source_id", "spam"], :name => "index_comments_on_source_id_and_spam"
... ... @@ -357,6 +371,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
357 371 t.boolean "thumbnails_processed", :default => false
358 372 end
359 373  
  374 + add_index "images", ["parent_id"], :name => "index_images_on_parent_id"
  375 +
360 376 create_table "inputs", :force => true do |t|
361 377 t.integer "product_id", :null => false
362 378 t.integer "product_category_id", :null => false
... ... @@ -650,6 +666,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
650 666 end
651 667  
652 668 add_index "tags", ["name"], :name => "index_tags_on_name", :unique => true
  669 + add_index "tags", ["parent_id"], :name => "index_tags_on_parent_id"
653 670  
654 671 create_table "tasks", :force => true do |t|
655 672 t.text "data"
... ... @@ -689,6 +706,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
689 706 t.string "thumbnail"
690 707 end
691 708  
  709 + add_index "thumbnails", ["parent_id"], :name => "index_thumbnails_on_parent_id"
  710 +
692 711 create_table "units", :force => true do |t|
693 712 t.string "singular", :null => false
694 713 t.string "plural", :null => false
... ... @@ -699,23 +718,26 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
699 718 create_table "users", :force => true do |t|
700 719 t.string "login"
701 720 t.string "email"
702   - t.string "crypted_password", :limit => 40
703   - t.string "salt", :limit => 40
  721 + t.string "crypted_password", :limit => 40
  722 + t.string "salt", :limit => 40
704 723 t.datetime "created_at"
705 724 t.datetime "updated_at"
706 725 t.string "remember_token"
707 726 t.datetime "remember_token_expires_at"
708 727 t.text "terms_of_use"
709   - t.string "terms_accepted", :limit => 1
  728 + t.string "terms_accepted", :limit => 1
710 729 t.integer "environment_id"
711 730 t.string "password_type"
712   - t.boolean "enable_email", :default => false
713   - t.string "last_chat_status", :default => ""
714   - t.string "chat_status", :default => ""
  731 + t.boolean "enable_email", :default => false
  732 + t.string "last_chat_status", :default => ""
  733 + t.string "chat_status", :default => ""
715 734 t.datetime "chat_status_at"
716   - t.string "activation_code", :limit => 40
  735 + t.string "activation_code", :limit => 40
717 736 t.datetime "activated_at"
718 737 t.string "return_to"
  738 + t.datetime "last_login_at"
  739 + t.string "private_token"
  740 + t.datetime "private_token_generated_at"
719 741 end
720 742  
721 743 create_table "validation_infos", :force => true do |t|
... ...
debian/control
... ... @@ -48,7 +48,6 @@ Depends: adduser,
48 48 ruby-feedparser,
49 49 ruby-feedparser (>= 0.7-3~),
50 50 ruby-gettext,
51   - ruby-hpricot,
52 51 ruby-memcache-client,
53 52 ruby-minitest,
54 53 ruby-nokogiri,
... ...
features/events.feature
... ... @@ -9,6 +9,7 @@ Feature: events
9 9 And the following events
10 10 | owner | name | start_date |
11 11 | josesilva | Another Conference | 2009-10-24 |
  12 + | josesilva | Some Conference | 2009-10-22 |
12 13  
13 14 Scenario: go to next month
14 15 Given I am on /profile/josesilva/events/2009/10
... ... @@ -114,9 +115,11 @@ Feature: events
114 115 @selenium
115 116 Scenario: show events when i follow a specific day
116 117 Given I am on /profile/josesilva/events/2009/10
117   - And I should see "Another Conference"
  118 + And I should see "Another Conference" within "#agenda"
  119 + And I should see "Some Conference" within "#agenda"
118 120 When I follow "24"
119   - Then I should see "Another Conference"
  121 + Then I should see "Another Conference" within "#agenda"
  122 + And I should not see "Some Conference" within "#agenda"
120 123  
121 124 @selenium
122 125 Scenario: show events in a range when i follow a specific day
... ...
lib/acts_as_filesystem.rb
1 1 module ActsAsFileSystem
2 2  
3   - module ClassMethods
  3 + module ActsMethods
4 4  
5 5 # Declares the ActiveRecord model to acts like a filesystem: objects are
6 6 # arranged in a tree (liks acts_as_tree), and . The underlying table must
... ... @@ -14,66 +14,80 @@ module ActsAsFileSystem
14 14 # the parent, a "/" and the slug of the object)
15 15 # * children_count - a cache of the number of children elements.
16 16 def acts_as_filesystem
17   -
18   - include ActsAsFileSystem::InstanceMethods
19   -
20 17 # a filesystem is a tree
21   - acts_as_tree :order => 'name', :counter_cache => :children_count
  18 + acts_as_tree :counter_cache => :children_count
22 19  
23   - # calculate the right path
24   - before_create do |record|
25   - if record.path == record.slug && (! record.top_level?)
26   - record.path = record.calculate_path
27   - end
28   - true
  20 + extend ClassMethods
  21 + include InstanceMethods
  22 + if self.has_path?
  23 + after_update :update_children_path
  24 + before_create :set_path
  25 + include InstanceMethods::PathMethods
29 26 end
30 27  
31   - # when renaming a category, all children categories must have their paths
32   - # recalculated
33   - after_update do |record|
34   - if record.recalculate_path
35   - record.children.each do |item|
36   - item.path = item.calculate_path
37   - item.recalculate_path = true
38   - item.save!
39   - end
  28 + before_save :set_ancestry
  29 + end
  30 +
  31 + end
  32 +
  33 + module ClassMethods
  34 +
  35 + def build_ancestry(parent_id = nil, ancestry = '')
  36 + ActiveRecord::Base.transaction do
  37 + self.base_class.all(:conditions => {:parent_id => parent_id}).each do |node|
  38 + node.update_column :ancestry, ancestry
  39 +
  40 + build_ancestry node.id, (ancestry.empty? ? "#{node.formatted_ancestry_id}" :
  41 + "#{ancestry}#{node.ancestry_sep}#{node.formatted_ancestry_id}")
40 42 end
41   - record.recalculate_path = false
42   - true
43 43 end
44 44  
  45 + #raise "Couldn't reach and set ancestry on every record" if self.base_class.count(:conditions => ['ancestry is null']) != 0
  46 + end
  47 +
  48 + def has_path?
  49 + (['name', 'slug', 'path'] - self.column_names).blank?
45 50 end
  51 +
46 52 end
47 53  
48 54 module InstanceMethods
49   - # used to know when to trigger batch renaming
50   - attr_accessor :recalculate_path
51 55  
52   - # calculates the full name of a category by accessing the name of all its
53   - # ancestors.
54   - #
55   - # If you have this category hierarchy:
56   - # Category "A"
57   - # Category "B"
58   - # Category "C"
59   - #
60   - # Then Category "C" will have "A/B/C" as its full name.
61   - def full_name(sep = '/')
62   - self.hierarchy.map {|item| item.name || '?' }.join(sep)
  56 + def ancestry_column
  57 + 'ancestry'
  58 + end
  59 + def ancestry_sep
  60 + '.'
  61 + end
  62 + def has_ancestry?
  63 + self.class.column_names.include? self.ancestry_column
  64 + end
  65 +
  66 + def formatted_ancestry_id
  67 + "%010d" % self.id if self.id
63 68 end
64 69  
65   - # gets the name without leading parents. Usefull when dividing categories
66   - # in top-level groups and full names must not include the top-level
67   - # category which is already a emphasized label
68   - def full_name_without_leading(count, sep = '/')
69   - parts = self.full_name(sep).split(sep)
70   - count.times { parts.shift }
71   - parts.join(sep)
  70 + def ancestry
  71 + self[ancestry_column]
  72 + end
  73 + def ancestor_ids
  74 + return nil if !has_ancestry? or ancestry.nil?
  75 + @ancestor_ids ||= ancestry.split(ancestry_sep).map{ |id| id.to_i }
  76 + end
  77 +
  78 + def ancestry=(value)
  79 + self[ancestry_column] = value
  80 + end
  81 + def set_ancestry
  82 + return unless self.has_ancestry?
  83 + if self.ancestry.nil? or (new_record? or parent_id_changed?) or recalculate_path
  84 + self.ancestry = self.hierarchy(true)[0...-1].map{ |p| p.formatted_ancestry_id }.join(ancestry_sep)
  85 + end
72 86 end
73 87  
74   - # calculates the level of the category in the category hierarchy. Top-level
75   - # categories have level 0; the children of the top-level categories have
76   - # level 1; the children of categories with level 1 have level 2, and so on.
  88 + # calculates the level of the record in the records hierarchy. Top-level
  89 + # records have level 0; the children of the top-level records have
  90 + # level 1; the children of records with level 1 have level 2, and so on.
77 91 #
78 92 # A level 0
79 93 # / \
... ... @@ -82,61 +96,36 @@ module ActsAsFileSystem
82 96 # E F G H level 2
83 97 # ...
84 98 def level
85   - self.parent ? (self.parent.level + 1) : 0
  99 + self.hierarchy.size - 1
86 100 end
87 101  
88   - # Is this category a top-level category?
  102 + # Is this record a top-level record?
89 103 def top_level?
90 104 self.parent.nil?
91 105 end
92 106  
93   - # Is this category a leaf in the hierarchy tree of categories?
  107 + # Is this record a leaf in the hierarchy tree of records?
94 108 #
95   - # Being a leaf means that this category has no subcategories.
  109 + # Being a leaf means that this record has no subrecord.
96 110 def leaf?
97 111 self.children.empty?
98 112 end
99 113  
100   - def set_name(value)
101   - if self.name != value
102   - self.recalculate_path = true
103   - end
104   - self[:name] = value
105   - end
106   -
107   - # sets the name of the category. Also sets #slug accordingly.
108   - def name=(value)
109   - self.set_name(value)
110   - unless self.name.blank?
111   - self.slug = self.name.to_slug
112   - end
113   - end
114   -
115   - # sets the slug of the category. Also sets the path with the new slug value.
116   - def slug=(value)
117   - self[:slug] = value
118   - unless self.slug.blank?
119   - self.path = self.calculate_path
  114 + def top_ancestor
  115 + if has_ancestry? and !ancestry.nil?
  116 + self.class.base_class.find_by_id self.top_ancestor_id
  117 + else
  118 + self.hierarchy.first
120 119 end
121 120 end
122   -
123   - # calculates the full path to this category using parent's path.
124   - def calculate_path
125   - if self.top_level?
126   - self.slug
  121 + def top_ancestor_id
  122 + if has_ancestry? and !ancestry.nil?
  123 + self.ancestor_ids.first
127 124 else
128   - self.parent.calculate_path + "/" + self.slug
  125 + self.hierarchy.first.id
129 126 end
130 127 end
131 128  
132   - def top_ancestor
133   - self.top_level? ? self : self.parent.top_ancestor
134   - end
135   -
136   - def explode_path
137   - path.split(/\//)
138   - end
139   -
140 129 # returns the full hierarchy from the top-level item to this one. For
141 130 # example, if item1 has a children item2 and item2 has a children item3,
142 131 # then item3's hierarchy would be [item1, item2, item3].
... ... @@ -145,16 +134,21 @@ module ActsAsFileSystem
145 134 # when the ActiveRecord object was modified in some way, or just after
146 135 # changing parent)
147 136 def hierarchy(reload = false)
148   - if reload
149   - @hierarchy = nil
150   - end
  137 + @hierarchy = nil if reload or recalculate_path
151 138  
152   - unless @hierarchy
  139 + if @hierarchy.nil?
153 140 @hierarchy = []
154   - item = self
155   - while item
156   - @hierarchy.unshift(item)
157   - item = item.parent
  141 +
  142 + if !reload and !recalculate_path and ancestor_ids
  143 + objects = self.class.base_class.all(:conditions => {:id => ancestor_ids})
  144 + ancestor_ids.each{ |id| @hierarchy << objects.find{ |t| t.id == id } }
  145 + @hierarchy << self
  146 + else
  147 + item = self
  148 + while item
  149 + @hierarchy.unshift(item)
  150 + item = item.parent
  151 + end
158 152 end
159 153 end
160 154  
... ... @@ -181,8 +175,86 @@ module ActsAsFileSystem
181 175 res
182 176 end
183 177  
  178 + #####
  179 + # Path methods
  180 + # These methods are used when _path_, _name_ and _slug_ attributes exist
  181 + # and should be calculated based on the tree
  182 + #####
  183 + module PathMethods
  184 + # used to know when to trigger batch renaming
  185 + attr_accessor :recalculate_path
  186 +
  187 + # calculates the full path to this record using parent's path.
  188 + def calculate_path
  189 + self.hierarchy.map{ |obj| obj.slug }.join('/')
  190 + end
  191 + def set_path
  192 + if self.path == self.slug && !self.top_level?
  193 + self.path = self.calculate_path
  194 + end
  195 + end
  196 + def explode_path
  197 + path.split(/\//)
  198 + end
  199 +
  200 + def update_children_path
  201 + if self.recalculate_path
  202 + self.children.each do |child|
  203 + child.path = child.calculate_path
  204 + child.recalculate_path = true
  205 + child.save!
  206 + end
  207 + end
  208 + self.recalculate_path = false
  209 + end
  210 +
  211 + # calculates the full name of a record by accessing the name of all its
  212 + # ancestors.
  213 + #
  214 + # If you have this record hierarchy:
  215 + # Record "A"
  216 + # Record "B"
  217 + # Record "C"
  218 + #
  219 + # Then Record "C" will have "A/B/C" as its full name.
  220 + def full_name(sep = '/')
  221 + self.hierarchy.map {|item| item.name || '?' }.join(sep)
  222 + end
  223 +
  224 + # gets the name without leading parents. Useful when dividing records
  225 + # in top-level groups and full names must not include the top-level
  226 + # record which is already a emphasized label
  227 + def full_name_without_leading(count, sep = '/')
  228 + parts = self.full_name(sep).split(sep)
  229 + count.times { parts.shift }
  230 + parts.join(sep)
  231 + end
  232 +
  233 + def set_name(value)
  234 + if self.name != value
  235 + self.recalculate_path = true
  236 + end
  237 + self[:name] = value
  238 + end
  239 +
  240 + # sets the name of the record. Also sets #slug accordingly.
  241 + def name=(value)
  242 + self.set_name(value)
  243 + unless self.name.blank?
  244 + self.slug = self.name.to_slug
  245 + end
  246 + end
  247 +
  248 + # sets the slug of the record. Also sets the path with the new slug value.
  249 + def slug=(value)
  250 + self[:slug] = value
  251 + unless self.slug.blank?
  252 + self.path = self.calculate_path
  253 + end
  254 + end
  255 + end
184 256 end
185 257 end
186 258  
187   -ActiveRecord::Base.extend ActsAsFileSystem::ClassMethods
  259 +ActiveRecord::Base.extend ActsAsFileSystem::ActsMethods
188 260  
... ...
lib/acts_as_having_boxes.rb
... ... @@ -27,8 +27,9 @@ module ActsAsHavingBoxes
27 27 end
28 28  
29 29 # returns 3 unless the class table has a boxes_limit column. In that case
30   - # return the value of the column.
31   - def boxes_limit
  30 + # return the value of the column.
  31 + def boxes_limit layout_template = nil
  32 + layout_template ||= self.layout_template
32 33 @boxes_limit ||= LayoutTemplate.find(layout_template).number_of_boxes || 3
33 34 end
34 35  
... ...
lib/authenticated_system.rb
... ... @@ -5,22 +5,23 @@ module AuthenticatedSystem
5 5 def logged_in?
6 6 current_user != nil
7 7 end
8   -
  8 +
9 9 # Accesses the current user from the session.
10 10 def current_user
11 11 @current_user ||= (session[:user] && User.find_by_id(session[:user])) || nil
12 12 end
13   -
  13 +
14 14 # Store the given user in the session.
15 15 def current_user=(new_user)
16 16 if new_user.nil?
17 17 session.delete(:user)
18 18 else
19 19 session[:user] = new_user.id
  20 + new_user.register_login
20 21 end
21 22 @current_user = new_user
22 23 end
23   -
  24 +
24 25 # Check if the user is authorized.
25 26 #
26 27 # Override this method in your controllers if you want to restrict access
... ... @@ -62,7 +63,7 @@ module AuthenticatedSystem
62 63 access_denied
63 64 end
64 65 end
65   -
  66 +
66 67 # Redirect as appropriate when an access request fails.
67 68 #
68 69 # The default action is to redirect to the login screen.
... ... @@ -88,15 +89,15 @@ module AuthenticatedSystem
88 89 end
89 90 end
90 91 false
91   - end
92   -
  92 + end
  93 +
93 94 # Store the URI of the current request in the session.
94 95 #
95 96 # We can return to this location by calling #redirect_back_or_default.
96 97 def store_location(location = request.url)
97 98 session[:return_to] = location
98 99 end
99   -
  100 +
100 101 # Redirect to the URI stored by the most recent store_location call or
101 102 # to the passed default.
102 103 def redirect_back_or_default(default)
... ... @@ -106,7 +107,7 @@ module AuthenticatedSystem
106 107 redirect_to(default)
107 108 end
108 109 end
109   -
  110 +
110 111 # Inclusion hook to make #current_user and #logged_in?
111 112 # available as ActionView helper methods.
112 113 def self.included(base)
... ... @@ -132,6 +133,6 @@ module AuthenticatedSystem
132 133 def get_auth_data
133 134 auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
134 135 auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
135   - return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
  136 + return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
136 137 end
137 138 end
... ...
lib/noosfero/constants.rb
1 1 module Noosfero::Constants
2   - EMAIL_FORMAT = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
  2 + EMAIL_FORMAT = /\A([^@\s]+)@((?:[-_a-z0-9]+\.)+[a-z]{2,})\Z/i
3 3 INTEGER_FORMAT = /\A\d*\Z/i
4 4 PROFILE_PER_PAGE = 10
5 5 end
... ...
lib/noosfero/plugin.rb
... ... @@ -24,11 +24,17 @@ class Noosfero::Plugin
24 24  
25 25 def initialize!
26 26 return if !should_load
27   - available_plugins.each do |plugin_dir|
  27 +
  28 + klasses = available_plugins.map do |plugin_dir|
28 29 plugin_name = File.basename(plugin_dir)
29   - plugin = load_plugin(plugin_name)
30   - load_plugin_extensions(plugin_dir)
31   - load_plugin_filters(plugin)
  30 + load_plugin plugin_name
  31 + end
  32 + available_plugins.each do |plugin_dir|
  33 + load_plugin_extensions plugin_dir
  34 + end
  35 + # filters must be loaded after all extensions
  36 + klasses.each do |plugin|
  37 + load_plugin_filters plugin
32 38 end
33 39 end
34 40  
... ... @@ -88,7 +94,7 @@ class Noosfero::Plugin
88 94 # This is a generic method that initialize any possible filter defined by a
89 95 # plugin to a specific controller
90 96 def load_plugin_filters(plugin)
91   - Rails.configuration.to_prepare do
  97 + ActionDispatch::Reloader.to_prepare do
92 98 filters = plugin.new.send 'application_controller_filters' rescue []
93 99 Noosfero::Plugin.add_controller_filters ApplicationController, plugin, filters
94 100  
... ... @@ -116,7 +122,7 @@ class Noosfero::Plugin
116 122 end
117 123  
118 124 def load_plugin_extensions(dir)
119   - Rails.configuration.to_prepare do
  125 + ActionDispatch::Reloader.to_prepare do
120 126 Dir[File.join(dir, 'lib', 'ext', '*.rb')].each {|file| require_dependency file }
121 127 end
122 128 end
... ... @@ -267,7 +273,16 @@ class Noosfero::Plugin
267 273 nil
268 274 end
269 275  
270   - # -> Adds content to catalog item
  276 + # -> Adds tabs to the products
  277 + # returns = { :title => title, :id => id, :content => content }
  278 + # title = name that will be displayed.
  279 + # id = div id.
  280 + # content = lambda block that creates html code.
  281 + def product_tabs product
  282 + nil
  283 + end
  284 +
  285 + # -> Adds content to calalog item
271 286 # returns = lambda block that creates html code
272 287 def catalog_item_extras(item)
273 288 nil
... ... @@ -444,7 +459,7 @@ class Noosfero::Plugin
444 459 def upload_files_extra_fields(article)
445 460 nil
446 461 end
447   -
  462 +
448 463 # -> Adds fields to the signup form
449 464 # returns = proc that creates html code
450 465 def signup_extra_contents
... ...