Commit 11dfb86bf56dd6ce8784ab13682b46a96f9efc2f

Authored by Rodrigo Souto
2 parents d442dac2 ec0f8b0e

Merge branch 'master' of gitlab.com:noosfero/noosfero

Showing 174 changed files with 2162 additions and 2196 deletions   Show diff stats
Gemfile
... ... @@ -11,7 +11,6 @@ gem 'will_paginate', '~> 3.0.3'
11 11 gem 'ruby-feedparser', '~> 0.7'
12 12 gem 'daemons', '~> 1.1.5'
13 13 gem 'thin', '~> 1.3.1'
14   -gem 'hpricot', '~> 0.8.6'
15 14 gem 'nokogiri', '~> 1.5.5'
16 15 gem 'rake', :require => false
17 16 gem 'rest-client', '~> 1.6.7'
... ... @@ -41,9 +40,12 @@ group :cucumber do
41 40 gem 'selenium-webdriver', '~> 2.39.0'
42 41 end
43 42  
  43 +# Requires custom dependencies
  44 +eval(File.read('config/Gemfile'), binding) rescue nil
  45 +
44 46 # include gemfiles from enabled plugins
45 47 # plugins in baseplugins/ are not included on purpose. They should not have any
46 48 # dependencies.
47 49 Dir.glob('config/plugins/*/Gemfile').each do |gemfile|
48 50 eval File.read(gemfile)
49 51 -end
  52 +end
50 53 \ No newline at end of file
... ...
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  
... ...
app/controllers/application_controller.rb
... ... @@ -28,6 +28,7 @@ class ApplicationController &lt; ActionController::Base
28 28 unless environment.access_control_allow_methods.blank?
29 29 response.headers["Access-Control-Allow-Methods"] = environment.access_control_allow_methods
30 30 end
  31 + response.headers["Access-Control-Allow-Credentials"] = 'true'
31 32 elsif environment.restrict_to_access_control_origins
32 33 render_access_denied _('Origin not in allowed.')
33 34 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  
... ... @@ -651,8 +647,8 @@ module ApplicationHelper
651 647 ' onfocus="if(this.value==\''+s+'\'){this.value=\'\'} this.form.className=\'focus-in\'"'+
652 648 ' onblur="if(/^\s*$/.test(this.value)){this.value=\''+s+'\'} this.form.className=\'focus-out\'">'+
653 649 '</form>'
654   - else #opt == 'lightbox_link' is default
655   - lightbox_link_to '<span class="icon-menu-search"></span>'+ _('Search'), {
  650 + else
  651 + modal_link_to '<span class="icon-menu-search"></span>'+ _('Search'), {
656 652 :controller => 'search',
657 653 :action => 'popup',
658 654 :category_path => (@category ? @category.explode_path : nil)},
... ... @@ -1050,7 +1046,7 @@ module ApplicationHelper
1050 1046 {s_('contents|Most commented') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_comments'})}}
1051 1047 ]
1052 1048 if logged_in?
1053   - 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})}))
1054 1050 end
1055 1051  
1056 1052 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') +
... ... @@ -1398,16 +1394,16 @@ module ApplicationHelper
1398 1394 end
1399 1395  
1400 1396 def convert_macro(html, source)
1401   - doc = Hpricot(html)
  1397 + doc = Nokogiri::HTML.fragment html
1402 1398 #TODO This way is more efficient but do not support macro inside of
1403 1399 # macro. You must parse them from the inside-out in order to enable
1404 1400 # that.
1405   - doc.search('.macro').each do |macro|
  1401 + doc.css('.macro').each do |macro|
1406 1402 macro_name = macro['data-macro']
1407 1403 result = @plugins.parse_macro(macro_name, macro, source)
1408 1404 macro.inner_html = result.kind_of?(Proc) ? self.instance_exec(&result) : result
1409 1405 end
1410   - doc.html
  1406 + doc.to_html
1411 1407 end
1412 1408  
1413 1409 def default_folder_for_image_upload(profile)
... ...
app/helpers/boxes_helper.rb
... ... @@ -231,7 +231,7 @@ module BoxesHelper
231 231 end
232 232  
233 233 if block.editable?
234   - buttons << colorbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
  234 + buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
235 235 end
236 236  
237 237 if !block.main?
... ... @@ -241,7 +241,7 @@ module BoxesHelper
241 241 end
242 242  
243 243 if block.respond_to?(:help)
244   - 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}")
245 245 end
246 246  
247 247 if block.embedable?
... ...
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/layout_helper.rb
... ... @@ -45,8 +45,6 @@ module LayoutHelper
45 45 standard_stylesheets = [
46 46 'application',
47 47 'search',
48   - 'thickbox',
49   - 'lightbox',
50 48 'colorbox',
51 49 'selectordie',
52 50 'inputosaurus',
... ...
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/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/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  
... ... @@ -707,7 +706,7 @@ class Article &lt; ActiveRecord::Base
707 706 end
708 707  
709 708 def first_paragraph
710   - paragraphs = Hpricot(to_html).search('p')
  709 + paragraphs = Nokogiri::HTML.fragment(to_html).css('p')
711 710 paragraphs.empty? ? '' : paragraphs.first.to_html
712 711 end
713 712  
... ... @@ -729,8 +728,8 @@ class Article &lt; ActiveRecord::Base
729 728  
730 729 def body_images_paths
731 730 require 'uri'
732   - Hpricot(self.body.to_s).search('img[@src]').collect do |i|
733   - (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i.attributes['src'])).to_s : i.attributes['src']
  731 + Nokogiri::HTML.fragment(self.body.to_s).css('img[src]').collect do |i|
  732 + (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i['src'])).to_s : i['src']
734 733 end
735 734 end
736 735  
... ... @@ -767,8 +766,8 @@ class Article &lt; ActiveRecord::Base
767 766 end
768 767  
769 768 def first_image
770   - img = Hpricot(self.lead.to_s).search('img[@src]').first || Hpricot(self.body.to_s).search('img').first
771   - img.nil? ? '' : img.attributes['src']
  769 + img = Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first || Nokogiri::HTML.fragment(self.body.to_s).search('img').first
  770 + img.nil? ? '' : img['src']
772 771 end
773 772  
774 773 delegate :lat, :lng, :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true
... ...
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
... ... @@ -273,6 +273,7 @@ class Environment &lt; ActiveRecord::Base
273 273 settings_items :help_message_to_add_enterprise, :type => String, :default => ''
274 274 settings_items :tip_message_enterprise_activation_question, :type => String, :default => ''
275 275  
  276 + settings_items :currency_iso_unit, :type => String, :default => 'USD'
276 277 settings_items :currency_unit, :type => String, :default => '$'
277 278 settings_items :currency_separator, :type => String, :default => '.'
278 279 settings_items :currency_delimiter, :type => String, :default => ','
... ...
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/person_notifier.rb
... ... @@ -22,12 +22,17 @@ class PersonNotifier
22 22 schedule_next_notification_mail
23 23 end
24 24  
  25 + def notify_from
  26 + @person.last_notification || DateTime.now - @person.notification_time.hours
  27 + end
  28 +
25 29 def notify
26 30 if @person.notification_time && @person.notification_time > 0
27   - from = @person.last_notification || DateTime.now - @person.notification_time.hours
28   - notifications = @person.tracked_notifications.find(:all, :conditions => ["created_at > ?", from])
  31 + notifications = @person.tracked_notifications.find(:all, :conditions => ["created_at > ?", notify_from])
  32 + tasks = Task.to(@person).without_spam.pending.where("created_at > ?", notify_from).order_by('created_at', 'asc')
  33 +
29 34 Noosfero.with_locale @person.environment.default_language do
30   - Mailer::content_summary(@person, notifications).deliver unless notifications.empty?
  35 + Mailer::content_summary(@person, notifications, tasks).deliver unless notifications.empty? && tasks.empty?
31 36 end
32 37 @person.settings[:last_notification] = DateTime.now
33 38 @person.save!
... ... @@ -59,8 +64,12 @@ class PersonNotifier
59 64 end
60 65  
61 66 def failure(job)
62   - person = Person.find(person_id)
63   - person.notifier.dispatch_notification_mail
  67 + begin
  68 + person = Person.find(person_id)
  69 + person.notifier.dispatch_notification_mail
  70 + rescue
  71 + Rails.logger.error "PersonNotifier::NotifyJob: Cannot recover from failure"
  72 + end
64 73 end
65 74  
66 75 end
... ... @@ -73,18 +82,24 @@ class PersonNotifier
73 82 {:theme => nil}
74 83 end
75 84  
76   - def content_summary(person, notifications)
  85 + def content_summary(person, notifications, tasks)
  86 + if person.environment
  87 + ActionMailer::Base.asset_host = person.environment.top_url
  88 + ActionMailer::Base.default_url_options[:host] = person.environment.default_hostname
  89 + end
  90 +
77 91 @current_theme = 'default'
78 92 @profile = person
79 93 @recipient = @profile.nickname || @profile.name
80 94 @notifications = notifications
  95 + @tasks = tasks
81 96 @environment = @profile.environment.name
82 97 @url = @profile.environment.top_url
83 98 mail(
84 99 content_type: "text/html",
85 100 from: "#{@profile.environment.name} <#{@profile.environment.noreply_email}>",
86 101 to: @profile.email,
87   - subject: _("[%s] Network Activity") % [@profile.environment.name]
  102 + subject: _("[%s] Notifications") % [@profile.environment.name]
88 103 )
89 104 end
90 105 end
... ...
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'
... ...
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
... ... @@ -54,7 +54,7 @@ class User &lt; ActiveRecord::Base
54 54  
55 55 user.person = p
56 56 end
57   - if user.environment.enabled?('skip_new_user_email_confirmation')
  57 + if user.environment.enabled?('skip_new_user_email_confirmation')
58 58 if user.environment.enabled?('admin_must_approve_new_users')
59 59 create_moderate_task
60 60 else
... ... @@ -102,6 +102,7 @@ class User &lt; ActiveRecord::Base
102 102 validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?})
103 103 validates_uniqueness_of :login, :email, :case_sensitive => false, :scope => :environment_id
104 104 before_save :encrypt_password
  105 + before_save :normalize_email, if: proc{ |u| u.email.present? }
105 106 validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?})
106 107  
107 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
... ... @@ -114,6 +115,10 @@ class User &lt; ActiveRecord::Base
114 115 u && u.authenticated?(password) ? u : nil
115 116 end
116 117  
  118 + def register_login
  119 + self.update_attribute :last_login_at, Time.now
  120 + end
  121 +
117 122 # Activates the user in the database.
118 123 def activate
119 124 return false unless self.person
... ... @@ -332,6 +337,11 @@ class User &lt; ActiveRecord::Base
332 337 end
333 338  
334 339 protected
  340 +
  341 + def normalize_email
  342 + self.email = self.email.squish.downcase
  343 + end
  344 +
335 345 # before filter
336 346 def encrypt_password
337 347 return if password.blank?
... ... @@ -359,6 +369,6 @@ class User &lt; ActiveRecord::Base
359 369  
360 370 def delay_activation_check
361 371 return if person.is_template?
362   - Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => 72.hours.from_now})
  372 + Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => (NOOSFERO_CONF['hours_until_user_activation_check'] || 72).hours.from_now})
363 373 end
364 374 end
... ...
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/_signup_form.html.erb
... ... @@ -16,7 +16,7 @@
16 16 <input type="hidden" id="signup_time_key" name="signup_time_key" />
17 17 <script type="text/javascript">
18 18 jQuery.ajax({
19   - type: "POST",
  19 + type: "GET",
20 20 url: "<%= url_for :controller=>'account', :action=>'signup_time' %>",
21 21 dataType: 'json',
22 22 success: function(data) {
... ...
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/box_organizer/add_block.html.erb
... ... @@ -42,7 +42,7 @@
42 42  
43 43 <% button_bar do %>
44 44 <%= submit_button(:add, _("Add")) %>
45   - <%= colorbox_close_button(_('Close')) %>
  45 + <%= modal_close_button(_('Close')) %>
46 46 <% end %>
47 47  
48 48 <% end %>
... ...
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/index.html.erb
1 1 <h1><%= _('Editing sideboxes')%></h1>
2 2  
3 3 <% button_bar :class=>'design-menu' do %>
4   - <%= colorbox_button('add', _('Add a block'), { :action => 'add_block' }) %>
  4 + <%= modal_button('add', _('Add a block'), { :action => 'add_block' }) %>
5 5 <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %>
6 6 <% end %>
... ...
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
... ... @@ -28,14 +28,14 @@
28 28 <%= expirable_button @page, :locale, content, url %>
29 29 <% end %>
30 30  
31   - <%= 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) %>
  31 + <%= 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) %>
32 32 <% end %>
33 33  
34 34 <% if @page.accept_uploads? && @page.allow_create?(user) %>
35 35 <%= 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)%>
36 36 <% end %>
37 37  
38   - <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest, @page) %>
  38 + <% if !@page.allow_create?(user) && profile.organization? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest, @page) %>
39 39 <% content = content_tag( 'span', _('Suggest an article') ) %>
40 40 <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}) %>
41 41 <% 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/layouts/_javascript.html.erb
1 1 <%= javascript_include_tag 'jquery-2.1.1.min', 'jquery-migrate-1.2.1', 'jrails', 'rails.js',
2   -'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox',
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   -'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow', 'select-or-die/_src/selectordie',
6   -'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'application.js', 'inputosaurus.js', :cache => 'cache/application' %>
  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' %>
7 10  
8 11 <% language = FastGettext.locale %>
9 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
... ... @@ -18,7 +18,7 @@
18 18 <%= yield :head %>
19 19 <%=
20 20 @plugins.dispatch(:head_ending).map do |content|
21   - 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
22 22 end.join("\n")
23 23 %>
24 24  
... ... @@ -32,7 +32,7 @@
32 32  
33 33 <%=
34 34 @plugins.dispatch(:body_beginning).map do |content|
35   - 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
36 36 end.join("\n")
37 37 %>
38 38  
... ...
app/views/person_notifier/mailer/_comment.html.erb
... ... @@ -19,7 +19,7 @@
19 19 <span style="font-size: 12px;"><%= comment.title %></span><br/>
20 20 <% end %>
21 21 <span style="font-size: 10px;"><%= txt2html comment.body %></span><br/>
22   - <span style="font-size: 8px; color: #444444"><%= time_ago_as_sentence(comment.created_at) %></span>
  22 + <span style="font-size: 8px; color: #929292"><%= time_ago_as_sentence(comment.created_at) %></span>
23 23 <br style="clear: both;" />
24 24  
25 25 <% unless comment.replies.blank? %>
... ...
app/views/person_notifier/mailer/_create_article.html.erb
1   -<table>
2 1 <tr>
3   - <td>
  2 + <td style="width: 11%">
4 3 <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
5 4 </td>
6 5 <td>
7   - <p style="width:550px">
  6 + <p>
8 7 <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span>
9 8 <span style="font-size: 14px;"><%= _("has published on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span>
10   - <span style="font-size: 10px; color: #444444; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  9 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
11 10 </p>
12 11 <p>
13 12 <span style="font-size: 14px;"><%= link_to(activity.params['name'], activity.params['url'], :style => "color: #333; font-weight: bold; text-decoration: none;") %></span>
... ... @@ -24,4 +23,3 @@
24 23 <%= render :partial => 'profile_comments', :locals => { :activity => activity } %>
25 24 </td>
26 25 </tr>
27   -</table>
... ...
app/views/person_notifier/mailer/_default_activity.html.erb
1   -<table>
2 1 <tr>
3   - <td>
  2 + <td style="width: 11%">
4 3 <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
5 4 </td>
6 5 <td>
7   - <p style="width:550px">
  6 + <p>
8 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
9   - <span style="font-size: 10px; color: #444444; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
10 9 </p>
11 10 </td>
12 11 </tr>
... ... @@ -16,4 +15,3 @@
16 15 <%= render :partial => 'profile_comments', :locals => { :activity => activity } %>
17 16 </td>
18 17 </tr>
19   -</table>
... ...
app/views/person_notifier/mailer/_task.html.erb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +<div style="border-bottom:1px solid #e2e2e2;padding:15px 0;width:600px">
  2 + <table style="width:100%;">
  3 + <tr>
  4 + <td style="width: 11%">
  5 + <%= profile_image(task.requestor, :minor) %>
  6 + </td>
  7 + <td>
  8 + <div>
  9 + <strong><%= link_to task.title, url_for(:controller => 'tasks', :profile => @profile.identifier, :action => 'index', :only_path => false) %></strong>
  10 + </div>
  11 + <div style="font-size: 14px">
  12 + <span style="font-size: 14px">
  13 + <%= task_information(task) %>
  14 + </span>
  15 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(task.created_at) %></span>
  16 + </div>
  17 + </td>
  18 + </tr>
  19 + </table>
  20 +</div>
... ...
app/views/person_notifier/mailer/_upload_image.html.erb
1   -<table>
2 1 <tr>
3   - <td>
  2 + <td style="width: 11%">
4 3 <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
5 4 </td>
6 5 <td>
7   - <p style="width:550px">
  6 + <p>
8 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
9   - <span style="font-size: 10px; color: #444444; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
10 9 </p>
11 10 </td>
12 11 </tr>
13   -</table>
14 12 <div title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-newgallery'></div>
15 13 <br/>
... ...
app/views/person_notifier/mailer/content_summary.html.erb
1   -<h3><%= _("%s's network activity") % @profile.name %></h3>
2   -<br/>
3   -<div>
4   -<% @notifications.each do |activity| %>
5   - <div style="border-left:none;border-right:none;border-top:1px solid #ccc;border-bottom:none;padding:10px;width:600px">
6   - <%= render :partial => activity.verb, :locals => { :activity => activity } rescue "cannot render notification for #{activity.verb}" %>
7   - </div>
8   -<% end %>
9   -</div>
  1 +<div style="background-color: #EEEEEE">
  2 + <table style="width: 100%;"><tbody><tr><td align="center">
  3 + <div style="display: table; background-color: white; margin: 26px 0;">
  4 + <div style="padding: 25px 20px 20px 20px;text-align: left;">
  5 + <%= link_to @url, :style => "text-decoration: none;" do %>
  6 + <span style="font-weight:bold;font-size: 28px;margin: 0;color: white;background-color: #AAAAAA;padding: 5px;"><%= @environment %></span>
  7 + <% end %>
  8 + <span style="font-weight:bold;color: #333;font-size:19px;margin-left: 8px;"><%= _("%s's Notifications") % @profile.name %></h3>
  9 + </div>
  10 + <div style="margin: 0 20px 20px 20px;border-top:1px solid #e2e2e2;">
  11 + <% if @tasks.present? %>
  12 + <div style="border-top: 1px solid #e2e2e2;">
  13 + <div style="border-bottom: 1px solid #CBCBCB;padding-top: 15px;font-weight: bold;text-align: right;color: #7c7c7c;float: right;min-width: 140px;">
  14 + <%= _('Tasks') %>
  15 + </div>
  16 + <%= render :partial => 'task', :collection => @tasks %>
  17 + </div>
  18 + <% end %>
  19 +
  20 + <% if @notifications.present? %>
  21 + <div style="border-top: 1px solid #e2e2e2;">
  22 + <div style="border-bottom: 1px solid #CBCBCB;padding-top: 15px;font-weight: bold;text-align: right;color: #7c7c7c;float: right;min-width: 140px;">
  23 + <%= _('Network Activity') %>
  24 + </div>
  25 + <% @notifications.each do |activity| %>
  26 + <div style="border-bottom:1px solid #e2e2e2;padding:15px 0;width:600px">
  27 + <table style="width:100%;">
  28 + <%= render :partial => activity.verb, :locals => { :activity => activity } rescue "cannot render notification for #{activity.verb}" %>
  29 + </table>
  30 + </div>
  31 + <% end %>
  32 + </div>
  33 + <% end %>
10 34  
11   -<div style="color:#444444;font-size:11px;">
12   -<p><%= _("Greetings,") %></p>
13   -<br/>
14   -<p>--</p>
15   -<p><%= _('%s team.') % @environment %></p>
16   -<p><%= url_for @url %></p>
  35 + <div style="color:#444444;font-size:11px;margin-bottom: 20px;">
  36 + <p style="margin:0"><%= _("Greetings,") %></p>
  37 + <p style="margin:0"><%= _('%s team.') % @environment %></p>
  38 + <p style="margin:0"><%= link_to @url, url_for(@url) %></p>
  39 + </div>
  40 + </div>
  41 + </td></tr></tbody></table>
17 42 </div>
18   -<br/>
... ...
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_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/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 %>
... ...
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/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/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
... ... @@ -733,6 +733,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
733 733 t.string "activation_code", :limit => 40
734 734 t.datetime "activated_at"
735 735 t.string "return_to"
  736 + t.datetime "last_login_at"
736 737 end
737 738  
738 739 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,
... ...
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/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
... ...
lib/noosfero/plugin/macro.rb
... ... @@ -35,7 +35,7 @@ class Noosfero::Plugin::Macro
35 35 def attributes(macro)
36 36 macro.attributes.to_hash.
37 37 select {|key, value| key[0..10] == 'data-macro-'}.
38   - inject({}){|result, a| result.merge({a[0][11..-1] => a[1]})}.
  38 + inject({}){|result, a| result.merge({a[0][11..-1] => a[1].to_s})}.
39 39 with_indifferent_access
40 40 end
41 41  
... ...
lib/noosfero/plugin/routes.rb
1 1 plugins_root = Rails.env.test? ? 'plugins' : '{baseplugins,config/plugins}'
  2 +prefixes_by_folder = {public: 'plugin',
  3 + profile: 'profile/:profile/plugin',
  4 + myprofile: 'myprofile/:profile/plugin',
  5 + admin: 'admin/plugin'}
2 6  
3 7 Dir.glob(Rails.root.join(plugins_root, '*', 'controllers')) do |controllers_dir|
4   - prefixes_by_folder = {'public' => 'plugin',
5   - 'profile' => 'profile/:profile/plugin',
6   - 'myprofile' => 'myprofile/:profile/plugin',
7   - 'admin' => 'admin/plugin'}
  8 + plugin_name = File.basename(File.dirname(controllers_dir))
8 9  
9 10 controllers_by_folder = prefixes_by_folder.keys.inject({}) do |hash, folder|
10   - hash.merge!({folder => Dir.glob(File.join(controllers_dir, folder, '*')).map {|full_names| File.basename(full_names).gsub(/_controller.rb$/,'')}})
  11 + path = "#{controllers_dir}/#{folder}/"
  12 + hash[folder] = Dir.glob("#{path}{*.rb,#{plugin_name}_plugin/*.rb}").map do |filename|
  13 + filename.gsub(path, '').gsub(/_controller.rb$/, '')
  14 + end
  15 + hash
11 16 end
12 17  
13   - plugin_name = File.basename(File.dirname(controllers_dir))
14   -
15 18 controllers_by_folder.each do |folder, controllers|
16 19 controllers.each do |controller|
17 20 controller_name = controller.gsub("#{plugin_name}_plugin_",'')
... ...
lib/noosfero/plugin/spammable.rb
1   -Rails.configuration.to_prepare do
  1 +ActionDispatch::Reloader.to_prepare do
2 2 Spammable.module_eval do
3 3 def marked_as_spam
4 4 plugins.dispatch(:marked_as_spam, self)
... ...
lib/tasks/multitenancy.rake
1 1 namespace :multitenancy do
2 2  
3   - task :create do
  3 + task :create => :environment do
4 4 db_envs = ActiveRecord::Base.configurations.keys.select{ |k| k.match(/_development$|_production$|_test$/) }
5 5 cd Rails.root.join('config', 'environments'), :verbose => true
6   - file_envs = Dir.glob "{*_development.rb,*_prodution.rb,*_test.rb}"
  6 + file_envs = Dir.glob "{*_development.rb,*_production.rb,*_test.rb}"
7 7 (db_envs.map{ |e| e + '.rb' } - file_envs).each { |env| ln_s env.split('_').last, env }
8 8 end
9 9  
10   - task :remove do
  10 + task :remove => :environment do
11 11 db_envs = ActiveRecord::Base.configurations.keys.select{ |k| k.match(/_development$|_production$|_test$/) }
12 12 cd Rails.root.join('config', 'environments'), :verbose => true
13   - file_envs = Dir.glob "{*_development.rb,*_prodution.rb,*_test.rb}"
  13 + file_envs = Dir.glob "{*_development.rb,*_production.rb,*_test.rb}"
14 14 (file_envs - db_envs.map{ |e| e + '.rb' }).each { |env| safe_unlink env }
15 15 end
16 16  
... ...
lib/tasks/plugins_tests.rake
... ... @@ -106,7 +106,7 @@ def run_test(name, files)
106 106 files = Array(files)
107 107 plugin = filename2plugin(files.first)
108 108 if name == :cucumber || name == :selenium
109   - run_cucumber task2_profile(name, plugin), files
  109 + run_cucumber task2profile(name, plugin), files
110 110 else
111 111 run_testrb files
112 112 end
... ... @@ -134,7 +134,11 @@ end
134 134  
135 135 def run_tests(name, plugins, run=:all)
136 136 plugins = Array(plugins)
137   - glob = "plugins/{#{plugins.join(',')}}/test/#{task2folder(name)}/**/*.#{task2ext(name)}"
  137 + if name == :cucumber || name == :selenium
  138 + glob = "plugins/{#{plugins.join(',')}}/#{task2folder(name)}/**/*.#{task2ext(name)}"
  139 + else
  140 + glob = "plugins/{#{plugins.join(',')}}/test/#{task2folder(name)}/**/*.#{task2ext(name)}"
  141 + end
138 142 files = Dir.glob(glob)
139 143 if files.empty?
140 144 puts "I: no tests to run #{name}"
... ...
plugins/bsc/public/jquery.ui.spinner
... ... @@ -1 +0,0 @@
1   -Subproject commit bd879003043b4a93b78cbd4a582b6e0650900bcb
plugins/comment_classification/features/step_definitions/plugin_steps.rb
1 1 Given /^CommentClassificationPlugin is enabled$/ do
2   - step %{I am logged in as admin}
3   - step %{I am on the environment control panel}
4   - step %{I follow "Plugins"}
5   - step %{I check "Comment Classification"}
6   - step %{I press "Save changes"}
  2 + steps %Q{
  3 + Given I am logged in as admin
  4 + Given I am on the environment control panel
  5 + Given I follow "Plugins"
  6 + Given I check "Comment Classification"
  7 + Given I press "Save changes"
  8 + }
  9 +
7 10 Environment.default.enabled_plugins.should include("CommentClassificationPlugin")
8 11 end
9 12  
... ...
plugins/comment_classification/lib/ext/comment.rb
1 1 require_dependency 'comment'
2   -require 'comment_classification_plugin.rb'
3   -require 'comment_classification_plugin/label.rb'
4 2  
5 3 class Comment
6 4  
... ...
plugins/comment_group/lib/ext/article.rb
... ... @@ -9,7 +9,7 @@ class Article
9 9 def not_empty_group_comments_removed
10 10 if body && body_changed?
11 11 groups_with_comments = Comment.find(:all, :select => 'distinct group_id', :conditions => {:source_id => self.id}).map(&:group_id).compact
12   - groups = Hpricot(body.to_s).search('.macro').collect{|element| element['data-macro-group_id'].to_i}
  12 + groups = Nokogiri::HTML.fragment(body.to_s).css('.macro').collect{|element| element['data-macro-group_id'].to_i}
13 13 errors[:base] << (N_('Not empty group comment cannot be removed')) unless (groups_with_comments-groups).empty?
14 14 end
15 15 end
... ...
plugins/community_track/lib/community_track_plugin/track.rb
... ... @@ -59,7 +59,7 @@ class CommunityTrackPlugin::Track &lt; Folder
59 59  
60 60 def first_paragraph
61 61 return '' if body.blank?
62   - paragraphs = Hpricot(body).search('p')
  62 + paragraphs = Nokogiri::HTML.fragment(body).css('p')
63 63 paragraphs.empty? ? '' : paragraphs.first.to_html
64 64 end
65 65  
... ...
plugins/custom_forms/public/style.css
... ... @@ -25,7 +25,7 @@
25 25 .edit-information {
26 26 display: none;
27 27 }
28   -#colorbox .edit-information {
  28 +.modal .edit-information {
29 29 display: block;
30 30 }
31 31  
... ...
plugins/custom_forms/views/custom_forms_plugin_myprofile/_edit_select.html.erb
... ... @@ -26,7 +26,7 @@
26 26 <%= labelled_radio_button 'Multiple Select', "fields[#{counter}][kind]", 'multiple_select', field.multiple && field.list %><br />
27 27  
28 28 <% button_bar do %>
29   - <%= button :ok, c_('Ok'), '#', :class => 'colorbox-ok-button', :div_id => elem_id %>
  29 + <%= button :ok, _('Ok'), '#', :div_id => elem_id %>
30 30 <% end %>
31 31 </div>
32 32  
... ...
plugins/oauth_client/Gemfile 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +gem 'omniauth', '~> 1.2.2'
  2 +gem 'omniauth-facebook', '~> 2.0.0'
  3 +gem "omniauth-google-oauth2", '~> 0.2.6'
... ...
plugins/oauth_client/README.md 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +README - Oauth Client Plugin
  2 +================================
  3 +
  4 +OauthClient is a plugin which allow users to login/signup to noosfero with some oauth providers (for now, google, facebook and noosfero itself).
  5 +
  6 +Install
  7 +=======
  8 +
  9 +Enable Plugin
  10 +-------------
  11 +
  12 +cd <your_noosfero_dir>
  13 +./script/noosfero-plugins enable oauth_client
  14 +
  15 +Active Plugin
  16 +-------------
  17 +
  18 +As a Noosfero administrator user, go to administrator panel:
  19 +
  20 +- Click on "Enable/disable plugins" option
  21 +- Click on "Oauth Client Plugin" check-box
  22 +
  23 +Provider Settings
  24 +=================
  25 +
  26 +Goggle
  27 +------
  28 +
  29 +[Create Google+ application](https://developers.google.com/+/web/signin/javascript-flow)
  30 +
  31 +Facebook
  32 +--------
  33 +
  34 +[Create Facebook application](https://developers.facebook.com/docs/facebook-login/v2.1)
  35 +
  36 +Varnish Settings
  37 +================
  38 +If varnish has been used in your stack, you've to bypass the cache for signup page and prevent cookies to be removed when calling the oauth_client plugin callback. E.g.:
  39 +
  40 +```
  41 +if (req.url !~ "^/account/*" && req.url !~ "^/plugin/oauth_provider/*" && req.url !~ "^/plugin/oauth_client/*" && req.http.cookie !~ "_noosfero_.*") {
  42 + unset req.http.cookie;
  43 + return(lookup);
  44 +}
  45 +```
  46 +
  47 +Using Oauth Provider Plugin
  48 +===========================
  49 +The oauth_provider plugin may be used as a provider in the same noosfero installation that hosts your oauth_client plugin (this is usefull in a multi environment setup).
  50 +
  51 +However, you've to use a distinct set of thin processes to handle the authorization requests (to avoid deadlock).
  52 +
  53 +Apache settings example:
  54 +```
  55 +RewriteRule ^/oauth_provider/oauth/(authorize|token).*$ balancer://noosfero-oauth-provider%{REQUEST_URI} [P,QSA,L]
  56 +```
  57 +
  58 +
  59 +Development
  60 +===========
  61 +
  62 +Running OauthClient tests
  63 +--------------------
  64 +
  65 +$ rake test:noosfero_plugins:oauth_client
  66 +
  67 +License
  68 +=======
  69 +
  70 +Copyright (c) The Author developers.
  71 +
  72 +See Noosfero license.
... ...
plugins/oauth_client/controllers/oauth_client_plugin_admin_controller.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +class OauthClientPluginAdminController < AdminController
  2 +
  3 + def index
  4 + end
  5 +
  6 + def new
  7 + @provider = environment.oauth_providers.new
  8 + render :file => 'oauth_client_plugin_admin/edit'
  9 + end
  10 +
  11 + def remove
  12 + environment.oauth_providers.find(params[:id]).destroy
  13 + redirect_to :action => 'index'
  14 + end
  15 +
  16 + def edit
  17 + @provider = params[:id] ? environment.oauth_providers.find(params[:id]) : environment.oauth_providers.new
  18 + if request.post?
  19 + if @provider.update_attributes(params['oauth_client_plugin_provider'])
  20 + session[:notice] = _('Saved!')
  21 + else
  22 + session[:notice] = _('Error!')
  23 + end
  24 + end
  25 + end
  26 +
  27 +end
... ...
plugins/oauth_client/controllers/public/oauth_client_plugin_public_controller.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +class OauthClientPluginPublicController < PublicController
  2 +
  3 + skip_before_filter :login_required
  4 +
  5 + def callback
  6 + auth = request.env["omniauth.auth"]
  7 + user = environment.users.find_by_email(auth.info.email)
  8 + user ? login(user) : signup(auth)
  9 + end
  10 +
  11 + def failure
  12 + session[:notice] = _('Failed to login')
  13 + redirect_to root_url
  14 + end
  15 +
  16 + def destroy
  17 + session[:user] = nil
  18 + redirect_to root_url
  19 + end
  20 +
  21 + protected
  22 +
  23 + def login(user)
  24 + provider = OauthClientPlugin::Provider.find(session[:provider_id])
  25 + user_provider = user.oauth_user_providers.find_by_provider_id(provider.id)
  26 + unless user_provider
  27 + user_provider = user.oauth_user_providers.create(:user => user, :provider => provider, :enabled => true)
  28 + end
  29 + if user_provider.enabled? && provider.enabled?
  30 + session[:user] = user.id
  31 + else
  32 + session[:notice] = _("Can't login with #{provider.name}")
  33 + end
  34 +
  35 + redirect_to :controller => :account, :action => :login
  36 + end
  37 +
  38 + def signup(auth)
  39 + login = auth.info.email.split('@').first
  40 + session[:oauth_data] = auth
  41 + name = auth.info.name
  42 + name ||= auth.extra && auth.extra.raw_info ? auth.extra.raw_info.name : ''
  43 + redirect_to :controller => :account, :action => :signup, :user => {:login => login, :email => auth.info.email}, :profile_data => {:name => name}
  44 + end
  45 +
  46 +end
... ...
plugins/oauth_client/db/migrate/20141010135314_create_oauth_client_plugin_provider.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class CreateOauthClientPluginProvider < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + create_table :oauth_client_plugin_providers do |t|
  5 + t.integer :environment_id
  6 + t.string :strategy
  7 + t.string :name
  8 + t.text :options
  9 + t.boolean :enabled
  10 + t.integer :image_id
  11 +
  12 + t.timestamps
  13 + end
  14 + end
  15 +
  16 + def self.down
  17 + drop_table :oauth_client_plugin_providers
  18 + end
  19 +end
... ...
plugins/oauth_client/db/migrate/20141014162710_create_oauth_client_user_providers.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class CreateOauthClientUserProviders < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :oauth_client_plugin_user_providers do |t|
  4 + t.references :user
  5 + t.references :provider
  6 + t.boolean :enabled
  7 + t.timestamps
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + drop_table :oauth_client_plugin_user_providers
  13 + end
  14 +end
... ...
plugins/oauth_client/lib/ext/environment.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +require_dependency 'environment'
  2 +
  3 +class Environment
  4 +
  5 + has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider'
  6 +
  7 +end
... ...
plugins/oauth_client/lib/ext/user.rb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +require_dependency 'user'
  2 +
  3 +class User
  4 +
  5 + has_many :oauth_user_providers, :class_name => 'OauthClientPlugin::UserProvider'
  6 + has_many :oauth_providers, :through => :oauth_user_providers, :source => :provider
  7 +
  8 + def password_required_with_oauth?
  9 + password_required_without_oauth? && oauth_providers.empty?
  10 + end
  11 +
  12 + alias_method_chain :password_required?, :oauth
  13 +
  14 + after_create :activate_oauth_user
  15 +
  16 + def activate_oauth_user
  17 + unless oauth_providers.empty?
  18 + activate
  19 + oauth_providers.each do |provider|
  20 + OauthClientPlugin::UserProvider.create!(:user => self, :provider => provider, :enabled => true)
  21 + end
  22 + end
  23 + end
  24 +
  25 + def make_activation_code_with_oauth
  26 + oauth_providers.blank? ? make_activation_code_without_oauth : nil
  27 + end
  28 +
  29 + alias_method_chain :make_activation_code, :oauth
  30 +
  31 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin.rb 0 → 100644
... ... @@ -0,0 +1,95 @@
  1 +require 'omniauth/strategies/noosfero_oauth2'
  2 +
  3 +class OauthClientPlugin < Noosfero::Plugin
  4 +
  5 + def self.plugin_name
  6 + "Oauth Client Plugin"
  7 + end
  8 +
  9 + def self.plugin_description
  10 + _("Login with Oauth.")
  11 + end
  12 +
  13 + def login_extra_contents
  14 + plugin = self
  15 + proc do
  16 + render :partial => 'auth/oauth_login', :locals => {:providers => environment.oauth_providers.enabled}
  17 + end
  18 + end
  19 +
  20 + def signup_extra_contents
  21 + plugin = self
  22 +
  23 + proc do
  24 + if plugin.context.session[:oauth_data].present?
  25 + render :partial => 'account/oauth_signup'
  26 + else
  27 + ''
  28 + end
  29 + end
  30 + end
  31 +
  32 + PROVIDERS = {
  33 + :facebook => {
  34 + :name => 'Facebook'
  35 + },
  36 + :google_oauth2 => {
  37 + :name => 'Google'
  38 + },
  39 + :noosfero_oauth2 => {
  40 + :name => 'Noosfero'
  41 + }
  42 + }
  43 +
  44 + def stylesheet?
  45 + true
  46 + end
  47 +
  48 + OmniAuth.config.on_failure = OauthClientPluginPublicController.action(:failure)
  49 +
  50 + Rails.application.config.middleware.use OmniAuth::Builder do
  51 + PROVIDERS.each do |provider, options|
  52 + setup = lambda { |env|
  53 + request = Rack::Request.new(env)
  54 + strategy = env['omniauth.strategy']
  55 +
  56 + Noosfero::MultiTenancy.setup!(request.host)
  57 + domain = Domain.find_by_name(request.host)
  58 + environment = domain.environment rescue Environment.default
  59 +
  60 + provider_id = request.params['id']
  61 + provider_id ||= request.session['omniauth.params']['id'] if request.session['omniauth.params']
  62 + provider = environment.oauth_providers.find(provider_id)
  63 + strategy.options.merge!(provider.options.symbolize_keys)
  64 +
  65 + request.session[:provider_id] = provider_id
  66 + }
  67 +
  68 + provider provider, :setup => setup,
  69 + :path_prefix => '/plugin/oauth_client',
  70 + :callback_path => "/plugin/oauth_client/public/callback/#{provider}",
  71 + :client_options => { :connection_opts => { :proxy => ENV["OAUTH_HTTP_PROXY"] } }
  72 + end
  73 +
  74 + unless Rails.env.production?
  75 + provider :developer, :path_prefix => "/plugin/oauth_client", :callback_path => "/plugin/oauth_client/public/callback/developer"
  76 + end
  77 + end
  78 +
  79 + def account_controller_filters
  80 + {
  81 + :type => 'before_filter', :method_name => 'signup',
  82 + :block => proc {
  83 + auth = session[:oauth_data]
  84 +
  85 + if auth.present? && params[:user].present?
  86 + params[:user][:oauth_providers] = [OauthClientPlugin::Provider.find(session[:provider_id])]
  87 + if request.post? && auth.info.email != params[:user][:email]
  88 + raise "Wrong email for oauth signup"
  89 + end
  90 + end
  91 + }
  92 + }
  93 + end
  94 +
  95 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin/provider.rb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +class OauthClientPlugin::Provider < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :environment
  4 +
  5 + validates_presence_of :name, :strategy
  6 +
  7 + acts_as_having_image
  8 + acts_as_having_settings :field => :options
  9 +
  10 + settings_items :client_id, :type => :string
  11 + settings_items :client_secret, :type => :string
  12 + settings_items :client_options, :type => Hash
  13 +
  14 + attr_accessible :name, :environment, :strategy, :client_id, :client_secret, :enabled, :client_options, :image_builder
  15 +
  16 + scope :enabled, :conditions => {:enabled => true}
  17 +
  18 + acts_as_having_image
  19 +
  20 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin/user_provider.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +class OauthClientPlugin::UserProvider < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :user, :class_name => 'User'
  4 + belongs_to :provider, :class_name => 'OauthClientPlugin::Provider'
  5 +
  6 + set_table_name :oauth_client_plugin_user_providers
  7 +
  8 + attr_accessible :user, :provider, :enabled
  9 +
  10 +end
... ...
plugins/oauth_client/lib/omniauth/strategies/noosfero_oauth2.rb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +require 'omniauth/strategies/oauth2'
  2 +
  3 +module OmniAuth
  4 + module Strategies
  5 + class NoosferoOauth2 < OmniAuth::Strategies::OAuth2
  6 + option :name, :noosfero_oauth2
  7 + option :client_options, {
  8 + :authorize_url => '/oauth_provider/oauth/authorize',
  9 + :token_url => '/oauth_provider/oauth/token'
  10 + }
  11 +
  12 + uid { raw_info["id"] }
  13 +
  14 + info do
  15 + {
  16 + :email => raw_info["email"]
  17 + }
  18 + end
  19 +
  20 + def raw_info
  21 + #FIXME access the noosfero api (coming soon)
  22 + @raw_info ||= access_token.get('/plugin/oauth_provider/public/me').parsed
  23 + end
  24 + end
  25 + end
  26 +end
... ...
plugins/oauth_client/public/style.css 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +.oauth-login .provider a {
  2 + min-width: 20px;
  3 + min-height: 20px;
  4 + background-size: 20px;
  5 + display: inline-block;
  6 + text-decoration: none;
  7 + background-repeat: no-repeat;
  8 + line-height: 20px;
  9 +}
  10 +.oauth-login .provider a img {
  11 + max-width: 40px;
  12 +}
  13 +.oauth-login .provider a:hover {
  14 + opacity: 0.7;
  15 +}
  16 +.oauth-login .provider .developer {
  17 + display: none;
  18 +}
... ...
plugins/oauth_client/test/functional/oauth_client_plugin_public_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,80 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class OauthClientPluginPublicControllerTest < ActionController::TestCase
  4 +
  5 + def setup
  6 + @auth = mock
  7 + @auth.stubs(:info).returns(mock)
  8 + request.env["omniauth.auth"] = @auth
  9 + @environment = Environment.default
  10 + @provider = OauthClientPlugin::Provider.create!(:name => 'provider', :strategy => 'provider', :enabled => true)
  11 + end
  12 + attr_reader :auth, :environment, :provider
  13 +
  14 + should 'redirect to signup when user is not found' do
  15 + auth.info.stubs(:email).returns("xyz123@noosfero.org")
  16 + auth.info.stubs(:name).returns('xyz123')
  17 + session[:provider_id] = provider.id
  18 +
  19 + get :callback
  20 + assert_match /.*\/account\/signup/, @response.redirect_url
  21 + end
  22 +
  23 + should 'redirect to login when user is found' do
  24 + user = fast_create(User, :environment_id => environment.id)
  25 + auth.info.stubs(:email).returns(user.email)
  26 + auth.info.stubs(:name).returns(user.name)
  27 + session[:provider_id] = provider.id
  28 +
  29 + get :callback
  30 + assert_redirected_to :controller => :account, :action => :login
  31 + assert_equal user.id, session[:user]
  32 + end
  33 +
  34 + should 'do not login when the provider is disabled' do
  35 + user = fast_create(User, :environment_id => environment.id)
  36 + auth.info.stubs(:email).returns(user.email)
  37 + auth.info.stubs(:name).returns(user.name)
  38 + session[:provider_id] = provider.id
  39 + provider.update_attribute(:enabled, false)
  40 +
  41 + get :callback
  42 + assert_redirected_to :controller => :account, :action => :login
  43 + assert_equal nil, session[:user]
  44 + end
  45 +
  46 + should 'do not login when the provider is disabled for a user' do
  47 + user = fast_create(User, :environment_id => environment.id)
  48 + auth.info.stubs(:email).returns(user.email)
  49 + auth.info.stubs(:name).returns(user.name)
  50 + session[:provider_id] = provider.id
  51 + user.oauth_user_providers.create(:user => user, :provider => provider, :enabled => false)
  52 +
  53 + get :callback
  54 + assert_redirected_to :controller => :account, :action => :login
  55 + assert_equal nil, session[:user]
  56 + end
  57 +
  58 + should 'save provider when an user login with it' do
  59 + user = fast_create(User, :environment_id => environment.id)
  60 + auth.info.stubs(:email).returns(user.email)
  61 + auth.info.stubs(:name).returns(user.name)
  62 + session[:provider_id] = provider.id
  63 +
  64 + get :callback
  65 + assert_equal [provider], user.oauth_providers
  66 + end
  67 +
  68 + should 'do not duplicate relations between an user and a provider when the same provider was used again in a login' do
  69 + user = fast_create(User, :environment_id => environment.id)
  70 + auth.info.stubs(:email).returns(user.email)
  71 + auth.info.stubs(:name).returns(user.name)
  72 + session[:provider_id] = provider.id
  73 +
  74 + get :callback
  75 + assert_no_difference 'user.oauth_user_providers.count' do
  76 + 3.times { get :callback }
  77 + end
  78 + end
  79 +
  80 +end
... ...
plugins/oauth_client/test/test_helper.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
... ...
plugins/oauth_client/test/unit/environment_test.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class UserTest < ActiveSupport::TestCase
  4 +
  5 + should 'be able to add oauth providers in a environment' do
  6 + env = fast_create(Environment)
  7 + env.oauth_providers << OauthClientPlugin::Provider.new(:name => 'test', :strategy => 'test')
  8 + end
  9 +
  10 +end
... ...
plugins/oauth_client/test/unit/oauth_client_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,86 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class OauthClientPluginTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @plugin = OauthClientPlugin.new(self)
  7 + @params = {}
  8 + @plugin.stubs(:context).returns(self)
  9 + @environment = Environment.default
  10 + @session = {}
  11 + @request = mock
  12 + @provider = OauthClientPlugin::Provider.create!(:name => 'name', :strategy => 'strategy')
  13 + end
  14 +
  15 + attr_reader :params, :plugin, :environment, :session, :request, :provider
  16 +
  17 + should 'has extra contents for login' do
  18 + assert plugin.login_extra_contents
  19 + end
  20 +
  21 + should 'has no signup extra contents if no provider was enabled' do
  22 + assert_equal '', instance_eval(&plugin.signup_extra_contents)
  23 + end
  24 +
  25 + should 'has signup extra contents if oauth_data exists in session' do
  26 + session[:oauth_data] = {:oauth => 'test'}
  27 + expects(:render).with(:partial => 'account/oauth_signup').once
  28 + instance_eval(&plugin.signup_extra_contents)
  29 + end
  30 +
  31 + should 'define before filter for account controller' do
  32 + assert plugin.account_controller_filters
  33 + end
  34 +
  35 + should 'raise error if oauth email was changed' do
  36 + request.expects(:post?).returns(true)
  37 +
  38 + oauth_data = mock
  39 + info = mock
  40 + oauth_data.stubs(:info).returns(info)
  41 + oauth_data.stubs(:uid).returns('uid')
  42 + oauth_data.stubs(:provider).returns('provider')
  43 + info.stubs(:email).returns('test@example.com')
  44 + session[:oauth_data] = oauth_data
  45 + session[:provider_id] = provider.id
  46 +
  47 + params[:user] = {:email => 'test2@example.com'}
  48 + assert_raises RuntimeError do
  49 + instance_eval(&plugin.account_controller_filters[:block])
  50 + end
  51 + end
  52 +
  53 + should 'do not raise error if oauth email was not changed' do
  54 + request.expects(:post?).returns(true)
  55 +
  56 + oauth_data = mock
  57 + info = mock
  58 + oauth_data.stubs(:info).returns(info)
  59 + oauth_data.stubs(:uid).returns('uid')
  60 + oauth_data.stubs(:provider).returns('provider')
  61 + info.stubs(:email).returns('test@example.com')
  62 + session[:oauth_data] = oauth_data
  63 + session[:provider_id] = provider.id
  64 +
  65 + params[:user] = {:email => 'test@example.com'}
  66 + instance_eval(&plugin.account_controller_filters[:block])
  67 + end
  68 +
  69 + should 'do not raise error if oauth session is not set' do
  70 + instance_eval(&plugin.account_controller_filters[:block])
  71 + end
  72 +
  73 + should 'do not raise error if it is not a post' do
  74 + request.expects(:post?).returns(false)
  75 + params[:user] = {:email => 'test2@example.com'}
  76 +
  77 + oauth_data = mock
  78 + oauth_data.stubs(:uid).returns('uid')
  79 + oauth_data.stubs(:provider).returns('provider')
  80 + session[:provider_id] = provider.id
  81 +
  82 + session[:oauth_data] = oauth_data
  83 + instance_eval(&plugin.account_controller_filters[:block])
  84 + end
  85 +
  86 +end
... ...
plugins/oauth_client/test/unit/user_test.rb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class UserTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @provider = OauthClientPlugin::Provider.create!(:name => 'name', :strategy => 'strategy')
  7 + end
  8 + attr_reader :provider
  9 +
  10 + should 'password is not required if there is a oauth provider' do
  11 + User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  12 + end
  13 +
  14 + should 'password is required if there is a oauth provider' do
  15 + user = User.new(:email => 'testoauth@example.com', :login => 'testoauth')
  16 + user.save
  17 + assert user.errors[:password].present?
  18 + end
  19 +
  20 + should 'activate user when created with oauth' do
  21 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  22 + assert user.activated?
  23 + end
  24 +
  25 + should 'not activate user when created without oauth' do
  26 + user = fast_create(User)
  27 + assert !user.activated?
  28 + end
  29 +
  30 + should 'not make activation code when created with oauth' do
  31 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  32 + assert !user.activation_code
  33 + end
  34 +
  35 + should 'make activation code when created without oauth' do
  36 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :password => 'test', :password_confirmation => 'test')
  37 + assert user.activation_code
  38 + end
  39 +
  40 +end
... ...
plugins/oauth_client/views/account/_oauth_signup.html.erb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<%= hidden_field_tag 'return_to', '/' %>
  2 +
  3 +<style>
  4 + #signup-password, #signup-password-confirmation, #signup-email {
  5 + display: none;
  6 + }
  7 +</style>
  8 +
  9 +<div id='signup-email-readonly'>
  10 + <%= labelled_form_field(_('Email'), text_field(:user, :email, :class => "disabled", :readonly => true)) %>
  11 +</div>
... ...
plugins/oauth_client/views/auth/_oauth_login.html.erb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<div class="oauth-login">
  2 + <% unless providers.empty? %>
  3 + <%= _('Login with:') %>
  4 + <% end %>
  5 + <% providers.each do |provider| %>
  6 + <span class="provider">
  7 + <%= link_to provider.image ? image_tag(provider.image.public_filename) : provider.name, "/plugin/oauth_client/#{provider.strategy}?id=#{provider.id}", :class => provider.strategy, :title => provider.name %>
  8 + </span>
  9 + <% end %>
  10 +
  11 + <span class="provider">
  12 + <% unless Rails.env.production? %>
  13 + <%= link_to _('Developer Login'), "/plugin/oauth_client/developer", :class => 'developer' %>
  14 + <% end %>
  15 + </span>
  16 +</div>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/_noosfero_oauth2.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%= f.fields_for :client_options, OpenStruct.new(provider.options[:client_options]) do |c| %>
  2 + <div class="client-url">
  3 + <%= labelled_form_field _('Client Url'), c.text_field(:site) %>
  4 + </div>
  5 +<% end %>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/edit.html.erb 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +<h1><%= _('Oauth Client Settings') %></h1>
  2 +<h3><%= _('Edit Provider') %></h3>
  3 +
  4 +<%= form_for @provider, :url => {:action => 'edit'}, :method => 'post' do |f| %>
  5 +
  6 + <div class="enabled">
  7 + <%= labelled_form_field f.check_box(:enabled) + _('Enabled'), '' %>
  8 + </div>
  9 +
  10 + <div class="name">
  11 + <%= labelled_form_field _('Name'), f.text_field(:name) %>
  12 + </div>
  13 +
  14 + <div class="strategy">
  15 + <%= labelled_form_field _('Strategy'), f.select(:strategy, OauthClientPlugin::PROVIDERS) %>
  16 + </div>
  17 +
  18 + <div class="client-id">
  19 + <%= labelled_form_field _('Client Id'), f.text_field(:client_id) %>
  20 + </div>
  21 +
  22 + <div class="client-secret">
  23 + <%= labelled_form_field _('Client Secret'), f.text_field(:client_secret) %>
  24 + </div>
  25 +
  26 + <% if File.exists?(File.join(File.dirname(__FILE__), "_#{@provider.strategy}.html.erb")) %>
  27 + <%= render :partial => "#{@provider.strategy}", :locals => {:f => f, :provider => @provider} %>
  28 + <% end %>
  29 +
  30 + <div class="image-icon">
  31 + <%= f.fields_for :image_builder, @provider.image do |i| %>
  32 + <%= file_field_or_thumbnail(_('Image:'), @provider.image, i) %><%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %>
  33 + <% end %>
  34 + </div>
  35 +
  36 + <% button_bar do %>
  37 + <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %>
  38 + <% end %>
  39 +<% end %>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/index.html.erb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +<h1><%= _('Oauth Client Settings') %></h1>
  2 +<h3><%= _('Providers') %></h3>
  3 +<%= button :add, _('New'), {:action => 'new'} %>
  4 +<table>
  5 + <tr>
  6 + <th><%= _('Name') %></th>
  7 + <th><%= _('Strategy') %></th>
  8 + <th><%= _('Actions') %></th>
  9 + </tr>
  10 +
  11 + <% environment.oauth_providers.each do |provider| %>
  12 + <tr>
  13 + <td><%= provider.name %></td>
  14 + <td><%= provider.strategy %></td>
  15 + <td>
  16 + <%= link_to _('Edit'), {:action => 'edit', :id => provider.id} %>
  17 + <%= link_to _('Remove'), {:action => 'remove', :id => provider.id} %>
  18 + </td>
  19 + </tr>
  20 + <% end %>
  21 +</table>
  22 +<div class="actions">
  23 + <%= button(:back, _('Go back'), {:controller => 'plugins', :action => 'index'}) %>
  24 +</div>
... ...
plugins/oauth_provider/Gemfile 0 → 100644
... ... @@ -0,0 +1 @@
  1 +gem 'doorkeeper', '~> 1.4.0'
... ...
plugins/oauth_provider/README.md 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +README - Oauth Provider Plugin
  2 +================================
  3 +
  4 +OauthProvider is a plugin which allow noosfero to be used as an oauth provider
  5 +
  6 +Install
  7 +=======
  8 +
  9 +Enable Plugin
  10 +-------------
  11 +
  12 +cd <your_noosfero_dir>
  13 +./script/noosfero-plugins enable oauth_provider
  14 +
  15 +Active Plugin
  16 +-------------
  17 +
  18 +As a Noosfero administrator user, go to administrator panel:
  19 +
  20 +- Click on "Enable/disable plugins" option
  21 +- Click on "Oauth Provider Plugin" check-box
  22 +
  23 +Varnish Settings
  24 +================
  25 +If varnish has been used in your stack, you've to prevent cookies to be removed when calling authorization actions for oauth_provider. E.g.:
  26 +
  27 +```
  28 +if (req.url !~ "^/plugin/oauth_provider/*" && req.http.cookie !~ "_noosfero_.*") {
  29 + unset req.http.cookie;
  30 + return(lookup);
  31 +}
  32 +```
  33 +
  34 +Development
  35 +===========
  36 +
  37 +Running OauthProvider tests
  38 +--------------------
  39 +
  40 +$ rake test:noosfero_plugins:oauth_provider
  41 +
  42 +License
  43 +=======
  44 +
  45 +Copyright (c) The Author developers.
  46 +
  47 +See Noosfero license.
... ...
plugins/oauth_provider/controllers/doorkeeper/application_controller.rb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +module Doorkeeper
  2 + class ApplicationController < ApplicationController
  3 +
  4 + include Helpers::Controller
  5 + helper 'doorkeeper/form_errors'
  6 +
  7 + end
  8 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_applications_controller.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class OauthProviderApplicationsController < Doorkeeper::ApplicationsController
  2 +
  3 + no_design_blocks
  4 + layout :get_layout
  5 +
  6 + def show
  7 + end
  8 +
  9 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_authorizations_controller.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class OauthProviderAuthorizationsController < Doorkeeper::AuthorizationsController
  2 +
  3 + no_design_blocks
  4 + layout :get_layout
  5 +
  6 + def index
  7 + end
  8 +
  9 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_authorized_applications_controller.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +class OauthProviderAuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController
  2 +
  3 + no_design_blocks
  4 + layout :get_layout
  5 +
  6 +end
... ...
plugins/oauth_provider/controllers/oauth_provider_plugin_admin_controller.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +class OauthProviderPluginAdminController < AdminController
  2 +
  3 + def index
  4 + end
  5 +
  6 +end
... ...
plugins/oauth_provider/controllers/public/oauth_provider_plugin_public_controller.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +class OauthProviderPluginPublicController < PublicController
  2 +
  3 + doorkeeper_for :me
  4 +
  5 + def me
  6 + user = environment.users.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
  7 + render :json => {:id =>user.login, :email => user.email}.to_json
  8 + end
  9 +
  10 +end
... ...
plugins/oauth_provider/db/migrate/20140829153047_create_doorkeeper_tables.rb 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +class CreateDoorkeeperTables < ActiveRecord::Migration
  2 + def change
  3 + create_table :oauth_applications do |t|
  4 + t.string :name, null: false
  5 + t.string :uid, null: false
  6 + t.string :secret, null: false
  7 + t.text :redirect_uri, null: false
  8 + t.timestamps
  9 + end
  10 +
  11 + add_index :oauth_applications, :uid, unique: true
  12 +
  13 + create_table :oauth_access_grants do |t|
  14 + t.integer :resource_owner_id, null: false
  15 + t.integer :application_id, null: false
  16 + t.string :token, null: false
  17 + t.integer :expires_in, null: false
  18 + t.text :redirect_uri, null: false
  19 + t.datetime :created_at, null: false
  20 + t.datetime :revoked_at
  21 + t.string :scopes
  22 + end
  23 +
  24 + add_index :oauth_access_grants, :token, unique: true
  25 +
  26 + create_table :oauth_access_tokens do |t|
  27 + t.integer :resource_owner_id
  28 + t.integer :application_id
  29 + t.string :token, null: false
  30 + t.string :refresh_token
  31 + t.integer :expires_in
  32 + t.datetime :revoked_at
  33 + t.datetime :created_at, null: false
  34 + t.string :scopes
  35 + end
  36 +
  37 + add_index :oauth_access_tokens, :token, unique: true
  38 + add_index :oauth_access_tokens, :resource_owner_id
  39 + add_index :oauth_access_tokens, :refresh_token, unique: true
  40 + end
  41 +end
... ...
plugins/oauth_provider/lib/oauth_provider_plugin.rb 0 → 100644
... ... @@ -0,0 +1,55 @@
  1 +class OauthProviderPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + "Oauth Provider Plugin"
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("Oauth Provider.")
  9 + end
  10 +
  11 + def stylesheet?
  12 + true
  13 + end
  14 +
  15 + Doorkeeper.configure do
  16 + orm :active_record
  17 +
  18 + resource_owner_authenticator do
  19 + domain = Domain.find_by_name(request.host)
  20 + environment = domain ? domain.environment : Environment.default
  21 + environment.users.find_by_id(session[:user]) || redirect_to('/account/login')
  22 + end
  23 +
  24 + admin_authenticator do
  25 + domain = Domain.find_by_name(request.host)
  26 + environment = domain ? domain.environment : Environment.default
  27 + user = environment.users.find_by_id(session[:user])
  28 + unless user && user.person.is_admin?(environment)
  29 + redirect_to('/account/login')
  30 + end
  31 + user
  32 + end
  33 +
  34 + default_scopes :public
  35 + end
  36 +
  37 + Rails.configuration.to_prepare do
  38 + Rails.application.routes.prepend do
  39 + scope 'oauth_provider' do
  40 + use_doorkeeper do
  41 + controllers ({
  42 + :applications => 'oauth_provider_applications',
  43 + :authorized_applications => 'oauth_provider_authorized_applications',
  44 + :authorizations => 'oauth_provider_authorizations'
  45 + })
  46 + end
  47 + end
  48 + end
  49 + end
  50 +
  51 + SCOPE_TRANSLATION = {
  52 + 'public' => _('Access your public data')
  53 + }
  54 +
  55 +end
... ...
plugins/oauth_provider/public/style.css 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +.oauth-provider-authorize .actions form {
  2 + display: inline-block;
  3 +}
  4 +.oauth-provider-authorize .h4 {
  5 + font-size: 14px;
  6 + color: rgb(36, 36, 36)
  7 +}
  8 +.oauth-provider-authorize #oauth-permissions {
  9 + color: rgb(92, 92, 92);
  10 +}
  11 +.oauth-provider .actions {
  12 + margin-top: 10px;
  13 +}
... ...
plugins/oauth_provider/views/doorkeeper/applications/_delete_form.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%- submit_btn_css ||= 'btn btn-link' %>
  2 +<%= form_tag [:oauth, application] do %>
  3 + <input type="hidden" name="_method" value="delete">
  4 + <%= submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css %>
  5 +<% end %>
... ...
plugins/oauth_provider/views/doorkeeper/applications/_form.html.erb 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +<%= form_for [:oauth, application], html: {class: 'form-horizontal', role: 'form'} do |f| %>
  2 + <% if application.errors.any? %>
  3 + <div class="alert alert-danger" data-alert>
  4 + <p><%= _('Whoops! Check your form for possible errors') %></p>
  5 + </div>
  6 + <% end %>
  7 +
  8 + <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do %>
  9 + <%= f.label :name, class: 'col-sm-2 control-label', for: 'application_name' %>
  10 + <div class="col-sm-10">
  11 + <%= f.text_field :name, class: 'form-control' %>
  12 + <%= doorkeeper_errors_for application, :name %>
  13 + </div>
  14 + <% end %>
  15 +
  16 + <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do %>
  17 + <%= f.label :redirect_uri, class: 'col-sm-2 control-label', for: 'application_redirect_uri' %>
  18 + <div class="col-sm-10">
  19 + <%= f.text_area :redirect_uri, class: 'form-control' %>
  20 + <%= doorkeeper_errors_for application, :redirect_uri %>
  21 + <span class="help-block">
  22 + <%= _('Use one line per URI') %>
  23 + </span>
  24 + <% if Doorkeeper.configuration.native_redirect_uri %>
  25 + <span class="help-block">
  26 + Use <code><%= Doorkeeper.configuration.native_redirect_uri %></code> for local tests
  27 + </span>
  28 + <% end %>
  29 + </div>
  30 + <% end %>
  31 +
  32 + <div class="form-group">
  33 + <div class="col-sm-offset-2 col-sm-10">
  34 + <%= f.submit _('Submit'), class: "btn btn-primary" %>
  35 + <%= link_to _("Cancel"), oauth_applications_path, :class => "btn btn-default" %>
  36 + </div>
  37 + </div>
  38 +<% end %>
  39 +
... ...
plugins/oauth_provider/views/doorkeeper/applications/edit.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<div class="page-header">
  2 + <h1><%= _('Edit application') %></h1>
  3 +</div>
  4 +
  5 +<%= render 'form', application: @application %>
... ...
plugins/oauth_provider/views/doorkeeper/applications/index.html.erb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +<div class="oauth-provider">
  2 +<div class="page-header">
  3 + <h3><%= link_to _('Oauh Provider'), '/admin/plugin/oauth_provider' %></h3>
  4 +</div>
  5 +
  6 +<p><%= link_to _('New Application'), new_oauth_application_path, class: 'btn btn-success' %></p>
  7 +
  8 +<table class="table table-striped">
  9 + <thead>
  10 + <tr>
  11 + <th><%= _('Name') %></th>
  12 + <th><%= _('Callback URL') %></th>
  13 + <th></th>
  14 + <th></th>
  15 + </tr>
  16 + </thead>
  17 + <tbody>
  18 + <% @applications.each do |application| %>
  19 + <tr id="application_<%= application.id %>">
  20 + <td><%= link_to application.name, [:oauth, application] %></td>
  21 + <td><%= application.redirect_uri %></td>
  22 + <td><%= link_to _('Edit'), edit_oauth_application_path(application), class: 'btn btn-link' %></td>
  23 + <td><%= render 'delete_form', application: application %></td>
  24 + </tr>
  25 + <% end %>
  26 + </tbody>
  27 +</table>
  28 +<div class="actions">
  29 + <%= button(:back, _('Go back'), {:controller => 'oauth_provider_plugin_admin', :action => 'index'}) %>
  30 +</div>
  31 +</div>
... ...
plugins/oauth_provider/views/doorkeeper/applications/new.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<div class="page-header">
  2 + <h1>New application</h1>
  3 +</div>
  4 +
  5 +<%= render 'form', application: @application %>
... ...
plugins/oauth_provider/views/doorkeeper/applications/show.html.erb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +<div class="page-header">
  2 + <h1><%= _('Application: %s' % @application.name) %></h1>
  3 +</div>
  4 +
  5 +<div class="row">
  6 + <div class="col-md-8">
  7 + <h4><%= _('Application Id:') %></h4>
  8 +
  9 + <p><code id="application_id"><%= @application.uid %></code></p>
  10 +
  11 + <h4><%= _('Secret:') %></h4>
  12 +
  13 + <p><code id="secret"><%= @application.secret %></code></p>
  14 +
  15 + <h4><%= _('Callback urls:') %></h4>
  16 +
  17 + <table>
  18 + <% @application.redirect_uri.split.each do |uri| %>
  19 + <tr>
  20 + <td>
  21 + <code><%= uri %></code>
  22 + </td>
  23 + <td>
  24 + </td>
  25 + </tr>
  26 + <% end %>
  27 + </table>
  28 + </div>
  29 +
  30 + <div class="col-md-4">
  31 + <h3><%= _('Actions') %></h3>
  32 +
  33 + <p>
  34 + <%= link_to _('Edit'), edit_oauth_application_path(@application), class: 'btn btn-primary' %>
  35 + <%= link_to _("Cancel"), oauth_applications_path, :class => "btn btn-default" %>
  36 + </p>
  37 +
  38 + <p><%= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger' %></p>
  39 + </div>
  40 +</div>
... ...
plugins/oauth_provider/views/doorkeeper/authorizations/error.html.erb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +<div class="page-header">
  2 + <h1>An error has occurred</h1>
  3 +</div>
  4 +
  5 +<main role="main">
  6 + <pre><%= @pre_auth.error_response.body[:error_description] %></pre>
  7 +</main>
... ...
plugins/oauth_provider/views/doorkeeper/authorizations/new.html.erb 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +<div class="oauth-provider-authorize">
  2 +
  3 +<header class="page-header" role="banner">
  4 + <h1><%= _('Authorize required') %></h1>
  5 +</header>
  6 +
  7 +<main role="main">
  8 + <p class="h4">
  9 + <%= _('Authorize %s to use your account?' % "<strong class=\"text-info\">#{@pre_auth.client.name}</strong>") %>
  10 + </p>
  11 +
  12 + <% if @pre_auth.scopes %>
  13 + <div id="oauth-permissions">
  14 + <p><%= _('This application will be able to:') %></p>
  15 +
  16 + <ul class="text-info">
  17 + <% @pre_auth.scopes.each do |scope| %>
  18 + <li><%= OauthProviderPlugin::SCOPE_TRANSLATION[scope] %></li>
  19 + <% end %>
  20 + </ul>
  21 + </div>
  22 + <% end %>
  23 +
  24 + <div class="actions">
  25 + <%= form_tag oauth_authorization_path, method: :post do %>
  26 + <%= hidden_field_tag :client_id, @pre_auth.client.uid %>
  27 + <%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
  28 + <%= hidden_field_tag :state, @pre_auth.state %>
  29 + <%= hidden_field_tag :response_type, @pre_auth.response_type %>
  30 + <%= hidden_field_tag :scope, @pre_auth.scope %>
  31 + <%= submit_button :ok, _("Authorize") %>
  32 + <% end %>
  33 + <%= form_tag oauth_authorization_path, method: :delete do %>
  34 + <%= hidden_field_tag :client_id, @pre_auth.client.uid %>
  35 + <%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
  36 + <%= hidden_field_tag :state, @pre_auth.state %>
  37 + <%= hidden_field_tag :response_type, @pre_auth.response_type %>
  38 + <%= hidden_field_tag :scope, @pre_auth.scope %>
  39 + <%= submit_button :cancel, _("Deny") %>
  40 + <% end %>
  41 + </div>
  42 +</main>
  43 +</div>
... ...
plugins/oauth_provider/views/doorkeeper/authorizations/show.html.erb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +<header class="page-header">
  2 + <h1>Authorization code:</h1>
  3 +</header>
  4 +
  5 +<main role="main">
  6 + <code id="authorization_code"><%= params[:code] %></code>
  7 +</main>
... ...
plugins/oauth_provider/views/doorkeeper/authorized_applications/_delete_form.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%- submit_btn_css ||= 'btn btn-link' %>
  2 +<%= form_tag oauth_authorized_application_path(application) do %>
  3 + <input type="hidden" name="_method" value="delete">
  4 + <%= submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: submit_btn_css %>
  5 +<% end %>
... ...
plugins/oauth_provider/views/doorkeeper/authorized_applications/index.html.erb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +<div class="oauth-provider">
  2 +<header class="page-header">
  3 + <h1>Your authorized applications</h1>
  4 +</header>
  5 +
  6 +<main role="main">
  7 + <table class="table table-striped">
  8 + <thead>
  9 + <tr>
  10 + <th>Application</th>
  11 + <th>Created At</th>
  12 + <th></th>
  13 + <th></th>
  14 + </tr>
  15 + </thead>
  16 + <tbody>
  17 + <% @applications.each do |application| %>
  18 + <tr>
  19 + <td><%= application.name %></td>
  20 + <td><%= application.created_at.strftime('%Y-%m-%d %H:%M:%S') %></td>
  21 + <td><%= render 'delete_form', application: application %></td>
  22 + </tr>
  23 + <% end %>
  24 + </tbody>
  25 + </table>
  26 +</main>
  27 +
  28 +<div class="actions">
  29 + <%= button(:back, _('Go back'), :back) %>
  30 +</div>
  31 +</div>
... ...
plugins/oauth_provider/views/oauth_provider_plugin_admin/index.html.erb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +<div class="oauth-provider">
  2 +<h3><%= _('Oauh Provider') %></h3>
  3 +
  4 + <div class="applications">
  5 + <%= link_to _('Applications'), oauth_applications_path %>
  6 + </div>
  7 + <div class="authorized-applications">
  8 + <%= link_to _('Authorized Applications'), oauth_authorized_applications_path %>
  9 + </div>
  10 +
  11 + <div class="actions">
  12 + <%= button(:back, _('Go back'), {:controller => 'plugins', :action => 'index'}) %>
  13 + </div>
  14 +</div>
... ...
plugins/relevant_content/lib/relevant_content_plugin/relevant_content_block.rb
... ... @@ -4,7 +4,7 @@ class RelevantContentPlugin::RelevantContentBlock &lt; Block
4 4 end
5 5  
6 6 def default_title
7   - _('Relevant content')
  7 + _('Relevant content')
8 8 end
9 9  
10 10 def help
... ... @@ -53,7 +53,7 @@ class RelevantContentPlugin::RelevantContentBlock &lt; Block
53 53 env = owner.environment
54 54 end
55 55  
56   - if env.plugin_enabled?(VotePlugin)
  56 + if env.plugin_enabled?('VotePlugin')
57 57 if self.show_most_liked
58 58 docs = Article.more_positive_votes(owner, self.limit)
59 59 if !docs.blank?
... ...
plugins/relevant_content/test/unit/article.rb
... ... @@ -20,10 +20,10 @@ class RelevantContentBlockTest &lt; ActiveSupport::TestCase
20 20  
21 21 def enable_vote_plugin
22 22 enabled = false
23   - environment=Environment.default
  23 + environment = Environment.default
24 24 if Noosfero::Plugin.all.include?('VotePlugin')
25   - if not environment.enabled_plugins.include?(:vote)
26   - environment.enable_plugin(Vote)
  25 + if not environment.enabled_plugins.include?('VotePlugin')
  26 + environment.enable_plugin(VotePlugin)
27 27 environment.save!
28 28 end
29 29 enabled = true
... ... @@ -145,4 +145,4 @@ class RelevantContentBlockTest &lt; ActiveSupport::TestCase
145 145 assert_equal '23 votes for 29 votes against', articles.first.name
146 146 assert_equal '2 votes against', articles.last.name
147 147 end
148   -end
149 148 \ No newline at end of file
  149 +end
... ...
plugins/relevant_content/test/unit/relevant_content_block_test.rb
... ... @@ -44,4 +44,19 @@ class RelevantContentBlockTest &lt; ActiveSupport::TestCase
44 44 assert_equal RelevantContentPlugin::RelevantContentBlock.expire_on, {:environment=>[:article], :profile=>[:article]}
45 45 end
46 46  
  47 + should 'not crash if vote plugin is not found' do
  48 + box = fast_create(Box, :owner_id => @profile.id, :owner_type => 'Profile')
  49 + block = RelevantContentPlugin::RelevantContentBlock.new(:box => box)
  50 +
  51 + Environment.any_instance.stubs(:enabled_plugins).returns(['RelevantContent'])
  52 + # When the plugin is disabled from noosfero instance, its constant name is
  53 + # undefined. To test this case, I have to manually undefine the constant
  54 + # if necessary.
  55 + Object.send(:remove_const, VotePlugin.to_s) if defined? VotePlugin
  56 +
  57 + assert_nothing_raised do
  58 + block.content
  59 + end
  60 + end
  61 +
47 62 end
... ...
plugins/shopping_cart/public/cart.js
... ... @@ -290,14 +290,11 @@ function Cart(config) {
290 290 log.error('Send request - HTTP '+status, errorThrown);
291 291 },
292 292 complete: function() {
293   - $.colorbox.close();
  293 + noosfero.modal.close();
294 294 }
295 295 });
296 296 }
297 297  
298   - Cart.colorbox_close = function() {
299   - $.colorbox.close();
300   - }
301 298  
302 299 $(window).bind('beforeunload', function(){
303 300 log('Page unload.');
... ...
plugins/shopping_cart/views/cart.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <a href="cart:clean" onclick="Cart.clean(this); return false" class="cart-clean"><%=_('Clean basket')%></a>
6 6 <ul class="cart-items"></ul>
7 7 <div class="cart-total"><%=_('Total:')%> <b></b></div>
8   - <a href="/plugin/shopping_cart/buy" class="cart-buy colorbox"><%=_('Shopping checkout')%></a>
  8 + <a href="/plugin/shopping_cart/buy" class="cart-buy modal"><%=_('Shopping checkout')%></a>
9 9 </div>
10 10 <a href="#" onclick="Cart.toggle(this); return false" class="cart-toggle">
11 11 <span class="str-show"><%=_('Show basket')%></span>
... ...
plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb
... ... @@ -24,7 +24,7 @@
24 24 <% end %>
25 25 <% delivery_option = @settings.delivery_options.first && @settings.delivery_options.first.first %>
26 26 <%= items_table(@cart[:items], @profile, delivery_option) %>
27   - <%= link_to '', '#', :onclick => "Cart.colorbox_close(this);", :class => 'cart-box-close icon-cancel' %>
  27 + <%= link_to_function '', "noosfero.modal.close();", :class => 'cart-box-close icon-cancel' %>
28 28 </div>
29 29  
30 30 <%= javascript_include_tag '../plugins/shopping_cart/buy' %>
... ...
plugins/shopping_cart/views/shopping_cart_plugin_profile/buy.html.erb
... ... @@ -17,7 +17,7 @@
17 17 </div>
18 18 <% end %>
19 19 <%= items_table(session[:cart][:items], profile) %>
20   - <%= link_to '', '#', :onclick => "Cart.colorbox_close(this);", :class => 'cart-box-close icon-cancel' %>
  20 + <%= link_to_function '', "noosfero.modal.close();", :class => 'cart-box-close icon-cancel' %>
21 21 </div>
22 22  
23 23 <script type="text/javascript">
... ...
plugins/statistics/test/functional/statistics_plugin_home_controller_test.rb 100644 → 100755
... ... @@ -84,6 +84,9 @@ class HomeControllerTest &lt; ActionController::TestCase
84 84 end
85 85  
86 86 should 'not display products class in statistics-block-data block' do
  87 + @block.product_counter = true
  88 + @environment.disable('products_for_enterprises')
  89 + @block.save!
87 90 get :index
88 91  
89 92 assert_no_tag :tag => 'div', :attributes => {:class => 'statistics-block-data'}, :descendant => { :tag => 'li', :attributes => {:class => 'products'} }
... ...
plugins/stoa/public/javascripts/signup_complement.js
... ... @@ -55,9 +55,10 @@ $(&quot;#usp_id_field&quot;).observe_field(1, function(){
55 55 });
56 56  
57 57 function displayValidationUspIdError(error){
58   - jQuery.colorbox({html: '<h2>'+error.message+'</h2>'+error.backtrace.join("<br />"),
  58 + noosfero.modal.html('<h2>'+error.message+'</h2>'+error.backtrace.join("<br />"), {
59 59 height: "80%",
60   - width: "70%" });
  60 + width: "70%"
  61 + });
61 62 }
62 63  
63 64 jQuery('#usp_id_field').focus(function() { jQuery('#usp-id-balloon').fadeIn('slow'); });
... ...
plugins/tolerance_time/lib/tolerance_time_plugin.rb
... ... @@ -28,8 +28,7 @@ class ToleranceTimePlugin &lt; Noosfero::Plugin
28 28 end
29 29  
30 30 def cms_controller_filters
31   - p = Proc.new { |context| return if !context.environment.plugin_enabled?(ToleranceTimePlugin) }
32   - block = lambda do
  31 + block = proc do
33 32 content = Article.find(params[:id])
34 33 if ToleranceTimePlugin.expired?(content)
35 34 session[:notice] = _("This content can't be edited anymore because it expired the tolerance time")
... ... @@ -43,8 +42,7 @@ class ToleranceTimePlugin &lt; Noosfero::Plugin
43 42 end
44 43  
45 44 def content_viewer_controller_filters
46   - p = Proc.new { |context| return if !context.environment.plugin_enabled?(ToleranceTimePlugin) }
47   - block = lambda do
  45 + block = proc do
48 46 content = Comment.find(params[:id])
49 47 if ToleranceTimePlugin.expired?(content)
50 48 session[:notice] = _("This content can't be edited anymore because it expired the tolerance time")
... ...
public/designs/templates/topleft/config.yml 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +name: "Top and Left Bar"
  2 +title: "Style 2 columns and a box at top of content"
  3 +description: "A theme with 2 columns and a box at the top of the content"
  4 +number_of_boxes: 3
... ...
public/designs/templates/topleft/stylesheets/style.css 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +#boxes {
  2 + display: table;
  3 + width: 100%;
  4 +}
  5 +
  6 +.box-1 {
  7 + margin: 0 0 0 240px;
  8 +}
  9 +
  10 +.box-1 .blocks {
  11 + width: 100%;
  12 + float: left;
  13 +}
  14 +
  15 +.box-2 {
  16 + position: relative;
  17 + float: left;
  18 + width: 190px;
  19 +}
  20 +
  21 +.box-3 {
  22 + position: relative;
  23 + display: table-footer-group;
  24 + width: 100%;
  25 +}
  26 +
  27 +#profile-activity ul,
  28 +#profile-network ul,
  29 +#profile-wall ul {
  30 + width: 460px;
  31 +}
  32 +#profile-activity ul.comment-replies,
  33 +#profile-network ul.comment-replies,
  34 +#profile-wall ul.comment-replies {
  35 + width: auto;
  36 +}
  37 +
... ...
public/designs/templates/topleft/thumbnail.png 0 → 100644

3.87 KB

public/designs/templates/topleft/thumbnail.svg 0 → 100644
... ... @@ -0,0 +1,239 @@
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<!-- Created with Inkscape (http://www.inkscape.org/) -->
  3 +
  4 +<svg
  5 + xmlns:dc="http://purl.org/dc/elements/1.1/"
  6 + xmlns:cc="http://creativecommons.org/ns#"
  7 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  8 + xmlns:svg="http://www.w3.org/2000/svg"
  9 + xmlns="http://www.w3.org/2000/svg"
  10 + xmlns:xlink="http://www.w3.org/1999/xlink"
  11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  12 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  13 + width="64px"
  14 + height="64px"
  15 + id="svg2383"
  16 + sodipodi:version="0.32"
  17 + inkscape:version="0.48.4 r9939"
  18 + sodipodi:docname="thumbnail.svg"
  19 + inkscape:output_extension="org.inkscape.output.svg.inkscape"
  20 + inkscape:export-filename="thumbnail.png"
  21 + inkscape:export-xdpi="90"
  22 + inkscape:export-ydpi="90"
  23 + version="1.1">
  24 + <defs
  25 + id="defs2385">
  26 + <linearGradient
  27 + id="linearGradient3263">
  28 + <stop
  29 + id="stop3265"
  30 + offset="0"
  31 + style="stop-color:#204a87;stop-opacity:1" />
  32 + <stop
  33 + id="stop3267"
  34 + offset="1"
  35 + style="stop-color:#729fcf;stop-opacity:1" />
  36 + </linearGradient>
  37 + <linearGradient
  38 + id="linearGradient3257"
  39 + inkscape:collect="always">
  40 + <stop
  41 + id="stop3259"
  42 + offset="0"
  43 + style="stop-color:#204a87;stop-opacity:1" />
  44 + <stop
  45 + id="stop3261"
  46 + offset="1"
  47 + style="stop-color:#729fcf;stop-opacity:1" />
  48 + </linearGradient>
  49 + <linearGradient
  50 + inkscape:collect="always"
  51 + id="linearGradient3245">
  52 + <stop
  53 + style="stop-color:#204a87;stop-opacity:1"
  54 + offset="0"
  55 + id="stop3247" />
  56 + <stop
  57 + style="stop-color:#729fcf;stop-opacity:1"
  58 + offset="1"
  59 + id="stop3249" />
  60 + </linearGradient>
  61 + <inkscape:perspective
  62 + sodipodi:type="inkscape:persp3d"
  63 + inkscape:vp_x="0 : 32 : 1"
  64 + inkscape:vp_y="0 : 1000 : 0"
  65 + inkscape:vp_z="64 : 32 : 1"
  66 + inkscape:persp3d-origin="32 : 21.333333 : 1"
  67 + id="perspective2391" />
  68 + <filter
  69 + inkscape:collect="always"
  70 + id="filter3241">
  71 + <feGaussianBlur
  72 + inkscape:collect="always"
  73 + stdDeviation="0.9075"
  74 + id="feGaussianBlur3243" />
  75 + </filter>
  76 + <linearGradient
  77 + inkscape:collect="always"
  78 + xlink:href="#linearGradient3245"
  79 + id="linearGradient3251"
  80 + x1="11.5"
  81 + y1="60.5"
  82 + x2="3.5"
  83 + y2="3.5"
  84 + gradientUnits="userSpaceOnUse"
  85 + gradientTransform="matrix(1.0025263,0,0,0.76423683,0.2157619,0.85033188)" />
  86 + <linearGradient
  87 + inkscape:collect="always"
  88 + xlink:href="#linearGradient3263"
  89 + id="linearGradient3253"
  90 + x1="42.5"
  91 + y1="60.5"
  92 + x2="19.5"
  93 + y2="3.5"
  94 + gradientUnits="userSpaceOnUse"
  95 + gradientTransform="matrix(1.4160224,0,0,0.76166072,-5.6247232,0.93276759)" />
  96 + <linearGradient
  97 + inkscape:collect="always"
  98 + xlink:href="#linearGradient3257"
  99 + id="linearGradient3255"
  100 + x1="60.5"
  101 + y1="60.5"
  102 + x2="51.5"
  103 + y2="3.5"
  104 + gradientUnits="userSpaceOnUse"
  105 + gradientTransform="translate(0.32391508,-62.512846)" />
  106 + </defs>
  107 + <sodipodi:namedview
  108 + id="base"
  109 + pagecolor="#ffffff"
  110 + bordercolor="#666666"
  111 + borderopacity="1.0"
  112 + inkscape:pageopacity="0.0"
  113 + inkscape:pageshadow="2"
  114 + inkscape:zoom="3.5852524"
  115 + inkscape:cx="21.387308"
  116 + inkscape:cy="33.791467"
  117 + inkscape:current-layer="layer1"
  118 + showgrid="true"
  119 + inkscape:document-units="px"
  120 + inkscape:grid-bbox="true"
  121 + inkscape:window-width="1364"
  122 + inkscape:window-height="714"
  123 + inkscape:window-x="0"
  124 + inkscape:window-y="27"
  125 + objecttolerance="10"
  126 + gridtolerance="10"
  127 + guidetolerance="10"
  128 + inkscape:window-maximized="0">
  129 + <inkscape:grid
  130 + type="xygrid"
  131 + id="grid2382"
  132 + visible="true"
  133 + enabled="true"
  134 + originx="0.5px"
  135 + originy="0.5px"
  136 + empcolor="#0000ff"
  137 + empopacity="0.1254902"
  138 + dotted="true" />
  139 + </sodipodi:namedview>
  140 + <metadata
  141 + id="metadata2388">
  142 + <rdf:RDF>
  143 + <cc:Work
  144 + rdf:about="">
  145 + <dc:format>image/svg+xml</dc:format>
  146 + <dc:type
  147 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
  148 + <dc:title></dc:title>
  149 + </cc:Work>
  150 + </rdf:RDF>
  151 + </metadata>
  152 + <g
  153 + id="layer1"
  154 + inkscape:label="Layer 1"
  155 + inkscape:groupmode="layer">
  156 + <rect
  157 + rx="2"
  158 + ry="2"
  159 + y="2.5"
  160 + x="50.5"
  161 + height="59"
  162 + width="12"
  163 + id="rect3186"
  164 + style="opacity:0.4;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3241);enable-background:accumulate"
  165 + transform="matrix(0,1,-1,0,64.512846,0.32391508)" />
  166 + <rect
  167 + style="fill:url(#linearGradient3255);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  168 + id="rect3154"
  169 + width="12"
  170 + height="59"
  171 + x="49.823914"
  172 + y="-61.012848"
  173 + ry="2"
  174 + transform="matrix(0,1,-1,0,0,0)" />
  175 + <rect
  176 + style="opacity:0.6;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  177 + id="rect3164"
  178 + width="10"
  179 + height="57"
  180 + x="50.823914"
  181 + y="-60.012848"
  182 + ry="1"
  183 + transform="matrix(0,1,-1,0,0,0)" />
  184 + <rect
  185 + rx="2"
  186 + ry="2"
  187 + style="opacity:0.4;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3241);enable-background:accumulate"
  188 + id="rect3184"
  189 + width="11"
  190 + height="59"
  191 + x="2.5"
  192 + y="2.5"
  193 + transform="matrix(1.0025263,0,0,0.76423683,0.2157619,0.85033188)" />
  194 + <rect
  195 + rx="2"
  196 + ry="2"
  197 + style="opacity:0.4;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3241);enable-background:accumulate"
  198 + id="rect3188"
  199 + width="31"
  200 + height="59"
  201 + x="16.5"
  202 + y="2.5"
  203 + transform="matrix(1.4160224,0,0,0.76166071,-5.6247232,0.93276758)" />
  204 + <rect
  205 + y="1.9966872"
  206 + x="1.7195514"
  207 + height="45.089973"
  208 + width="11.02779"
  209 + id="rect2395"
  210 + style="fill:url(#linearGradient3251);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:0.87531;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  211 + ry="1.5284736" />
  212 + <rect
  213 + y="2.0752587"
  214 + x="16.323626"
  215 + height="44.937984"
  216 + width="43.896694"
  217 + id="rect3156"
  218 + style="fill:url(#linearGradient3253);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:1.03852236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  219 + ry="1.5233214" />
  220 + <rect
  221 + ry="0.76423681"
  222 + style="opacity:0.6;fill:none;stroke:#ffffff;stroke-width:0.87531;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  223 + id="rect3158"
  224 + width="9.0227375"
  225 + height="43.561501"
  226 + x="2.7220778"
  227 + y="2.7609239" />
  228 + <rect
  229 + y="2.8369193"
  230 + x="17.739647"
  231 + height="43.414661"
  232 + width="41.064651"
  233 + id="rect3162"
  234 + style="opacity:0.6;fill:none;stroke:#ffffff;stroke-width:1.03852236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  235 + ry="0.7616607"
  236 + inkscape:export-xdpi="90"
  237 + inkscape:export-ydpi="90" />
  238 + </g>
  239 +</svg>
... ...
public/images/colorbox/controls.png

1.22 KB | W: | H:

2.83 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
public/javascripts/application.js
... ... @@ -1005,31 +1005,6 @@ log.error = function() {
1005 1005 window.log.apply(window, jQuery.merge(['error'], arguments));
1006 1006 }
1007 1007  
1008   -jQuery(function($) {
1009   - $('.colorbox').live('click', function() {
1010   - $.colorbox({
1011   - href: $(this).attr('href'),
1012   - maxWidth: $(window).width()-50,
1013   - height: $(window).height()-50,
1014   - open: true,
1015   - fixed: true,
1016   - close: 'Cancel',
1017   - onComplete: function(bt) {
1018   - var opt = {}, maxH = $(window).height()-50;
1019   - if ($('#cboxLoadedContent *:first').height() > maxH) opt.height = maxH;
1020   - $.colorbox.resize(opt);
1021   - }
1022   - });
1023   - return false;
1024   - });
1025   -
1026   - $('.colorbox-close').live('click', function() {
1027   - $.colorbox.close();
1028   - return false;
1029   - });
1030   -
1031   -});
1032   -
1033 1008 function showHideTermsOfUse() {
1034 1009 if( jQuery("#article_has_terms_of_use").attr("checked") )
1035 1010 jQuery("#text_area_terms_of_use").show();
... ...
public/javascripts/article.js
... ... @@ -88,7 +88,7 @@ jQuery(function($) {
88 88 var $item = $(this).closest('.item');
89 89 var html_selector = $item.attr('data-item');
90 90 insert_item_in_text($item.find(html_selector));
91   - $.colorbox.close();
  91 + noosfero.modal.close();
92 92 return false;
93 93 });
94 94 $('a.zoom').live('click', function() {
... ... @@ -96,14 +96,13 @@ jQuery(function($) {
96 96 var html_selector = $item.attr('data-item');
97 97 var name = $item.attr('title');
98 98 var img = $item.find(html_selector).find('img').attr('src');
99   - $.colorbox({
100   - html: zoom_dialog_html(name, img),
101   - scrolling: false
  99 + noosfero.modal.html(zoom_dialog_html(img), {
  100 + scrolling: false,
102 101 });
103 102 return false;
104 103 });
105 104 $('a.close').live('click', function() {
106   - $.colorbox.close();
  105 + noosfero.modal.close();
107 106 return false;
108 107 })
109 108  
... ...
public/javascripts/colorbox.js
... ... @@ -1,814 +0,0 @@
1   -// ColorBox v1.3.16 - a full featured, light-weight, customizable lightbox based on jQuery 1.3+
2   -// Copyright (c) 2011 Jack Moore - jack@colorpowered.com
3   -// Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
4   -(function ($, document, window) {
5   - var
6   - // ColorBox Default Settings.
7   - // See http://colorpowered.com/colorbox for details.
8   - defaults = {
9   - transition: "elastic",
10   - speed: 300,
11   - width: false,
12   - initialWidth: "600",
13   - innerWidth: false,
14   - maxWidth: false,
15   - height: false,
16   - initialHeight: "450",
17   - innerHeight: false,
18   - maxHeight: false,
19   - scalePhotos: true,
20   - scrolling: true,
21   - inline: false,
22   - html: false,
23   - iframe: false,
24   - fastIframe: true,
25   - photo: false,
26   - href: false,
27   - title: false,
28   - rel: false,
29   - opacity: 0.9,
30   - preloading: true,
31   - current: "image {current} of {total}",
32   - previous: "previous",
33   - next: "next",
34   - close: "close",
35   - open: false,
36   - returnFocus: true,
37   - loop: true,
38   - slideshow: false,
39   - slideshowAuto: true,
40   - slideshowSpeed: 2500,
41   - slideshowStart: "start slideshow",
42   - slideshowStop: "stop slideshow",
43   - onOpen: false,
44   - onLoad: false,
45   - onComplete: false,
46   - onCleanup: false,
47   - onClosed: false,
48   - overlayClose: true,
49   - escKey: true,
50   - arrowKey: true
51   - },
52   -
53   - // Abstracting the HTML and event identifiers for easy rebranding
54   - colorbox = 'colorbox',
55   - prefix = 'cbox',
56   -
57   - // Events
58   - event_open = prefix + '_open',
59   - event_load = prefix + '_load',
60   - event_complete = prefix + '_complete',
61   - event_cleanup = prefix + '_cleanup',
62   - event_closed = prefix + '_closed',
63   - event_purge = prefix + '_purge',
64   -
65   - // Special Handling for IE
66   - isIE = $.browser.msie && !$.support.opacity, // feature detection alone gave a false positive on at least one phone browser and on some development versions of Chrome.
67   - isIE6 = isIE && $.browser.version < 7,
68   - event_ie6 = prefix + '_IE6',
69   -
70   - // Cached jQuery Object Variables
71   - $overlay,
72   - $box,
73   - $wrap,
74   - $content,
75   - $topBorder,
76   - $leftBorder,
77   - $rightBorder,
78   - $bottomBorder,
79   - $related,
80   - $window,
81   - $loaded,
82   - $loadingBay,
83   - $loadingOverlay,
84   - $title,
85   - $current,
86   - $slideshow,
87   - $next,
88   - $prev,
89   - $close,
90   - $groupControls,
91   -
92   - // Variables for cached values or use across multiple functions
93   - settings = {},
94   - interfaceHeight,
95   - interfaceWidth,
96   - loadedHeight,
97   - loadedWidth,
98   - element,
99   - index,
100   - photo,
101   - open,
102   - active,
103   - closing = false,
104   -
105   - publicMethod,
106   - boxElement = prefix + 'Element';
107   -
108   - // ****************
109   - // HELPER FUNCTIONS
110   - // ****************
111   -
112   - // jQuery object generator to reduce code size
113   - function $div(id, cssText) {
114   - var div = document.createElement('div');
115   - if (id) {
116   - div.id = prefix + id;
117   - }
118   - div.style.cssText = cssText || false;
119   - return $(div);
120   - }
121   -
122   - // Convert % values to pixels
123   - function setSize(size, dimension) {
124   - dimension = dimension === 'x' ? $window.width() : $window.height();
125   - return (typeof size === 'string') ? Math.round((/%/.test(size) ? (dimension / 100) * parseInt(size, 10) : parseInt(size, 10))) : size;
126   - }
127   -
128   - // Checks an href to see if it is a photo.
129   - // There is a force photo option (photo: true) for hrefs that cannot be matched by this regex.
130   - function isImage(url) {
131   - return settings.photo || /\.(gif|png|jpg|jpeg|bmp)(?:\?([^#]*))?(?:#(\.*))?$/i.test(url);
132   - }
133   -
134   - // Assigns function results to their respective settings. This allows functions to be used as values.
135   - function process(settings) {
136   - for (var i in settings) {
137   - if ($.isFunction(settings[i]) && i.substring(0, 2) !== 'on') { // checks to make sure the function isn't one of the callbacks, they will be handled at the appropriate time.
138   - settings[i] = settings[i].call(element);
139   - }
140   - }
141   - settings.rel = settings.rel || element.rel || 'nofollow';
142   - settings.href = $.trim(settings.href || $(element).attr('href'));
143   - settings.title = settings.title || element.title;
144   - }
145   -
146   - function trigger(event, callback) {
147   - if (callback) {
148   - callback.call(element);
149   - }
150   - $.event.trigger(event);
151   - }
152   -
153   - // Slideshow functionality
154   - function slideshow() {
155   - var
156   - timeOut,
157   - className = prefix + "Slideshow_",
158   - click = "click." + prefix,
159   - start,
160   - stop,
161   - clear;
162   -
163   - if (settings.slideshow && $related[1]) {
164   - start = function () {
165   - $slideshow
166   - .text(settings.slideshowStop)
167   - .unbind(click)
168   - .bind(event_complete, function () {
169   - if (index < $related.length - 1 || settings.loop) {
170   - timeOut = setTimeout(publicMethod.next, settings.slideshowSpeed);
171   - }
172   - })
173   - .bind(event_load, function () {
174   - clearTimeout(timeOut);
175   - })
176   - .one(click + ' ' + event_cleanup, stop);
177   - $box.removeClass(className + "off").addClass(className + "on");
178   - timeOut = setTimeout(publicMethod.next, settings.slideshowSpeed);
179   - };
180   -
181   - stop = function () {
182   - clearTimeout(timeOut);
183   - $slideshow
184   - .text(settings.slideshowStart)
185   - .unbind([event_complete, event_load, event_cleanup, click].join(' '))
186   - .one(click, start);
187   - $box.removeClass(className + "on").addClass(className + "off");
188   - };
189   -
190   - if (settings.slideshowAuto) {
191   - start();
192   - } else {
193   - stop();
194   - }
195   - }
196   - }
197   -
198   - function launch(elem) {
199   - if (!closing) {
200   -
201   - element = elem;
202   -
203   - process($.extend(settings, $.data(element, colorbox)));
204   -
205   - $related = $(element);
206   -
207   - index = 0;
208   -
209   - if (settings.rel !== 'nofollow') {
210   - $related = $('.' + boxElement).filter(function () {
211   - var relRelated = $.data(this, colorbox).rel || this.rel;
212   - return (relRelated === settings.rel);
213   - });
214   - index = $related.index(element);
215   -
216   - // Check direct calls to ColorBox.
217   - if (index === -1) {
218   - $related = $related.add(element);
219   - index = $related.length - 1;
220   - }
221   - }
222   -
223   - if (!open) {
224   - open = active = true; // Prevents the page-change action from queuing up if the visitor holds down the left or right keys.
225   -
226   - $box.show();
227   -
228   - if (settings.returnFocus) {
229   - try {
230   - element.blur();
231   - $(element).one(event_closed, function () {
232   - try {
233   - this.focus();
234   - } catch (e) {
235   - // do nothing
236   - }
237   - });
238   - } catch (e) {
239   - // do nothing
240   - }
241   - }
242   -
243   - // +settings.opacity avoids a problem in IE when using non-zero-prefixed-string-values, like '.5'
244   - $overlay.css({"opacity": +settings.opacity, "cursor": settings.overlayClose ? "pointer" : "auto"}).show();
245   -
246   - // Opens inital empty ColorBox prior to content being loaded.
247   - settings.w = setSize(settings.initialWidth, 'x');
248   - settings.h = setSize(settings.initialHeight, 'y');
249   - publicMethod.position(0);
250   -
251   - if (isIE6) {
252   - $window.bind('resize.' + event_ie6 + ' scroll.' + event_ie6, function () {
253   - $overlay.css({width: $window.width(), height: $window.height(), top: $window.scrollTop(), left: $window.scrollLeft()});
254   - }).trigger('resize.' + event_ie6);
255   - }
256   -
257   - trigger(event_open, settings.onOpen);
258   -
259   - $groupControls.add($title).hide();
260   -
261   - $close.html(settings.close).show();
262   - }
263   -
264   - publicMethod.load(true);
265   - }
266   - }
267   -
268   - // ****************
269   - // PUBLIC FUNCTIONS
270   - // Usage format: $.fn.colorbox.close();
271   - // Usage from within an iframe: parent.$.fn.colorbox.close();
272   - // ****************
273   -
274   - publicMethod = $.fn[colorbox] = $[colorbox] = function (options, callback) {
275   - var $this = this, autoOpen;
276   -
277   - if (!$this[0] && $this.selector) { // if a selector was given and it didn't match any elements, go ahead and exit.
278   - return $this;
279   - }
280   -
281   - options = options || {};
282   -
283   - if (callback) {
284   - options.onComplete = callback;
285   - }
286   -
287   - if (!$this[0] || $this.selector === undefined) { // detects $.colorbox() and $.fn.colorbox()
288   - $this = $('<a/>');
289   - options.open = true; // assume an immediate open
290   - }
291   -
292   - $this.each(function () {
293   - $.data(this, colorbox, $.extend({}, $.data(this, colorbox) || defaults, options));
294   - $(this).addClass(boxElement);
295   - });
296   -
297   - autoOpen = options.open;
298   -
299   - if ($.isFunction(autoOpen)) {
300   - autoOpen = autoOpen.call($this);
301   - }
302   -
303   - if (autoOpen) {
304   - launch($this[0]);
305   - }
306   -
307   - return $this;
308   - };
309   -
310   - // Initialize ColorBox: store common calculations, preload the interface graphics, append the html.
311   - // This preps colorbox for a speedy open when clicked, and lightens the burdon on the browser by only
312   - // having to run once, instead of each time colorbox is opened.
313   - publicMethod.init = function () {
314   - // Create & Append jQuery Objects
315   - $window = $(window);
316   - $box = $div().attr({id: colorbox, 'class': isIE ? prefix + (isIE6 ? 'IE6' : 'IE') : ''});
317   - $overlay = $div("Overlay", isIE6 ? 'position:absolute' : '').hide();
318   -
319   - $wrap = $div("Wrapper");
320   - $content = $div("Content").append(
321   - $loaded = $div("LoadedContent", 'width:0; height:0; overflow:hidden'),
322   - $loadingOverlay = $div("LoadingOverlay").add($div("LoadingGraphic")),
323   - $title = $div("Title"),
324   - $current = $div("Current"),
325   - $next = $div("Next"),
326   - $prev = $div("Previous"),
327   - $slideshow = $div("Slideshow").bind(event_open, slideshow),
328   - $close = $div("Close")
329   - );
330   - $wrap.append( // The 3x3 Grid that makes up ColorBox
331   - $div().append(
332   - $div("TopLeft"),
333   - $topBorder = $div("TopCenter"),
334   - $div("TopRight")
335   - ),
336   - $div(false, 'clear:left').append(
337   - $leftBorder = $div("MiddleLeft"),
338   - $content,
339   - $rightBorder = $div("MiddleRight")
340   - ),
341   - $div(false, 'clear:left').append(
342   - $div("BottomLeft"),
343   - $bottomBorder = $div("BottomCenter"),
344   - $div("BottomRight")
345   - )
346   - ).children().children().css({'float': 'left'});
347   -
348   - $loadingBay = $div(false, 'position:absolute; width:9999px; visibility:hidden; display:none');
349   -
350   - $('body').prepend($overlay, $box.append($wrap, $loadingBay));
351   -
352   - $content.children()
353   - .hover(function () {
354   - $(this).addClass('hover');
355   - }, function () {
356   - $(this).removeClass('hover');
357   - }).addClass('hover');
358   -
359   - // Cache values needed for size calculations
360   - interfaceHeight = $topBorder.height() + $bottomBorder.height() + $content.outerHeight(true) - $content.height();//Subtraction needed for IE6
361   - interfaceWidth = $leftBorder.width() + $rightBorder.width() + $content.outerWidth(true) - $content.width();
362   - loadedHeight = $loaded.outerHeight(true);
363   - loadedWidth = $loaded.outerWidth(true);
364   -
365   - // Setting padding to remove the need to do size conversions during the animation step.
366   - $box.css({"padding-bottom": interfaceHeight, "padding-right": interfaceWidth}).hide();
367   -
368   - // Setup button events.
369   - $next.click(function () {
370   - publicMethod.next();
371   - });
372   - $prev.click(function () {
373   - publicMethod.prev();
374   - });
375   - $close.click(function () {
376   - publicMethod.close();
377   - });
378   -
379   - $groupControls = $next.add($prev).add($current).add($slideshow);
380   -
381   - // Adding the 'hover' class allowed the browser to load the hover-state
382   - // background graphics. The class can now can be removed.
383   - $content.children().removeClass('hover');
384   -
385   - $('.' + boxElement).live('click', function (e) {
386   - // checks to see if it was a non-left mouse-click and for clicks modified with ctrl, shift, or alt.
387   - if (!((e.button !== 0 && typeof e.button !== 'undefined') || e.ctrlKey || e.shiftKey || e.altKey)) {
388   - e.preventDefault();
389   - launch(this);
390   - }
391   - });
392   -
393   - $overlay.click(function () {
394   - if (settings.overlayClose) {
395   - publicMethod.close();
396   - }
397   - });
398   -
399   - // Set Navigation Key Bindings
400   - $(document).bind('keydown.' + prefix, function (e) {
401   - var key = e.keyCode;
402   - if (open && settings.escKey && key === 27) {
403   - e.preventDefault();
404   - publicMethod.close();
405   - }
406   - if (open && settings.arrowKey && $related[1]) {
407   - if (key === 37) {
408   - e.preventDefault();
409   - $prev.click();
410   - } else if (key === 39) {
411   - e.preventDefault();
412   - $next.click();
413   - }
414   - }
415   - });
416   - };
417   -
418   - publicMethod.remove = function () {
419   - $box.add($overlay).remove();
420   - $('.' + boxElement).die('click').removeData(colorbox).removeClass(boxElement);
421   - };
422   -
423   - publicMethod.position = function (speed, loadedCallback) {
424   - var
425   - animate_speed,
426   - // keeps the top and left positions within the browser's viewport.
427   - posTop = Math.max(document.documentElement.clientHeight - settings.h - loadedHeight - interfaceHeight, 0) / 2 + $window.scrollTop(),
428   - posLeft = Math.max($window.width() - settings.w - loadedWidth - interfaceWidth, 0) / 2 + $window.scrollLeft();
429   -
430   - // setting the speed to 0 to reduce the delay between same-sized content.
431   - animate_speed = ($box.width() === settings.w + loadedWidth && $box.height() === settings.h + loadedHeight) ? 0 : speed;
432   -
433   - // this gives the wrapper plenty of breathing room so it's floated contents can move around smoothly,
434   - // but it has to be shrank down around the size of div#colorbox when it's done. If not,
435   - // it can invoke an obscure IE bug when using iframes.
436   - $wrap[0].style.width = $wrap[0].style.height = "9999px";
437   -
438   - function modalDimensions(that) {
439   - // loading overlay height has to be explicitly set for IE6.
440   - $topBorder[0].style.width = $bottomBorder[0].style.width = $content[0].style.width = that.style.width;
441   - $loadingOverlay[0].style.height = $loadingOverlay[1].style.height = $content[0].style.height = $leftBorder[0].style.height = $rightBorder[0].style.height = that.style.height;
442   - }
443   -
444   - $box.dequeue().animate({width: settings.w + loadedWidth, height: settings.h + loadedHeight, top: posTop, left: posLeft}, {
445   - duration: animate_speed,
446   - complete: function () {
447   - modalDimensions(this);
448   -
449   - active = false;
450   -
451   - // shrink the wrapper down to exactly the size of colorbox to avoid a bug in IE's iframe implementation.
452   - $wrap[0].style.width = (settings.w + loadedWidth + interfaceWidth) + "px";
453   - $wrap[0].style.height = (settings.h + loadedHeight + interfaceHeight) + "px";
454   -
455   - if (loadedCallback) {
456   - loadedCallback();
457   - }
458   - },
459   - step: function () {
460   - modalDimensions(this);
461   - }
462   - });
463   - };
464   -
465   - publicMethod.resize = function (options) {
466   - if (open) {
467   - options = options || {};
468   -
469   - if (options.width) {
470   - settings.w = setSize(options.width, 'x') - loadedWidth - interfaceWidth;
471   - }
472   - if (options.innerWidth) {
473   - settings.w = setSize(options.innerWidth, 'x');
474   - }
475   - $loaded.css({width: settings.w});
476   -
477   - if (options.height) {
478   - settings.h = setSize(options.height, 'y') - loadedHeight - interfaceHeight;
479   - }
480   - if (options.innerHeight) {
481   - settings.h = setSize(options.innerHeight, 'y');
482   - }
483   - if (!options.innerHeight && !options.height) {
484   - var $child = $loaded.wrapInner("<div style='overflow:auto'></div>").children(); // temporary wrapper to get an accurate estimate of just how high the total content should be.
485   - settings.h = $child.height();
486   - $child.replaceWith($child.children()); // ditch the temporary wrapper div used in height calculation
487   - }
488   - $loaded.css({height: settings.h});
489   -
490   - publicMethod.position(settings.transition === "none" ? 0 : settings.speed);
491   - }
492   - };
493   -
494   - publicMethod.prep = function (object) {
495   - if (!open) {
496   - return;
497   - }
498   -
499   - var speed = settings.transition === "none" ? 0 : settings.speed;
500   -
501   - $window.unbind('resize.' + prefix);
502   - $loaded.remove();
503   - $loaded = $div('LoadedContent').html(object);
504   -
505   - function getWidth() {
506   - settings.w = settings.w || $loaded.width();
507   - settings.w = settings.mw && settings.mw < settings.w ? settings.mw : settings.w;
508   - return settings.w;
509   - }
510   - function getHeight() {
511   - settings.h = settings.h || $loaded.height();
512   - settings.h = settings.mh && settings.mh < settings.h ? settings.mh : settings.h;
513   - return settings.h;
514   - }
515   -
516   - $loaded.hide()
517   - .appendTo($loadingBay.show())// content has to be appended to the DOM for accurate size calculations.
518   - .css({width: getWidth(), overflow: settings.scrolling ? 'auto' : 'hidden'})
519   - .css({height: getHeight()})// sets the height independently from the width in case the new width influences the value of height.
520   - .prependTo($content);
521   -
522   - $loadingBay.hide();
523   -
524   - // floating the IMG removes the bottom line-height and fixed a problem where IE miscalculates the width of the parent element as 100% of the document width.
525   - //$(photo).css({'float': 'none', marginLeft: 'auto', marginRight: 'auto'});
526   -
527   - $(photo).css({'float': 'none'});
528   -
529   - // Hides SELECT elements in IE6 because they would otherwise sit on top of the overlay.
530   - if (isIE6) {
531   - $('select').not($box.find('select')).filter(function () {
532   - return this.style.visibility !== 'hidden';
533   - }).css({'visibility': 'hidden'}).one(event_cleanup, function () {
534   - this.style.visibility = 'inherit';
535   - });
536   - }
537   -
538   - function setPosition(s) {
539   - publicMethod.position(s, function () {
540   - var prev, prevSrc, next, nextSrc, total = $related.length, iframe, complete;
541   -
542   - if (!open) {
543   - return;
544   - }
545   -
546   - complete = function () {
547   - $loadingOverlay.hide();
548   - trigger(event_complete, settings.onComplete);
549   - };
550   -
551   - if (isIE) {
552   - //This fadeIn helps the bicubic resampling to kick-in.
553   - if (photo) {
554   - $loaded.fadeIn(100);
555   - }
556   - }
557   -
558   - $title.html(settings.title).add($loaded).show();
559   -
560   - if (total > 1) { // handle grouping
561   - if (typeof settings.current === "string") {
562   - $current.html(settings.current.replace(/\{current\}/, index + 1).replace(/\{total\}/, total)).show();
563   - }
564   -
565   - $next[(settings.loop || index < total - 1) ? "show" : "hide"]().html(settings.next);
566   - $prev[(settings.loop || index) ? "show" : "hide"]().html(settings.previous);
567   -
568   - prev = index ? $related[index - 1] : $related[total - 1];
569   - next = index < total - 1 ? $related[index + 1] : $related[0];
570   -
571   - if (settings.slideshow) {
572   - $slideshow.show();
573   - }
574   -
575   - // Preloads images within a rel group
576   - if (settings.preloading) {
577   - nextSrc = $.data(next, colorbox).href || next.href;
578   - prevSrc = $.data(prev, colorbox).href || prev.href;
579   -
580   - nextSrc = $.isFunction(nextSrc) ? nextSrc.call(next) : nextSrc;
581   - prevSrc = $.isFunction(prevSrc) ? prevSrc.call(prev) : prevSrc;
582   -
583   - if (isImage(nextSrc)) {
584   - $('<img/>')[0].src = nextSrc;
585   - }
586   -
587   - if (isImage(prevSrc)) {
588   - $('<img/>')[0].src = prevSrc;
589   - }
590   - }
591   - } else {
592   - $groupControls.hide();
593   - }
594   -
595   - if (settings.iframe) {
596   - iframe = $('<iframe/>').addClass(prefix + 'Iframe')[0];
597   -
598   - if (settings.fastIframe) {
599   - complete();
600   - } else {
601   - $(iframe).load(complete);
602   - }
603   - iframe.name = prefix + (+new Date());
604   - iframe.src = settings.href;
605   -
606   - if (!settings.scrolling) {
607   - iframe.scrolling = "no";
608   - }
609   -
610   - if (isIE) {
611   - iframe.frameBorder=0;
612   - iframe.allowTransparency = "true";
613   - }
614   -
615   - $(iframe).appendTo($loaded).one(event_purge, function () {
616   - iframe.src = "//about:blank";
617   - });
618   - } else {
619   - complete();
620   - }
621   -
622   - if (settings.transition === 'fade') {
623   - $box.fadeTo(speed, 1, function () {
624   - $box[0].style.filter = "";
625   - });
626   - } else {
627   - $box[0].style.filter = "";
628   - }
629   -
630   - $window.bind('resize.' + prefix, function () {
631   - publicMethod.position(0);
632   - });
633   - });
634   - }
635   -
636   - if (settings.transition === 'fade') {
637   - $box.fadeTo(speed, 0, function () {
638   - setPosition(0);
639   - });
640   - } else {
641   - setPosition(speed);
642   - }
643   - };
644   -
645   - publicMethod.load = function (launched) {
646   - var href, setResize, prep = publicMethod.prep;
647   -
648   - active = true;
649   -
650   - photo = false;
651   -
652   - element = $related[index];
653   -
654   - if (!launched) {
655   - process($.extend(settings, $.data(element, colorbox)));
656   - }
657   -
658   - trigger(event_purge);
659   -
660   - trigger(event_load, settings.onLoad);
661   -
662   - settings.h = settings.height ?
663   - setSize(settings.height, 'y') - loadedHeight - interfaceHeight :
664   - settings.innerHeight && setSize(settings.innerHeight, 'y');
665   -
666   - settings.w = settings.width ?
667   - setSize(settings.width, 'x') - loadedWidth - interfaceWidth :
668   - settings.innerWidth && setSize(settings.innerWidth, 'x');
669   -
670   - // Sets the minimum dimensions for use in image scaling
671   - settings.mw = settings.w;
672   - settings.mh = settings.h;
673   -
674   - // Re-evaluate the minimum width and height based on maxWidth and maxHeight values.
675   - // If the width or height exceed the maxWidth or maxHeight, use the maximum values instead.
676   - if (settings.maxWidth) {
677   - settings.mw = setSize(settings.maxWidth, 'x') - loadedWidth - interfaceWidth;
678   - settings.mw = settings.w && settings.w < settings.mw ? settings.w : settings.mw;
679   - }
680   - if (settings.maxHeight) {
681   - settings.mh = setSize(settings.maxHeight, 'y') - loadedHeight - interfaceHeight;
682   - settings.mh = settings.h && settings.h < settings.mh ? settings.h : settings.mh;
683   - }
684   -
685   - href = settings.href;
686   -
687   - $loadingOverlay.show();
688   -
689   - if (settings.inline) {
690   - // Inserts an empty placeholder where inline content is being pulled from.
691   - // An event is bound to put inline content back when ColorBox closes or loads new content.
692   - $div().hide().insertBefore($(href)[0]).one(event_purge, function () {
693   - $(this).replaceWith($loaded.children());
694   - });
695   - prep($(href));
696   - } else if (settings.iframe) {
697   - // IFrame element won't be added to the DOM until it is ready to be displayed,
698   - // to avoid problems with DOM-ready JS that might be trying to run in that iframe.
699   - prep(" ");
700   - } else if (settings.html) {
701   - prep(settings.html);
702   - } else if (isImage(href)) {
703   - $(photo = new Image())
704   - .addClass(prefix + 'Photo')
705   - .error(function () {
706   - settings.title = false;
707   - prep($div('Error').text('This image could not be loaded'));
708   - })
709   - .load(function () {
710   - var percent;
711   - photo.onload = null; //stops animated gifs from firing the onload repeatedly.
712   -
713   - if (settings.scalePhotos) {
714   - setResize = function () {
715   - photo.height -= photo.height * percent;
716   - photo.width -= photo.width * percent;
717   - };
718   - if (settings.mw && photo.width > settings.mw) {
719   - percent = (photo.width - settings.mw) / photo.width;
720   - setResize();
721   - }
722   - if (settings.mh && photo.height > settings.mh) {
723   - percent = (photo.height - settings.mh) / photo.height;
724   - setResize();
725   - }
726   - }
727   -
728   - if (settings.h) {
729   - photo.style.marginTop = Math.max(settings.h - photo.height, 0) / 2 + 'px';
730   - }
731   -
732   - if ($related[1] && (index < $related.length - 1 || settings.loop)) {
733   - photo.style.cursor = 'pointer';
734   - photo.onclick = function () {
735   - publicMethod.next();
736   - };
737   - }
738   -
739   - if (isIE) {
740   - photo.style.msInterpolationMode = 'bicubic';
741   - }
742   -
743   - setTimeout(function () { // A pause because Chrome will sometimes report a 0 by 0 size otherwise.
744   - prep(photo);
745   - }, 1);
746   - });
747   -
748   - setTimeout(function () { // A pause because Opera 10.6+ will sometimes not run the onload function otherwise.
749   - photo.src = href;
750   - }, 1);
751   - } else if (href) {
752   - $loadingBay.load(href, function (data, status, xhr) {
753   - prep(status === 'error' ? $div('Error').text('Request unsuccessful: ' + xhr.statusText) : $(this).contents());
754   - });
755   - }
756   - };
757   -
758   - // Navigates to the next page/image in a set.
759   - publicMethod.next = function () {
760   - if (!active && $related[1] && (index < $related.length - 1 || settings.loop)) {
761   - index = index < $related.length - 1 ? index + 1 : 0;
762   - publicMethod.load();
763   - }
764   - };
765   -
766   - publicMethod.prev = function () {
767   - if (!active && $related[1] && (index || settings.loop)) {
768   - index = index ? index - 1 : $related.length - 1;
769   - publicMethod.load();
770   - }
771   - };
772   -
773   - // Note: to use this within an iframe use the following format: parent.$.fn.colorbox.close();
774   - publicMethod.close = function () {
775   - if (open && !closing) {
776   -
777   - closing = true;
778   -
779   - open = false;
780   -
781   - trigger(event_cleanup, settings.onCleanup);
782   -
783   - $window.unbind('.' + prefix + ' .' + event_ie6);
784   -
785   - $overlay.fadeTo(200, 0);
786   -
787   - $box.stop().fadeTo(300, 0, function () {
788   -
789   - $box.add($overlay).css({'opacity': 1, cursor: 'auto'}).hide();
790   -
791   - trigger(event_purge);
792   -
793   - $loaded.remove();
794   -
795   - setTimeout(function () {
796   - closing = false;
797   - trigger(event_closed, settings.onClosed);
798   - }, 1);
799   - });
800   - }
801   - };
802   -
803   - // A method for fetching the current element ColorBox is referencing.
804   - // returns a jQuery object.
805   - publicMethod.element = function () {
806   - return $(element);
807   - };
808   -
809   - publicMethod.settings = defaults;
810   -
811   - // Initializes ColorBox when the DOM has loaded
812   - $(publicMethod.init);
813   -
814   -}(jQuery, document, this));
815 0 \ No newline at end of file
public/javascripts/comment_form.js
... ... @@ -53,7 +53,7 @@ function save_comment(button) {
53 53 //Comment of reply
54 54 $('#'+ data.render_target).replaceWith(data.html);
55 55 $('#' + data.render_target).effect("highlight", {}, 3000);
56   - $.colorbox.close();
  56 + noosfero.modal.close();
57 57 increment_comment_count(comment_div);
58 58 } else {
59 59 //New comment of article
... ... @@ -64,7 +64,7 @@ function save_comment(button) {
64 64 });
65 65  
66 66 page_comment_form.find('.errorExplanation').remove();
67   - $.colorbox.close();
  67 + noosfero.modal.close();
68 68 increment_comment_count(comment_div);
69 69 }
70 70  
... ...
public/javascripts/jquery.colorbox-min.js 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +/*!
  2 + Colorbox v1.4.36 - 2014-02-01
  3 + jQuery lightbox and modal window plugin
  4 + (c) 2014 Jack Moore - http://www.jacklmoore.com/colorbox
  5 + license: http://www.opensource.org/licenses/mit-license.php
  6 +*/
  7 +(function(e,t,i){function o(i,o,n){var r=t.createElement(i);return o&&(r.id=Z+o),n&&(r.style.cssText=n),e(r)}function n(){return i.innerHeight?i.innerHeight:e(i).height()}function r(e){var t=k.length,i=(z+e)%t;return 0>i?t+i:i}function h(e,t){return Math.round((/%/.test(e)?("x"===t?E.width():n())/100:1)*parseInt(e,10))}function l(e,t){return e.photo||e.photoRegex.test(t)}function s(e,t){return e.retinaUrl&&i.devicePixelRatio>1?t.replace(e.photoRegex,e.retinaSuffix):t}function a(e){"contains"in g[0]&&!g[0].contains(e.target)&&(e.stopPropagation(),g.focus())}function d(){var t,i=e.data(N,Y);null==i?(B=e.extend({},X),console&&console.log&&console.log("Error: cboxElement missing settings object")):B=e.extend({},i);for(t in B)e.isFunction(B[t])&&"on"!==t.slice(0,2)&&(B[t]=B[t].call(N));B.rel=B.rel||N.rel||e(N).data("rel")||"nofollow",B.href=B.href||e(N).attr("href"),B.title=B.title||N.title,"string"==typeof B.href&&(B.href=e.trim(B.href))}function c(i,o){e(t).trigger(i),lt.triggerHandler(i),e.isFunction(o)&&o.call(N)}function u(i){q||(N=i,d(),k=e(N),z=0,"nofollow"!==B.rel&&(k=e("."+et).filter(function(){var t,i=e.data(this,Y);return i&&(t=e(this).data("rel")||i.rel||this.rel),t===B.rel}),z=k.index(N),-1===z&&(k=k.add(N),z=k.length-1)),w.css({opacity:parseFloat(B.opacity),cursor:B.overlayClose?"pointer":"auto",visibility:"visible"}).show(),J&&g.add(w).removeClass(J),B.className&&g.add(w).addClass(B.className),J=B.className,B.closeButton?K.html(B.close).appendTo(y):K.appendTo("<div/>"),U||(U=$=!0,g.css({visibility:"hidden",display:"block"}),H=o(st,"LoadedContent","width:0; height:0; overflow:hidden"),y.css({width:"",height:""}).append(H),O=x.height()+C.height()+y.outerHeight(!0)-y.height(),_=b.width()+T.width()+y.outerWidth(!0)-y.width(),D=H.outerHeight(!0),A=H.outerWidth(!0),B.w=h(B.initialWidth,"x"),B.h=h(B.initialHeight,"y"),H.css({width:"",height:B.h}),Q.position(),c(tt,B.onOpen),P.add(L).hide(),g.focus(),B.trapFocus&&t.addEventListener&&(t.addEventListener("focus",a,!0),lt.one(rt,function(){t.removeEventListener("focus",a,!0)})),B.returnFocus&&lt.one(rt,function(){e(N).focus()})),m())}function f(){!g&&t.body&&(V=!1,E=e(i),g=o(st).attr({id:Y,"class":e.support.opacity===!1?Z+"IE":"",role:"dialog",tabindex:"-1"}).hide(),w=o(st,"Overlay").hide(),F=e([o(st,"LoadingOverlay")[0],o(st,"LoadingGraphic")[0]]),v=o(st,"Wrapper"),y=o(st,"Content").append(L=o(st,"Title"),S=o(st,"Current"),I=e('<button type="button"/>').attr({id:Z+"Previous"}),R=e('<button type="button"/>').attr({id:Z+"Next"}),M=o("button","Slideshow"),F),K=e('<button type="button"/>').attr({id:Z+"Close"}),v.append(o(st).append(o(st,"TopLeft"),x=o(st,"TopCenter"),o(st,"TopRight")),o(st,!1,"clear:left").append(b=o(st,"MiddleLeft"),y,T=o(st,"MiddleRight")),o(st,!1,"clear:left").append(o(st,"BottomLeft"),C=o(st,"BottomCenter"),o(st,"BottomRight"))).find("div div").css({"float":"left"}),W=o(st,!1,"position:absolute; width:9999px; visibility:hidden; display:none; max-width:none;"),P=R.add(I).add(S).add(M),e(t.body).append(w,g.append(v,W)))}function p(){function i(e){e.which>1||e.shiftKey||e.altKey||e.metaKey||e.ctrlKey||(e.preventDefault(),u(this))}return g?(V||(V=!0,R.click(function(){Q.next()}),I.click(function(){Q.prev()}),K.click(function(){Q.close()}),w.click(function(){B.overlayClose&&Q.close()}),e(t).bind("keydown."+Z,function(e){var t=e.keyCode;U&&B.escKey&&27===t&&(e.preventDefault(),Q.close()),U&&B.arrowKey&&k[1]&&!e.altKey&&(37===t?(e.preventDefault(),I.click()):39===t&&(e.preventDefault(),R.click()))}),e.isFunction(e.fn.on)?e(t).on("click."+Z,"."+et,i):e("."+et).live("click."+Z,i)),!0):!1}function m(){var n,r,a,u=Q.prep,f=++at;$=!0,j=!1,N=k[z],d(),c(ht),c(it,B.onLoad),B.h=B.height?h(B.height,"y")-D-O:B.innerHeight&&h(B.innerHeight,"y"),B.w=B.width?h(B.width,"x")-A-_:B.innerWidth&&h(B.innerWidth,"x"),B.mw=B.w,B.mh=B.h,B.maxWidth&&(B.mw=h(B.maxWidth,"x")-A-_,B.mw=B.w&&B.w<B.mw?B.w:B.mw),B.maxHeight&&(B.mh=h(B.maxHeight,"y")-D-O,B.mh=B.h&&B.h<B.mh?B.h:B.mh),n=B.href,G=setTimeout(function(){F.show()},100),B.inline?(a=o(st).hide().insertBefore(e(n)[0]),lt.one(ht,function(){a.replaceWith(H.children())}),u(e(n))):B.iframe?u(" "):B.html?u(B.html):l(B,n)?(n=s(B,n),j=t.createElement("img"),e(j).addClass(Z+"Photo").bind("error",function(){B.title=!1,u(o(st,"Error").html(B.imgError))}).one("load",function(){var t;f===at&&(e.each(["alt","longdesc","aria-describedby"],function(t,i){var o=e(N).attr(i)||e(N).attr("data-"+i);o&&j.setAttribute(i,o)}),B.retinaImage&&i.devicePixelRatio>1&&(j.height=j.height/i.devicePixelRatio,j.width=j.width/i.devicePixelRatio),B.scalePhotos&&(r=function(){j.height-=j.height*t,j.width-=j.width*t},B.mw&&j.width>B.mw&&(t=(j.width-B.mw)/j.width,r()),B.mh&&j.height>B.mh&&(t=(j.height-B.mh)/j.height,r())),B.h&&(j.style.marginTop=Math.max(B.mh-j.height,0)/2+"px"),k[1]&&(B.loop||k[z+1])&&(j.style.cursor="pointer",j.onclick=function(){Q.next()}),j.style.width=j.width+"px",j.style.height=j.height+"px",setTimeout(function(){u(j)},1))}),setTimeout(function(){j.src=n},1)):n&&W.load(n,B.data,function(t,i){f===at&&u("error"===i?o(st,"Error").html(B.xhrError):e(this).contents())})}var w,g,v,y,x,b,T,C,k,E,H,W,F,L,S,M,R,I,K,P,B,O,_,D,A,N,z,j,U,$,q,G,Q,J,V,X={html:!1,photo:!1,iframe:!1,inline:!1,transition:"elastic",speed:300,fadeOut:300,width:!1,initialWidth:"600",innerWidth:!1,maxWidth:!1,height:!1,initialHeight:"450",innerHeight:!1,maxHeight:!1,scalePhotos:!0,scrolling:!0,href:!1,title:!1,rel:!1,opacity:.9,preloading:!0,className:!1,overlayClose:!0,escKey:!0,arrowKey:!0,top:!1,bottom:!1,left:!1,right:!1,fixed:!1,data:void 0,closeButton:!0,fastIframe:!0,open:!1,reposition:!0,loop:!0,slideshow:!1,slideshowAuto:!0,slideshowSpeed:2500,slideshowStart:"start slideshow",slideshowStop:"stop slideshow",photoRegex:/\.(gif|png|jp(e|g|eg)|bmp|ico|webp)((#|\?).*)?$/i,retinaImage:!1,retinaUrl:!1,retinaSuffix:"@2x.$1",current:"image {current} of {total}",previous:"previous",next:"next",close:"close",xhrError:"This content failed to load.",imgError:"This image failed to load.",returnFocus:!0,trapFocus:!0,onOpen:!1,onLoad:!1,onComplete:!1,onCleanup:!1,onClosed:!1},Y="colorbox",Z="cbox",et=Z+"Element",tt=Z+"_open",it=Z+"_load",ot=Z+"_complete",nt=Z+"_cleanup",rt=Z+"_closed",ht=Z+"_purge",lt=e("<a/>"),st="div",at=0,dt={},ct=function(){function e(){clearTimeout(h)}function t(){(B.loop||k[z+1])&&(e(),h=setTimeout(Q.next,B.slideshowSpeed))}function i(){M.html(B.slideshowStop).unbind(s).one(s,o),lt.bind(ot,t).bind(it,e),g.removeClass(l+"off").addClass(l+"on")}function o(){e(),lt.unbind(ot,t).unbind(it,e),M.html(B.slideshowStart).unbind(s).one(s,function(){Q.next(),i()}),g.removeClass(l+"on").addClass(l+"off")}function n(){r=!1,M.hide(),e(),lt.unbind(ot,t).unbind(it,e),g.removeClass(l+"off "+l+"on")}var r,h,l=Z+"Slideshow_",s="click."+Z;return function(){r?B.slideshow||(lt.unbind(nt,n),n()):B.slideshow&&k[1]&&(r=!0,lt.one(nt,n),B.slideshowAuto?i():o(),M.show())}}();e.colorbox||(e(f),Q=e.fn[Y]=e[Y]=function(t,i){var o=this;if(t=t||{},f(),p()){if(e.isFunction(o))o=e("<a/>"),t.open=!0;else if(!o[0])return o;i&&(t.onComplete=i),o.each(function(){e.data(this,Y,e.extend({},e.data(this,Y)||X,t))}).addClass(et),(e.isFunction(t.open)&&t.open.call(o)||t.open)&&u(o[0])}return o},Q.position=function(t,i){function o(){x[0].style.width=C[0].style.width=y[0].style.width=parseInt(g[0].style.width,10)-_+"px",y[0].style.height=b[0].style.height=T[0].style.height=parseInt(g[0].style.height,10)-O+"px"}var r,l,s,a=0,d=0,c=g.offset();if(E.unbind("resize."+Z),g.css({top:-9e4,left:-9e4}),l=E.scrollTop(),s=E.scrollLeft(),B.fixed?(c.top-=l,c.left-=s,g.css({position:"fixed"})):(a=l,d=s,g.css({position:"absolute"})),d+=B.right!==!1?Math.max(E.width()-B.w-A-_-h(B.right,"x"),0):B.left!==!1?h(B.left,"x"):Math.round(Math.max(E.width()-B.w-A-_,0)/2),a+=B.bottom!==!1?Math.max(n()-B.h-D-O-h(B.bottom,"y"),0):B.top!==!1?h(B.top,"y"):Math.round(Math.max(n()-B.h-D-O,0)/2),g.css({top:c.top,left:c.left,visibility:"visible"}),v[0].style.width=v[0].style.height="9999px",r={width:B.w+A+_,height:B.h+D+O,top:a,left:d},t){var u=0;e.each(r,function(e){return r[e]!==dt[e]?(u=t,void 0):void 0}),t=u}dt=r,t||g.css(r),g.dequeue().animate(r,{duration:t||0,complete:function(){o(),$=!1,v[0].style.width=B.w+A+_+"px",v[0].style.height=B.h+D+O+"px",B.reposition&&setTimeout(function(){E.bind("resize."+Z,Q.position)},1),i&&i()},step:o})},Q.resize=function(e){var t;U&&(e=e||{},e.width&&(B.w=h(e.width,"x")-A-_),e.innerWidth&&(B.w=h(e.innerWidth,"x")),H.css({width:B.w}),e.height&&(B.h=h(e.height,"y")-D-O),e.innerHeight&&(B.h=h(e.innerHeight,"y")),e.innerHeight||e.height||(t=H.scrollTop(),H.css({height:"auto"}),B.h=H.height()),H.css({height:B.h}),t&&H.scrollTop(t),Q.position("none"===B.transition?0:B.speed))},Q.prep=function(i){function n(){return B.w=B.w||H.width(),B.w=B.mw&&B.mw<B.w?B.mw:B.w,B.w}function h(){return B.h=B.h||H.height(),B.h=B.mh&&B.mh<B.h?B.mh:B.h,B.h}if(U){var a,d="none"===B.transition?0:B.speed;H.empty().remove(),H=o(st,"LoadedContent").append(i),H.hide().appendTo(W.show()).css({width:n(),overflow:B.scrolling?"auto":"hidden"}).css({height:h()}).prependTo(y),W.hide(),e(j).css({"float":"none"}),a=function(){function i(){e.support.opacity===!1&&g[0].style.removeAttribute("filter")}var n,h,a=k.length,u="frameBorder",f="allowTransparency";U&&(h=function(){clearTimeout(G),F.hide(),c(ot,B.onComplete)},L.html(B.title).add(H).show(),a>1?("string"==typeof B.current&&S.html(B.current.replace("{current}",z+1).replace("{total}",a)).show(),R[B.loop||a-1>z?"show":"hide"]().html(B.next),I[B.loop||z?"show":"hide"]().html(B.previous),ct(),B.preloading&&e.each([r(-1),r(1)],function(){var i,o,n=k[this],r=e.data(n,Y);r&&r.href?(i=r.href,e.isFunction(i)&&(i=i.call(n))):i=e(n).attr("href"),i&&l(r,i)&&(i=s(r,i),o=t.createElement("img"),o.src=i)})):P.hide(),B.iframe?(n=o("iframe")[0],u in n&&(n[u]=0),f in n&&(n[f]="true"),B.scrolling||(n.scrolling="no"),e(n).attr({src:B.href,name:(new Date).getTime(),"class":Z+"Iframe",allowFullScreen:!0,webkitAllowFullScreen:!0,mozallowfullscreen:!0}).one("load",h).appendTo(H),lt.one(ht,function(){n.src="//about:blank"}),B.fastIframe&&e(n).trigger("load")):h(),"fade"===B.transition?g.fadeTo(d,1,i):i())},"fade"===B.transition?g.fadeTo(d,0,function(){Q.position(0,a)}):Q.position(d,a)}},Q.next=function(){!$&&k[1]&&(B.loop||k[z+1])&&(z=r(1),u(k[z]))},Q.prev=function(){!$&&k[1]&&(B.loop||z)&&(z=r(-1),u(k[z]))},Q.close=function(){U&&!q&&(q=!0,U=!1,c(nt,B.onCleanup),E.unbind("."+Z),w.fadeTo(B.fadeOut||0,0),g.stop().fadeTo(B.fadeOut||0,0,function(){g.add(w).css({opacity:1,cursor:"auto"}).hide(),c(ht),H.empty().remove(),setTimeout(function(){q=!1,c(rt,B.onClosed)},1)}))},Q.remove=function(){g&&(g.stop(),e.colorbox.close(),g.stop().remove(),w.remove(),q=!1,g=null,e("."+et).removeData(Y).removeClass(et),e(t).unbind("click."+Z))},Q.element=function(){return e(N)},Q.settings=X)})(jQuery,document,window);
0 8 \ No newline at end of file
... ...
public/javascripts/lightbox.js
... ... @@ -1,232 +0,0 @@
1   -/*
2   -Created By: Chris Campbell
3   -Website: http://particletree.com
4   -Date: 2/1/2006
5   -
6   -Inspired by the lightbox implementation found at http://www.huddletogether.com/projects/lightbox/
7   -*/
8   -
9   -/*-------------------------------GLOBAL VARIABLES------------------------------------*/
10   -
11   -var detect = navigator.userAgent.toLowerCase();
12   -var OS,browser,version,total,thestring;
13   -
14   -/*-----------------------------------------------------------------------------------------------*/
15   -
16   -//Browser detect script origionally created by Peter Paul Koch at http://www.quirksmode.org/
17   -
18   -function getBrowserInfo() {
19   - if (checkIt('konqueror')) {
20   - browser = "Konqueror";
21   - OS = "Linux";
22   - }
23   - else if (checkIt('safari')) browser = "Safari"
24   - else if (checkIt('omniweb')) browser = "OmniWeb"
25   - else if (checkIt('opera')) browser = "Opera"
26   - else if (checkIt('webtv')) browser = "WebTV";
27   - else if (checkIt('icab')) browser = "iCab"
28   - else if (checkIt('msie')) browser = "Internet Explorer"
29   - else if (!checkIt('compatible')) {
30   - browser = "Netscape Navigator"
31   - version = detect.charAt(8);
32   - }
33   - else browser = "An unknown browser";
34   -
35   - if (!version) version = detect.charAt(place + thestring.length);
36   -
37   - if (!OS) {
38   - if (checkIt('linux')) OS = "Linux";
39   - else if (checkIt('x11')) OS = "Unix";
40   - else if (checkIt('mac')) OS = "Mac"
41   - else if (checkIt('win')) OS = "Windows"
42   - else OS = "an unknown operating system";
43   - }
44   -}
45   -
46   -function checkIt(string) {
47   - place = detect.indexOf(string) + 1;
48   - thestring = string;
49   - return place;
50   -}
51   -
52   -/*-----------------------------------------------------------------------------------------------*/
53   -
54   -Event.observe(window, 'load', getBrowserInfo, false);
55   -
56   -var lightbox = Class.create();
57   -
58   -lightbox.prototype = {
59   -
60   - yPos : 0,
61   - xPos : 0,
62   -
63   - initialize: function(ctrl) {
64   - this.content = ctrl.href;
65   - if (ctrl.id != '') {
66   - this.lightbox_className = ctrl.id;
67   - }
68   - ctrl.onclick = function(){return false;};
69   - ctrl.lightbox = this;
70   - },
71   -
72   - // Turn everything on - mainly the IE fixes
73   - activate: function(){
74   - if (browser == 'Internet Explorer'){
75   - this.getScroll();
76   - this.prepareIE('100%', 'hidden');
77   - this.setScroll(0,0);
78   - this.hideSelects('hidden');
79   - }
80   - this.hideObjectsAndEmbeds('hidden');
81   - this.displayLightbox("block");
82   - },
83   -
84   - // Ie requires height to 100% and overflow hidden or else you can scroll down past the lightbox
85   - prepareIE: function(height, overflow){
86   - bod = document.getElementsByTagName('body')[0];
87   - bod.style.height = height;
88   - bod.style.overflow = overflow;
89   -
90   - htm = document.getElementsByTagName('html')[0];
91   - htm.style.height = height;
92   - htm.style.overflow = overflow;
93   - },
94   -
95   - // In IE, select elements hover on top of the lightbox
96   - hideSelects: function(visibility){
97   - selects = document.getElementsByTagName('select');
98   - for(i = 0; i < selects.length; i++) {
99   - selects[i].style.visibility = visibility;
100   - }
101   - },
102   -
103   - // In FF, objects and embeds elements hover on top of the lightbox
104   - hideObjectsAndEmbeds: function(visibility){
105   - var f = function(collection) {
106   - for(i = 0; i < collection.length; i++) {
107   - if (collection[i].style) {
108   - collection[i].style.visibility = visibility;
109   - }
110   - }
111   - };
112   - f(document.getElementsByTagName('object'));
113   - f(document.getElementsByTagName('embed'));
114   - },
115   -
116   - // Taken from lightbox implementation found at http://www.huddletogether.com/projects/lightbox/
117   - getScroll: function(){
118   - if (self.pageYOffset) {
119   - this.yPos = self.pageYOffset;
120   - } else if (document.documentElement && document.documentElement.scrollTop){
121   - this.yPos = document.documentElement.scrollTop;
122   - } else if (document.body) {
123   - this.yPos = document.body.scrollTop;
124   - }
125   - },
126   -
127   - setScroll: function(x, y){
128   - window.scrollTo(x, y);
129   - },
130   -
131   - displayLightbox: function(display){
132   - $('overlay').style.display = display;
133   - $('lightbox').style.display = display;
134   - if(display != 'none') this.loadInfo();
135   - },
136   -
137   - // Begin Ajax request based off of the href of the clicked linked
138   - loadInfo: function() {
139   - var myAjax = new Ajax.Request(
140   - this.content,
141   - {method: 'post', parameters: "", onComplete: this.processInfo.bindAsEventListener(this)}
142   - );
143   -
144   - },
145   -
146   - // Display Ajax response
147   - processInfo: function(response){
148   - info = "<div id='lbContent'><div id='lbBottomBG'><div id='lbTopBG'>" + response.responseText + "</div></div></div>";
149   - new Insertion.Before($('lbLoadMessage'), info)
150   - if (this.lightbox_className) {
151   - $('lightbox').className = "done " + this.lightbox_className;
152   - } else {
153   - $('lightbox').className = "done";
154   - }
155   - this.actions();
156   - },
157   -
158   - // Search through new links within the lightbox, and attach click event
159   - actions: function(){
160   - lbActions = document.getElementsByClassName('lbAction');
161   -
162   - for(i = 0; i < lbActions.length; i++) {
163   - Event.observe(lbActions[i], 'click', this[lbActions[i].rel].bindAsEventListener(this), false);
164   - lbActions[i].onclick = function(){return false;};
165   - }
166   -
167   - },
168   -
169   - // Example of creating your own functionality once lightbox is initiated
170   - insert: function(e){
171   - link = Event.element(e).parentNode;
172   - Element.remove($('lbContent'));
173   -
174   - var myAjax = new Ajax.Request(
175   - link.href,
176   - {method: 'post', parameters: "", onComplete: this.processInfo.bindAsEventListener(this)}
177   - );
178   -
179   - },
180   -
181   - // Example of creating your own functionality once lightbox is initiated
182   - deactivate: function(){
183   - Element.remove($('lbContent'));
184   -
185   - if (browser == "Internet Explorer"){
186   - this.setScroll(0,this.yPos);
187   - this.prepareIE("auto", "auto");
188   - this.hideSelects("visible");
189   - }
190   - this.hideObjectsAndEmbeds("visible");
191   - this.displayLightbox("none");
192   - }
193   -}
194   -
195   -/*-----------------------------------------------------------------------------------------------*/
196   -
197   -jQuery('.lbOn').live('click', function(event) {
198   - if (jQuery('#lbLoadMessage').length == 0)
199   - addLightboxMarkup();
200   - if (this.lightbox == undefined)
201   - valid = new lightbox(this);
202   - else {
203   - removeLightboxMarkup();
204   - addLightboxMarkup();
205   - }
206   -
207   - this.lightbox.activate();
208   -
209   - event.preventDefault();
210   - return false;
211   -});
212   -
213   -// Add in markup necessary to make this work. Basically two divs:
214   -// Overlay holds the shadow
215   -// Lightbox is the centered square that the content is put into.
216   -function addLightboxMarkup() {
217   - bod = document.getElementsByTagName('body')[0];
218   - overlay = document.createElement('div');
219   - overlay.id = 'overlay';
220   - lb = document.createElement('div');
221   - lb.id = 'lightbox';
222   - lb.className = 'loading';
223   - lb.innerHTML = '<div id="lbLoadMessage">' +
224   - '<img src="' + noosfero_root() + '/images/2loading.gif"/>' +
225   - '</div>';
226   - bod.appendChild(overlay);
227   - bod.appendChild(lb);
228   -}
229   -function removeLightboxMarkup() {
230   - Element.remove($('overlay'));
231   - Element.remove($('lightbox'));
232   -}
public/javascripts/modal.js 0 → 100644
... ... @@ -0,0 +1,58 @@
  1 +noosfero.modal = {
  2 +
  3 + watchClass: function() {
  4 + jQuery(function($) {
  5 + $(document).delegate('.modal-toggle', 'click', function() {
  6 + $.colorbox({
  7 + href: $(this).attr('href'),
  8 + maxWidth: $(window).width()-50,
  9 + height: $(window).height()-50,
  10 + open: true,
  11 + close: 'Cancel',
  12 + class: 'modal',
  13 + onComplete: function(bt) {
  14 + var opt = {}, maxH = $(window).height()-50;
  15 + if ($('#cboxLoadedContent *:first').height() > maxH) opt.height = maxH;
  16 + $.colorbox.resize(opt);
  17 + }
  18 + });
  19 + return false;
  20 + });
  21 +
  22 + $(document).delegate('.modal-close', 'click', function() {
  23 + $.colorbox.close();
  24 + return false;
  25 + });
  26 +
  27 + });
  28 + },
  29 +
  30 + inline: function(href, options) {
  31 + href = jQuery(href);
  32 + options = jQuery.extend({
  33 + inline: true, href: href,
  34 + onLoad: function(){ href.show(); },
  35 + onCleanup: function(){ href.hide(); },
  36 + }, options)
  37 +
  38 + jQuery.colorbox(options);
  39 +
  40 + return false;
  41 + },
  42 +
  43 + html: function(html, options) {
  44 + options = jQuery.extend({
  45 + html: html,
  46 + }, options);
  47 +
  48 + jQuery.colorbox(options);
  49 + },
  50 +
  51 + close: function() {
  52 + jQuery.colorbox.close();
  53 + },
  54 +
  55 +};
  56 +
  57 +noosfero.modal.watchClass();
  58 +
... ...
public/javascripts/report-abuse.js
1 1 jQuery(function($) {
2 2 $('.report-abuse-action').live('click', function() {
3 3 if($(this).attr('href')){
4   - $.fn.colorbox({
5   - href: $(this).attr('href'),
  4 + noosfero.modal.inline($(this).attr('href'), {
6 5 innerHeight: '300px',
7 6 innerWidth: '445px'
8 7 });
... ...
public/javascripts/thickbox.js
... ... @@ -1,319 +0,0 @@
1   -/*
2   - * Thickbox 3.1 - One Box To Rule Them All.
3   - * By Cody Lindley (http://www.codylindley.com)
4   - * Copyright (c) 2007 cody lindley
5   - * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
6   -*/
7   -
8   -var tb_pathToImage = "/images/loading.gif";
9   -
10   -/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/
11   -
12   -//on page load call tb_init
13   -jQuery(document).ready(function(){
14   - tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
15   - imgLoader = new Image();// preload image
16   - imgLoader.src = noosfero_root() + tb_pathToImage;
17   -});
18   -
19   -//add thickbox to href & area elements that have a class of .thickbox
20   -function tb_init(domChunk){
21   - jQuery(domChunk).click(function(){
22   - var t = this.title || this.name || null;
23   - var a = this.href || this.alt;
24   - var g = this.rel || false;
25   - tb_show(t,a,g);
26   - this.blur();
27   - return false;
28   - });
29   -}
30   -
31   -function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link
32   -
33   - try {
34   - if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
35   - jQuery("body","html").css({height: "100%", width: "100%"});
36   - jQuery("html").css("overflow","hidden");
37   - if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6
38   - jQuery("body").append("<iframe id='TB_HideSelect'></iframe><div id='TB_overlay'></div><div id='TB_window'></div>");
39   - jQuery("#TB_overlay").click(tb_remove);
40   - }
41   - }else{//all others
42   - if(document.getElementById("TB_overlay") === null){
43   - jQuery("body").append("<div id='TB_overlay'></div><div id='TB_window'></div>");
44   - jQuery("#TB_overlay").click(tb_remove);
45   - }
46   - }
47   -
48   - if(tb_detectMacXFF()){
49   - jQuery("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash
50   - }else{
51   - jQuery("#TB_overlay").addClass("TB_overlayBG");//use background and opacity
52   - }
53   -
54   - if(caption===null){caption="";}
55   - jQuery("body").append("<div id='TB_load'><img src='"+imgLoader.src+"' /></div>");//add loader to the page
56   - jQuery('#TB_load').show();//show loader
57   -
58   - var baseURL;
59   - if(url.indexOf("?")!==-1){ //ff there is a query string involved
60   - baseURL = url.substr(0, url.indexOf("?"));
61   - }else{
62   - baseURL = url;
63   - }
64   -
65   - var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/;
66   - var urlType = baseURL.toLowerCase().match(urlString);
67   -
68   - if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images
69   -
70   - TB_PrevCaption = "";
71   - TB_PrevURL = "";
72   - TB_PrevHTML = "";
73   - TB_NextCaption = "";
74   - TB_NextURL = "";
75   - TB_NextHTML = "";
76   - TB_imageCount = "";
77   - TB_FoundURL = false;
78   - if(imageGroup){
79   - TB_TempArray = jQuery("a[@rel="+imageGroup+"]").get();
80   - for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) {
81   - var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString);
82   - if (!(TB_TempArray[TB_Counter].href == url)) {
83   - if (TB_FoundURL) {
84   - TB_NextCaption = TB_TempArray[TB_Counter].title;
85   - TB_NextURL = TB_TempArray[TB_Counter].href;
86   - TB_NextHTML = "<span id='TB_next'>&nbsp;&nbsp;<a href='#'>Next &gt;</a></span>";
87   - } else {
88   - TB_PrevCaption = TB_TempArray[TB_Counter].title;
89   - TB_PrevURL = TB_TempArray[TB_Counter].href;
90   - TB_PrevHTML = "<span id='TB_prev'>&nbsp;&nbsp;<a href='#'>&lt; Prev</a></span>";
91   - }
92   - } else {
93   - TB_FoundURL = true;
94   - TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length);
95   - }
96   - }
97   - }
98   -
99   - imgPreloader = new Image();
100   - imgPreloader.onload = function(){
101   - imgPreloader.onload = null;
102   -
103   - // Resizing large images - orginal by Christian Montoya edited by me.
104   - var pagesize = tb_getPageSize();
105   - var x = pagesize[0] - 150;
106   - var y = pagesize[1] - 150;
107   - var imageWidth = imgPreloader.width;
108   - var imageHeight = imgPreloader.height;
109   - if (imageWidth > x) {
110   - imageHeight = imageHeight * (x / imageWidth);
111   - imageWidth = x;
112   - if (imageHeight > y) {
113   - imageWidth = imageWidth * (y / imageHeight);
114   - imageHeight = y;
115   - }
116   - } else if (imageHeight > y) {
117   - imageWidth = imageWidth * (y / imageHeight);
118   - imageHeight = y;
119   - if (imageWidth > x) {
120   - imageHeight = imageHeight * (x / imageWidth);
121   - imageWidth = x;
122   - }
123   - }
124   - // End Resizing
125   -
126   - TB_WIDTH = imageWidth + 30;
127   - TB_HEIGHT = imageHeight + 60;
128   - jQuery("#TB_window").append("<a href='' id='TB_ImageOff' title='Close'><img id='TB_Image' src='"+url+"' width='"+imageWidth+"' height='"+imageHeight+"' alt='"+caption+"'/></a>" + "<div id='TB_caption'>"+caption+"<div id='TB_secondLine'>" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "</div></div><div id='TB_closeWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a> or Esc Key</div>");
129   -
130   - jQuery("#TB_closeWindowButton").click(tb_remove);
131   -
132   - if (!(TB_PrevHTML === "")) {
133   - function goPrev(){
134   - if(jQuery(document).unbind("click",goPrev)){jQuery(document).unbind("click",goPrev);}
135   - jQuery("#TB_window").remove();
136   - jQuery("body").append("<div id='TB_window'></div>");
137   - tb_show(TB_PrevCaption, TB_PrevURL, imageGroup);
138   - return false;
139   - }
140   - jQuery("#TB_prev").click(goPrev);
141   - }
142   -
143   - if (!(TB_NextHTML === "")) {
144   - function goNext(){
145   - jQuery("#TB_window").remove();
146   - jQuery("body").append("<div id='TB_window'></div>");
147   - tb_show(TB_NextCaption, TB_NextURL, imageGroup);
148   - return false;
149   - }
150   - jQuery("#TB_next").click(goNext);
151   -
152   - }
153   -
154   - document.onkeydown = function(e){
155   - if (e == null) { // ie
156   - keycode = event.keyCode;
157   - } else { // mozilla
158   - keycode = e.which;
159   - }
160   - if(keycode == 27){ // close
161   - tb_remove();
162   - } else if(keycode == 190){ // display previous image
163   - if(!(TB_NextHTML == "")){
164   - document.onkeydown = "";
165   - goNext();
166   - }
167   - } else if(keycode == 188){ // display next image
168   - if(!(TB_PrevHTML == "")){
169   - document.onkeydown = "";
170   - goPrev();
171   - }
172   - }
173   - };
174   -
175   - tb_position();
176   - jQuery("#TB_load").remove();
177   - jQuery("#TB_ImageOff").click(tb_remove);
178   - jQuery("#TB_window").css({display:"block"}); //for safari using css instead of show
179   - };
180   -
181   - imgPreloader.src = url;
182   - }else{//code to show html
183   -
184   - var queryString = url.replace(/^[^\?]+\??/,'');
185   - var params = tb_parseQuery( queryString );
186   -
187   - TB_WIDTH = (params['width']*1) + 30 || 630; //defaults to 630 if no paramaters were added to URL
188   - TB_HEIGHT = (params['height']*1) + 40 || 440; //defaults to 440 if no paramaters were added to URL
189   - ajaxContentW = TB_WIDTH - 30;
190   - ajaxContentH = TB_HEIGHT - 45;
191   -
192   - if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window
193   - urlNoQuery = url.split('TB_');
194   - jQuery("#TB_iframeContent").remove();
195   - if(params['modal'] != "true"){//iframe no modal
196   - jQuery("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a> or Esc Key</div></div><iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;' > </iframe>");
197   - }else{//iframe modal
198   - jQuery("#TB_overlay").unbind();
199   - jQuery("#TB_window").append("<iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;'> </iframe>");
200   - }
201   - }else{// not an iframe, ajax
202   - if(jQuery("#TB_window").css("display") != "block"){
203   - if(params['modal'] != "true"){//ajax no modal
204   - jQuery("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton'>close</a> or Esc Key</div></div><div id='TB_ajaxContent' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px'></div>");
205   - }else{//ajax modal
206   - jQuery("#TB_overlay").unbind();
207   - jQuery("#TB_window").append("<div id='TB_ajaxContent' class='TB_modal' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px;'></div>");
208   - }
209   - }else{//this means the window is already up, we are just loading new content via ajax
210   - jQuery("#TB_ajaxContent")[0].style.width = ajaxContentW +"px";
211   - jQuery("#TB_ajaxContent")[0].style.height = ajaxContentH +"px";
212   - jQuery("#TB_ajaxContent")[0].scrollTop = 0;
213   - jQuery("#TB_ajaxWindowTitle").html(caption);
214   - }
215   - }
216   -
217   - jQuery("#TB_closeWindowButton").click(tb_remove);
218   -
219   - if(url.indexOf('TB_inline') != -1){
220   - jQuery("#TB_ajaxContent").append(jQuery('#' + params['inlineId']).children());
221   - jQuery("#TB_window").unload(function () {
222   - jQuery('#' + params['inlineId']).append( jQuery("#TB_ajaxContent").children() ); // move elements back when you're finished
223   - });
224   - tb_position();
225   - jQuery("#TB_load").remove();
226   - jQuery("#TB_window").css({display:"block"});
227   - }else if(url.indexOf('TB_iframe') != -1){
228   - tb_position();
229   - if(jQuery.browser.safari){//safari needs help because it will not fire iframe onload
230   - jQuery("#TB_load").remove();
231   - jQuery("#TB_window").css({display:"block"});
232   - }
233   - }else{
234   - jQuery("#TB_ajaxContent").load(url += "&random=" + (new Date().getTime()),function(){//to do a post change this load method
235   - tb_position();
236   - jQuery("#TB_load").remove();
237   - tb_init("#TB_ajaxContent a.thickbox");
238   - jQuery("#TB_window").css({display:"block"});
239   - });
240   - }
241   -
242   - }
243   -
244   - if(!params['modal']){
245   - document.onkeyup = function(e){
246   - if (e == null) { // ie
247   - keycode = event.keyCode;
248   - } else { // mozilla
249   - keycode = e.which;
250   - }
251   - if(keycode == 27){ // close
252   - tb_remove();
253   - }
254   - };
255   - }
256   -
257   - } catch(e) {
258   - //nothing here
259   - }
260   -}
261   -
262   -//helper functions below
263   -function tb_showIframe(){
264   - jQuery("#TB_load").remove();
265   - jQuery("#TB_window").css({display:"block"});
266   -}
267   -
268   -function tb_remove() {
269   - jQuery("#TB_imageOff").unbind("click");
270   - jQuery("#TB_closeWindowButton").unbind("click");
271   - jQuery("#TB_window").fadeOut("fast",function(){jQuery('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();});
272   - jQuery("#TB_load").remove();
273   - if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
274   - jQuery("body","html").css({height: "auto", width: "auto"});
275   - jQuery("html").css("overflow","");
276   - }
277   - document.onkeydown = "";
278   - document.onkeyup = "";
279   - return false;
280   -}
281   -
282   -function tb_position() {
283   -jQuery("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'});
284   - if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6
285   - jQuery("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'});
286   - }
287   -}
288   -
289   -function tb_parseQuery ( query ) {
290   - var Params = {};
291   - if ( ! query ) {return Params;}// return empty object
292   - var Pairs = query.split(/[;&]/);
293   - for ( var i = 0; i < Pairs.length; i++ ) {
294   - var KeyVal = Pairs[i].split('=');
295   - if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
296   - var key = unescape( KeyVal[0] );
297   - var val = unescape( KeyVal[1] );
298   - val = val.replace(/\+/g, ' ');
299   - Params[key] = val;
300   - }
301   - return Params;
302   -}
303   -
304   -function tb_getPageSize(){
305   - var de = document.documentElement;
306   - var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
307   - var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
308   - arrayPageSize = [w,h];
309   - return arrayPageSize;
310   -}
311   -
312   -function tb_detectMacXFF() {
313   - var userAgent = navigator.userAgent.toLowerCase();
314   - if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
315   - return true;
316   - }
317   -}
318   -
319   -
public/stylesheets/application.css
... ... @@ -1901,17 +1901,6 @@ a.button.disabled, input.disabled {
1901 1901 * Block options editor floating window *
1902 1902 ****************************************/
1903 1903  
1904   -/* FIXME This changes broke colorboxes all over the place.
1905   - * Therefore I'm canceling them until they are properly treateda. */
1906   -#cboxLoadedContent {
1907   - background: #FFF;
1908   -/* box-shadow: 0 0 15px #888 inset;
1909   - border-radius: 5px;
1910   - border: 1px solid #777;
1911   - border-left: none;
1912   - border-right: none; */
1913   -}
1914   -
1915 1904 .block-config-options {
1916 1905 padding: 0px 10px 0px 30px;
1917 1906 }
... ...
public/stylesheets/colorbox.css
1 1 /*
2   - ColorBox Core Style:
  2 + Colorbox Core Style:
3 3 The following CSS is consistent between example themes and should not be altered.
4 4 */
5 5 #colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
  6 +#cboxWrapper {max-width:none;}
6 7 #cboxOverlay{position:fixed; width:100%; height:100%;}
7 8 #cboxMiddleLeft, #cboxBottomLeft{clear:left;}
8 9 #cboxContent{position:relative;}
9   -#cboxLoadedContent{overflow:auto;}
  10 +#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
10 11 #cboxTitle{margin:0;}
11   -#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%;}
  12 +#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
12 13 #cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
13   -.cboxPhoto{float:left; margin:auto; border:0; display:block;}
  14 +.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
14 15 .cboxIframe{width:100%; height:100%; display:block; border:0;}
  16 +#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
15 17  
16   -/*
  18 +/*
17 19 User Style:
18   - Change the following styles to modify the appearance of ColorBox. They are
  20 + Change the following styles to modify the appearance of Colorbox. They are
19 21 ordered & tabbed in a way that represents the nesting of the generated HTML.
20 22 */
21 23 #cboxOverlay{background:url(../images/colorbox/overlay.png) repeat 0 0;}
22   -#colorbox{}
23   - #cboxTopLeft{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -100px 0;}
24   - #cboxTopRight{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -129px 0;}
25   - #cboxBottomLeft{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -100px -29px;}
26   - #cboxBottomRight{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -129px -29px;}
  24 +#colorbox{outline:0;}
  25 + #cboxTopLeft{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -101px 0;}
  26 + #cboxTopRight{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -130px 0;}
  27 + #cboxBottomLeft{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -101px -29px;}
  28 + #cboxBottomRight{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -130px -29px;}
27 29 #cboxMiddleLeft{width:21px; background:url(../images/colorbox/controls.png) left top repeat-y;}
28 30 #cboxMiddleRight{width:21px; background:url(../images/colorbox/controls.png) right top repeat-y;}
29 31 #cboxTopCenter{height:21px; background:url(../images/colorbox/border.png) 0 0 repeat-x;}
30 32 #cboxBottomCenter{height:21px; background:url(../images/colorbox/border.png) 0 -29px repeat-x;}
31 33 #cboxContent{background:#fff; overflow:hidden;}
  34 + .cboxIframe{background:#fff;}
32 35 #cboxError{padding:50px; border:1px solid #ccc;}
33 36 #cboxLoadedContent{margin-bottom:28px;}
34 37 #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;}
35 38 #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;}
  39 + #cboxLoadingOverlay{background:url(../images/colorbox/loading_background.png) no-repeat center center;}
  40 + #cboxLoadingGraphic{background:url(../images/colorbox/loading.gif) no-repeat center center;}
  41 +
  42 + /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
  43 + #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; width:auto; background:none; }
  44 +
  45 + /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
  46 + #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
  47 +
36 48 #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;}
37 49 #cboxPrevious{position:absolute; bottom:0; left:0; background:url(../images/colorbox/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;}
38   - #cboxPrevious.hover{background-position:-75px -25px;}
  50 + #cboxPrevious:hover{background-position:-75px -25px;}
39 51 #cboxNext{position:absolute; bottom:0; left:27px; background:url(../images/colorbox/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;}
40   - #cboxNext.hover{background-position:-50px -25px;}
41   - #cboxLoadingOverlay{background:url(../images/colorbox/loading_background.png) no-repeat center center;}
42   - #cboxLoadingGraphic{background:url(../images/colorbox/loading.gif) no-repeat center center;}
  52 + #cboxNext:hover{background-position:-50px -25px;}
43 53 #cboxClose{position:absolute; bottom:0; right:0; background:url(../images/colorbox/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;}
44   - #cboxClose.hover{background-position:-25px -25px;}
  54 + #cboxClose:hover{background-position:-25px -25px;}
45 55  
46 56 /*
47   - The following fixes a problem where IE7+ replaces a PNG's alpha transparency with a black fill
48   - when an alpha filter (opacity change) is set on the element or ancestor element.
  57 + The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
  58 + when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
  59 + See: http://jacklmoore.com/notes/ie-transparency-problems/
49 60 */
50 61 .cboxIE #cboxTopLeft,
51 62 .cboxIE #cboxTopCenter,
... ... @@ -57,26 +68,3 @@
57 68 .cboxIE #cboxMiddleRight {
58 69 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
59 70 }
60   -
61   -/*
62   - The following provides PNG transparency support for IE6
63   -*/
64   -.cboxIE6 #cboxTopLeft{background:url(../images/colorbox/ie6/borderTopLeft.png);}
65   -.cboxIE6 #cboxTopCenter{background:url(../images/colorbox/ie6/borderTopCenter.png);}
66   -.cboxIE6 #cboxTopRight{background:url(../images/colorbox/ie6/borderTopRight.png);}
67   -.cboxIE6 #cboxBottomLeft{background:url(../images/colorbox/ie6/borderBottomLeft.png);}
68   -.cboxIE6 #cboxBottomCenter{background:url(../images/colorbox/ie6/borderBottomCenter.png);}
69   -.cboxIE6 #cboxBottomRight{background:url(../images/colorbox/ie6/borderBottomRight.png);}
70   -.cboxIE6 #cboxMiddleLeft{background:url(../images/colorbox/ie6/borderMiddleLeft.png);}
71   -.cboxIE6 #cboxMiddleRight{background:url(../images/colorbox/ie6/borderMiddleRight.png);}
72   -
73   -.cboxIE6 #cboxTopLeft,
74   -.cboxIE6 #cboxTopCenter,
75   -.cboxIE6 #cboxTopRight,
76   -.cboxIE6 #cboxBottomLeft,
77   -.cboxIE6 #cboxBottomCenter,
78   -.cboxIE6 #cboxBottomRight,
79   -.cboxIE6 #cboxMiddleLeft,
80   -.cboxIE6 #cboxMiddleRight {
81   - _behavior: expression(this.src = this.src ? this.src : this.currentStyle.backgroundImage.split('"')[1], this.style.background = "none", this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + this.src + ", sizingMethod='scale')");
82   -}
... ...
public/stylesheets/lightbox.css
... ... @@ -1,63 +0,0 @@
1   -/* - - - - - - - - - - - - - - - - - - - - -
2   -
3   -Title : Lightbox CSS
4   -Author : Kevin Hale
5   -URL : http://particletree.com/features/lightbox-gone-wild/
6   -
7   -Created : January 13, 2006
8   -Modified : February 1, 2006
9   -
10   -- - - - - - - - - - - - - - - - - - - - - */
11   -
12   -#lightbox {
13   - display: none;
14   - position: absolute;
15   - top: 150px;
16   - left: 50%;
17   - z-index: 300;
18   - width: 500px;
19   - margin-left: -265px;
20   - border: 1px solid #000;
21   - text-align: left;
22   - padding: 1em;
23   - background: #FFF;
24   -}
25   -
26   -#overlay{
27   - display:none;
28   - position:absolute;
29   - top:0;
30   - left:0;
31   - width:100%;
32   - height:100%;
33   - z-index:200;
34   - background-color:#000;
35   - -moz-opacity: 0.75;
36   - opacity:.75;
37   - filter: alpha(opacity=75);
38   -}
39   -#overlay[id]{
40   - position:fixed;
41   -}
42   -
43   -#lightbox.done #lbLoadMessage{
44   - display:none;
45   -}
46   -#lightbox.done #lbContent{
47   - display:block;
48   -}
49   -#lightbox.loading #lbContent{
50   - display:none;
51   -}
52   -#lightbox.loading #lbLoadMessage{
53   - display:block;
54   -}
55   -
56   -#lightbox.done img{
57   - width:100%;
58   - height:100%;
59   -}
60   -
61   -#lightbox select {
62   - max-width: 100%;
63   -}
public/stylesheets/thickbox.css
... ... @@ -1,163 +0,0 @@
1   -/* ----------------------------------------------------------------------------------------------------------------*/
2   -/* ---------->>> global settings needed for thickbox <<<-----------------------------------------------------------*/
3   -/* ----------------------------------------------------------------------------------------------------------------*/
4   -/**{padding: 0; margin: 0;}*/
5   -
6   -/* ----------------------------------------------------------------------------------------------------------------*/
7   -/* ---------->>> thickbox specific link and font settings <<<------------------------------------------------------*/
8   -/* ----------------------------------------------------------------------------------------------------------------*/
9   -#TB_window {
10   - font: 12px Arial, Helvetica, sans-serif;
11   - color: #333333;
12   -}
13   -
14   -#TB_secondLine {
15   - font: 10px Arial, Helvetica, sans-serif;
16   - color:#666666;
17   -}
18   -
19   -#TB_window a:link {color: #666666;}
20   -#TB_window a:visited {color: #666666;}
21   -#TB_window a:hover {color: #000;}
22   -#TB_window a:active {color: #666666;}
23   -#TB_window a:focus{color: #666666;}
24   -
25   -/* ----------------------------------------------------------------------------------------------------------------*/
26   -/* ---------->>> thickbox settings <<<-----------------------------------------------------------------------------*/
27   -/* ----------------------------------------------------------------------------------------------------------------*/
28   -#TB_overlay {
29   - position: fixed;
30   - z-index:200;
31   - top: 0px;
32   - left: 0px;
33   - height:100%;
34   - width:100%;
35   -}
36   -
37   -.TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;}
38   -.TB_overlayBG {
39   - background-color:#000;
40   - filter:alpha(opacity=75);
41   - -moz-opacity: 0.75;
42   - opacity: 0.75;
43   -}
44   -
45   -* html #TB_overlay { /* ie6 hack */
46   - position: absolute;
47   - height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
48   -}
49   -
50   -#TB_window {
51   - position: fixed;
52   - background: white;
53   - z-index: 202;
54   - color:#000000;
55   - display:none;
56   - border: 1px solid #000;
57   - text-align:left;
58   - top:50%;
59   - left:50%;
60   -}
61   -
62   -* html #TB_window { /* ie6 hack */
63   -position: absolute;
64   -margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
65   -}
66   -
67   -#TB_window img#TB_Image {
68   - display:block;
69   - margin: 15px 0 0 15px;
70   - border-right: 1px solid #ccc;
71   - border-bottom: 1px solid #ccc;
72   - border-top: 1px solid #666;
73   - border-left: 1px solid #666;
74   -}
75   -
76   -#TB_caption{
77   - height:25px;
78   - padding:7px 30px 10px 25px;
79   - float:left;
80   -}
81   -
82   -#TB_closeWindow{
83   - height:25px;
84   - padding:11px 25px 10px 0;
85   - float:right;
86   -}
87   -
88   -#TB_closeAjaxWindow{
89   - padding:7px 10px 5px 0;
90   - margin-bottom:1px;
91   - text-align:right;
92   - float:right;
93   -}
94   -
95   -#TB_ajaxWindowTitle{
96   - float:left;
97   - padding:7px 0 5px 10px;
98   - margin-bottom:1px;
99   -}
100   -
101   -#TB_title{
102   - background-color:#e8e8e8;
103   - height:27px;
104   -}
105   -
106   -#TB_ajaxContent{
107   - clear:both;
108   - padding:2px 15px 15px 15px;
109   - overflow:auto;
110   - text-align:left;
111   - line-height:1.4em;
112   -}
113   -
114   -#TB_ajaxContent.TB_modal{
115   - padding:15px;
116   -}
117   -
118   -#TB_ajaxContent p{
119   - padding:5px 0px 5px 0px;
120   -}
121   -
122   -#TB_load{
123   - position: fixed;
124   - display:none;
125   - height:13px;
126   - width:208px;
127   - z-index:203;
128   - top: 50%;
129   - left: 50%;
130   - margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
131   -}
132   -
133   -* html #TB_load { /* ie6 hack */
134   -position: absolute;
135   -margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
136   -}
137   -
138   -#TB_HideSelect{
139   - z-index:199;
140   - position:fixed;
141   - top: 0;
142   - left: 0;
143   - background-color:#fff;
144   - border:none;
145   - filter:alpha(opacity=0);
146   - -moz-opacity: 0;
147   - opacity: 0;
148   - height:100%;
149   - width:100%;
150   -}
151   -
152   -* html #TB_HideSelect { /* ie6 hack */
153   - position: absolute;
154   - height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
155   -}
156   -
157   -#TB_iframeContent{
158   - clear:both;
159   - border:none;
160   - margin-bottom:-1px;
161   - margin-top:1px;
162   - _margin-bottom:1px;
163   -}
script/gitlab-ci 0 → 100755
... ... @@ -0,0 +1,56 @@
  1 +#!/usr/bin/env ruby
  2 +
  3 +# These just forward the signals to the whole process group and
  4 +# then immediately exit.
  5 +pgid = Process.getpgid Process.pid
  6 +Signal.trap(:TERM) { Process.kill(:TERM, -pgid); exit }
  7 +Signal.trap(:INT) { Process.kill(:INT, -pgid); exit }
  8 +
  9 +def run command, options = {}
  10 + command = "#{command} 2>&1 > /dev/null" if options[:output] == false
  11 + #command = "time #{command}" unless options[:runtime] == false
  12 + puts "== #{command}"
  13 + system command
  14 +end
  15 +
  16 +@id = (0...10).map{ ('a'..'z').to_a[rand(26)] }.join
  17 +@db = "gitlab-ci-#{@id}"
  18 +
  19 +def config
  20 + require 'yaml'
  21 + db_config = {
  22 + 'adapter' => 'postgresql', 'encoding' => 'unicode',
  23 + 'database' => @db, 'username' => ENV['USER'],
  24 + }
  25 + File.write 'config/database.yml', YAML.dump('test' => db_config, 'development' => db_config)
  26 +end
  27 +
  28 +def prepare
  29 + run("createdb #{@db}") and
  30 + run('mkdir -p tmp/pids log') and
  31 + run('bundle check || bundle install') and
  32 + run('rake db:schema:load', output: false) and
  33 + run('script/noosfero-plugins disableall') and
  34 + run('rake db:migrate')
  35 +end
  36 +
  37 +def test
  38 + %w[
  39 + test:units
  40 + test:functionals
  41 + test:integration
  42 + cucumber
  43 + test:noosfero_plugins
  44 + ].each do |task|
  45 + run "rake #{task}"
  46 + end
  47 +end
  48 +
  49 +def cleanup
  50 + run "dropdb #{@db}"
  51 +end
  52 +
  53 +ret = config and prepare and test
  54 +cleanup
  55 +
  56 +exit (if ret == true then 0 else 1 end)
... ...
script/install-dependencies/debian-squeeze.sh
... ... @@ -5,7 +5,7 @@ run sudo apt-get -y install $runtime_dependencies
5 5 sudo apt-get -y install iceweasel || sudo apt-get -y install firefox
6 6  
7 7 # needed for development
8   -run sudo apt-get -y install libtidy-ruby libhpricot-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev postgresql openjdk-6-jre
  8 +run sudo apt-get -y install libtidy-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev postgresql openjdk-6-jre
9 9 gem which bundler >/dev/null 2>&1 || gem_install bundler
10 10 setup_rubygems_path
11 11 run bundle install
... ...
test/functional/account_controller_test.rb
... ... @@ -818,17 +818,17 @@ class AccountControllerTest &lt; ActionController::TestCase
818 818 end
819 819  
820 820 should 'login with an alternative authentication defined by plugin' do
  821 + user = create_user
821 822 class Plugin1 < Noosfero::Plugin
822   - def alternative_authentication
823   - User.new(:login => 'testuser')
824   - end
825 823 end
  824 + Plugin1.send(:define_method, :alternative_authentication){ user }
  825 +
826 826 Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
827 827 Environment.default.enable_plugin(Plugin1.name)
828 828  
829 829 post :login, :user => {:login => "testuser"}
830 830  
831   - assert_equal 'testuser', assigns(:current_user).login
  831 + assert_equal user.login, assigns(:current_user).login
832 832 assert_response :redirect
833 833 end
834 834  
... ...
test/functional/chat_controller_test.rb
... ... @@ -6,18 +6,20 @@ class ChatControllerTest &lt; ActionController::TestCase
6 6 env = Environment.default
7 7 env.enable('xmpp_chat')
8 8 env.save!
  9 + #TODO Maybe someday we should have a real testing ejabberd server
  10 + RubyBOSH.stubs(:initialize_session).returns(['fake-jid@example.org', 'fake-sid', 'fake-rid'])
9 11 @person = create_user('testuser').person
10 12 end
11 13  
12 14 should 'cant view chat when not logged in' do
13   - get :index
  15 + get :start_session
14 16 assert_response 302
15 17 end
16 18  
17 19 should 'can view chat when logged in' do
18 20 login_as 'testuser'
19 21  
20   - get :index
  22 + get :start_session
21 23 assert_response :success
22 24 end
23 25  
... ... @@ -39,29 +41,6 @@ class ChatControllerTest &lt; ActionController::TestCase
39 41 assert @response.body.index('PNG')
40 42 end
41 43  
42   - should 'auto connect if last presence status is blank' do
43   - login_as 'testuser'
44   -
45   - get :index
46   - assert_template 'auto_connect_online'
47   - end
48   -
49   - should 'auto connect if there last presence status was chat' do
50   - create_user('testuser_online', :last_chat_status => 'chat')
51   - login_as 'testuser_online'
52   -
53   - get :index
54   - assert_template 'auto_connect_online'
55   - end
56   -
57   - should 'auto connect busy if last presence status was dnd' do
58   - create_user('testuser_busy', :last_chat_status => 'dnd')
59   - login_as 'testuser_busy'
60   -
61   - get :index
62   - assert_template 'auto_connect_busy'
63   - end
64   -
65 44 begin
66 45 require 'ruby_bosh'
67 46 should 'try to start xmpp session' do
... ... @@ -87,7 +66,7 @@ class ChatControllerTest &lt; ActionController::TestCase
87 66 env.disable('xmpp_chat')
88 67 env.save!
89 68  
90   - get :index
  69 + get :start_session
91 70  
92 71 assert_response 404
93 72 assert_template 'not_found'
... ... @@ -116,4 +95,67 @@ class ChatControllerTest &lt; ActionController::TestCase
116 95 assert_not_equal chat_status_at, @person.user.chat_status_at
117 96 end
118 97  
  98 + should 'toggle chat status' do
  99 + login_as 'testuser'
  100 +
  101 + get :start_session
  102 + assert_nil session[:chat][:status]
  103 +
  104 + get :toggle
  105 + assert_equal 'opened', session[:chat][:status]
  106 +
  107 + get :toggle
  108 + assert_equal 'closed', session[:chat][:status]
  109 +
  110 + get :toggle
  111 + assert_equal 'opened', session[:chat][:status]
  112 + end
  113 +
  114 + should 'set tab' do
  115 + login_as 'testuser'
  116 + get :start_session
  117 +
  118 + post :tab, :tab_id => 'my_tab'
  119 + assert_equal 'my_tab', session[:chat][:tab_id]
  120 + end
  121 +
  122 + should 'join room' do
  123 + login_as 'testuser'
  124 + get :start_session
  125 +
  126 + post :join, :room_id => 'room1'
  127 + assert_equivalent ['room1'], session[:chat][:rooms]
  128 +
  129 + post :join, :room_id => 'room2'
  130 + assert_equivalent ['room1', 'room2'], session[:chat][:rooms]
  131 +
  132 + post :join, :room_id => 'room1'
  133 + assert_equivalent ['room1', 'room2'], session[:chat][:rooms]
  134 + end
  135 +
  136 + should 'leave room' do
  137 + login_as 'testuser'
  138 + get :start_session
  139 + session[:chat][:rooms] = ['room1', 'room2']
  140 +
  141 + post :leave, :room_id => 'room2'
  142 + assert_equivalent ['room1'], session[:chat][:rooms]
  143 +
  144 + post :leave, :room_id => 'room1'
  145 + assert_equivalent [], session[:chat][:rooms]
  146 +
  147 + post :leave, :room_id => 'room1'
  148 + assert_equivalent [], session[:chat][:rooms]
  149 + end
  150 +
  151 + should 'fetch chat session as json' do
  152 + login_as 'testuser'
  153 + get :start_session
  154 + my_chat = {:status => 'opened', :rooms => ['room1', 'room2'], :tab_id => 'room1'}
  155 + session[:chat] = my_chat
  156 +
  157 + get :my_session
  158 + assert_equal @response.body, my_chat.to_json
  159 + end
  160 +
119 161 end
... ...
test/functional/cms_controller_test.rb
... ... @@ -638,7 +638,7 @@ class CmsControllerTest &lt; ActionController::TestCase
638 638  
639 639 should 'display OK button on why_categorize popup' do
640 640 get :why_categorize, :profile => profile.identifier
641   - assert_tag :tag => 'a', :attributes => { :rel => 'deactivate'} # lightbox close button
  641 + assert_tag :tag => 'a', :attributes => { :rel => 'deactivate'} # modal close button
642 642 end
643 643  
644 644 should 'display published option' do
... ... @@ -663,8 +663,8 @@ class CmsControllerTest &lt; ActionController::TestCase
663 663 should 'be able to add image with alignment' do
664 664 post :new, :type => 'TinyMceArticle', :profile => profile.identifier, :article => { :name => 'image-alignment', :body => "the text of the article with image <img src='#' align='right'/> right align..." }
665 665 saved = TinyMceArticle.find_by_name('image-alignment')
666   - assert_match /<img.*src="#".*\/>/, saved.body
667   - assert_match /<img.*align="right".*\/>/, saved.body
  666 + assert_match /<img.*src="#".*>/, saved.body
  667 + assert_match /<img.*align="right".*>/, saved.body
668 668 end
669 669  
670 670 should 'be able to add image with alignment when textile' do
... ...
test/functional/profile_editor_controller_test.rb
... ... @@ -500,7 +500,7 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase
500 500 xhr :get, :update_categories, :profile => profile.identifier, :category_id => top.id
501 501 assert_template 'shared/update_categories'
502 502 assert_equal top, assigns(:current_category)
503   - assert_equal [c1, c2], assigns(:categories)
  503 + assert_equivalent [c1, c2], assigns(:categories)
504 504 end
505 505  
506 506 should 'display manage my groups button for person' do
... ...
test/test_helper.rb
... ... @@ -3,7 +3,6 @@ ENV[&quot;RAILS_ENV&quot;] = &quot;test&quot;
3 3 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
4 4 require 'rails/test_help'
5 5 require 'mocha'
6   -require 'hpricot'
7 6  
8 7 require 'noosfero/test'
9 8 require 'authenticated_test_helper'
... ...
test/unit/application_helper_test.rb
... ... @@ -261,7 +261,7 @@ class ApplicationHelperTest &lt; ActionView::TestCase
261 261 fast_create(Community, :is_template => true, :environment_id => environment.id)
262 262 environment.community_default_template= community
263 263 environment.save
264   -
  264 +
265 265 assert_tag_in_string template_options(:communities, 'community'), :tag => 'input',
266 266 :attributes => { :name => "community[template_id]", :value => community.id, :checked => true }
267 267 end
... ... @@ -273,7 +273,7 @@ class ApplicationHelperTest &lt; ActionView::TestCase
273 273 fast_create(Person, :is_template => true, :environment_id => environment.id)
274 274 environment.person_default_template= person
275 275 environment.save
276   -
  276 +
277 277 assert_tag_in_string template_options(:people, 'profile_data'), :tag => 'input',
278 278 :attributes => { :name => "profile_data[template_id]", :value => person.id, :checked => true }
279 279 end
... ... @@ -287,7 +287,7 @@ class ApplicationHelperTest &lt; ActionView::TestCase
287 287 environment.enterprise_default_template= enterprise
288 288 environment.save
289 289 environment.reload
290   -
  290 +
291 291 assert_tag_in_string template_options(:enterprises, 'create_enterprise'), :tag => 'input',
292 292 :attributes => { :name => "create_enterprise[template_id]", :value => enterprise.id, :checked => true }
293 293 end
... ... @@ -734,16 +734,16 @@ class ApplicationHelperTest &lt; ActionView::TestCase
734 734 <div class='macro nonEdit' data-macro='unexistent' data-macro-param='987'></div>
735 735 "
736 736 parsed_html = convert_macro(html, mock())
737   - parsed_divs = Hpricot(parsed_html).search('div')
738   - expected_divs = Hpricot("
739   - <div data-macro='#{macro1_name}' class='parsed-macro #{macro1_name}'>Test1</div>
740   - <div data-macro='#{macro2_name}' class='parsed-macro #{macro2_name}'>Test2</div>
  737 + parsed_divs = Nokogiri::HTML.fragment(parsed_html).css('div')
  738 + expected_divs = Nokogiri::HTML.fragment("
  739 + <div class='parsed-macro #{macro1_name}' data-macro='#{macro1_name}'>Test1</div>
  740 + <div class='parsed-macro #{macro2_name}' data-macro='#{macro2_name}'>Test2</div>
741 741 <div data-macro='unexistent' class='failed-macro unexistent'>Unsupported macro unexistent!</div>
742   - ").search('div')
  742 + ").css('div')
743 743  
744 744 # comparing div attributes between parsed and expected html
745 745 parsed_divs.each_with_index do |div, i|
746   - assert_equal expected_divs[i].attributes.to_hash, div.attributes.to_hash
  746 + assert_equal expected_divs[i].attributes.to_xml, div.attributes.to_xml
747 747 assert_equal expected_divs[i].inner_text, div.inner_text
748 748 end
749 749 end
... ...
test/unit/colorbox_helper_test.rb
... ... @@ -1,36 +0,0 @@
1   -require_relative "../test_helper"
2   -
3   -class ColorboxHelperTest < ActiveSupport::TestCase
4   -
5   - include ColorboxHelper
6   -
7   - should 'provide the needed files' do
8   - assert File.exists?(Rails.root.join('public', 'stylesheets', 'colorbox.css')), 'colorbox.css expected to be in public/stylesheets, but not found'
9   - assert File.exists?(Rails.root.join('public', 'javascripts', 'colorbox.js')), 'colorbox.js expected to be in public/javascripts, but not found'
10   - end
11   -
12   - should 'provide link to close colorbox' do
13   - expects(:button).with(:close, 'text', '#', has_entries({ :class => 'colorbox-close', :id => 'my-id' })).returns('[close-colorbox]')
14   -
15   - assert_equal '[close-colorbox]', colorbox_close_button('text', :id => 'my-id')
16   - end
17   -
18   - should 'merge existing :class option in colorbox_close_button' do
19   - expects(:button).with(:close, 'text', '#', has_entries({ :class => 'colorbox-close my-class', :id => 'my-id' })).returns('[close-colorbox]')
20   -
21   - assert_equal '[close-colorbox]', colorbox_close_button('text', :class => 'my-class', :id => 'my-id' )
22   - end
23   -
24   - should 'provide colorbox_button' do
25   - expects(:button).with('type', 'label', { :action => 'popup'}, has_entries({ :class => 'colorbox' })).returns('[button]')
26   -
27   - assert_equal '[button]', colorbox_button('type', 'label', { :action => 'popup'})
28   - end
29   -
30   - should 'provide colorbox_icon_button' do
31   - expects(:icon_button).with('type', 'label', { :action => 'popup'}, has_entries({ :class => 'colorbox' })).returns('[button]')
32   -
33   - assert_equal '[button]', colorbox_icon_button('type', 'label', { :action => 'popup'})
34   - end
35   -
36   -end
test/unit/comment_helper_test.rb
... ... @@ -137,7 +137,7 @@ class CommentHelperTest &lt; ActiveSupport::TestCase
137 137 plugin_action = {:link => 'plugin_action', :action_bar => true}
138 138 @plugins.stubs(:dispatch).returns([plugin_action])
139 139 html = comment_actions(comment)
140   - assert_match /plugin_action/, Hpricot(html).search('.comments-action-bar').html
  140 + assert_match /plugin_action/, Nokogiri::HTML.fragment(html).css('.comments-action-bar').to_html
141 141 end
142 142  
143 143 def link_to_function(content, url, options = {})
... ...
test/unit/external_feed_test.rb
... ... @@ -18,7 +18,8 @@ class ExternalFeedTest &lt; ActiveSupport::TestCase
18 18 end
19 19  
20 20 should 'not add same item twice' do
21   - e = create(:external_feed)
  21 + blog = create_blog
  22 + e = create(:external_feed, blog: blog)
22 23 assert e.add_item('Article title', 'http://orig.link.invalid', Time.now, 'Content for external post')
23 24 assert !e.add_item('Article title', 'http://orig.link.invalid', Time.now, 'Content for external post')
24 25 assert_equal 1, e.blog.posts.size
... ... @@ -52,7 +53,8 @@ class ExternalFeedTest &lt; ActiveSupport::TestCase
52 53  
53 54 should 'add items to blog as posts' do
54 55 handler = FeedHandler.new
55   - e = create(:external_feed)
  56 + blog = create_blog
  57 + e = create(:external_feed, blog: blog)
56 58 handler.process(e)
57 59 assert_equal ["Last POST", "Second POST", "First POST"], e.blog.posts.map{|i| i.title}
58 60 end
... ... @@ -164,7 +166,7 @@ class ExternalFeedTest &lt; ActiveSupport::TestCase
164 166 next if a.kind_of?(RssFeed)
165 167 dd << a.body.to_s.strip.gsub(/\s+/, ' ')
166 168 end
167   - assert_equal '<img src="noosfero.png" /><p>Html content 1.</p><p>Html content 2.</p>', dd.sort.join
  169 + assert_equal '<img src="noosfero.png"><p>Html content 1.</p><p>Html content 2.</p>', dd.sort.join
168 170 end
169 171  
170 172 should 'use feed title as author name' do
... ...
test/unit/lightbox_helper_test.rb
... ... @@ -1,65 +0,0 @@
1   -require_relative "../test_helper"
2   -
3   -class LightboxHelperTest < ActiveSupport::TestCase
4   -
5   - include LightboxHelper
6   -
7   - def setup
8   - stubs(:_).with(anything).returns('TEXT')
9   - end
10   -
11   - should 'provide the needed files' do
12   - assert File.exists?(Rails.root.join('public', 'stylesheets', 'lightbox.css')), 'lightbox.css expected to be in public/stylesheets, but not found'
13   - assert File.exists?(Rails.root.join('public', 'javascripts', 'lightbox.js')), 'lightbox.js expected to be in public/javascripts, but not found'
14   - end
15   -
16   - should 'provide lightbox_link_to helper' do
17   - expects(:link_to).with('text', { :action => 'view', :id => '1' }, has_entries({ :class => 'lbOn', :id => 'my-link' })).returns('[link]')
18   - assert_equal '[link]', lightbox_link_to('text', { :action => 'view', :id => '1'}, { :id => 'my-link' })
19   - end
20   -
21   - should 'merge existing :class option in lightbox_link_to' do
22   - expects(:link_to).with('text', { :action => 'view', :id => '1' }, has_entries({ :class => 'lbOn my-button', :id => 'my-link' })).returns('[link]')
23   - assert_equal '[link]', lightbox_link_to('text', { :action => 'view', :id => '1'}, { :class => 'my-button', :id => 'my-link' })
24   -
25   - end
26   -
27   - should 'provide link to close lightbox' do
28   - expects(:button).with(:close, 'text', '#', has_entries({ :class => 'lbAction', :rel => 'deactivate', :id => 'my-id' })).returns('[close-lightbox]')
29   -
30   - assert_equal '[close-lightbox]', lightbox_close_button('text', :id => 'my-id')
31   - end
32   -
33   - should 'merge existing :class option in lightbox_close_button' do
34   - expects(:button).with(:close, 'text', '#', has_entries({ :class => 'lbAction my-class', :rel => 'deactivate', :id => 'my-id' })).returns('[close-lightbox]')
35   -
36   - assert_equal '[close-lightbox]', lightbox_close_button('text', :class => 'my-class', :id => 'my-id' )
37   - end
38   -
39   - should 'provide lightbox_button' do
40   - expects(:button).with('type', 'label', { :action => 'popup'}, has_entries({ :class => 'lbOn' })).returns('[button]')
41   -
42   - assert_equal '[button]', lightbox_button('type', 'label', { :action => 'popup'})
43   - end
44   -
45   - should 'provide lightbox_icon_button' do
46   - expects(:icon_button).with('type', 'label', { :action => 'popup'}, has_entries({ :class => 'lbOn' })).returns('[button]')
47   -
48   - assert_equal '[button]', lightbox_icon_button('type', 'label', { :action => 'popup'})
49   - end
50   -
51   - should 'tell if rendering inside lightbox' do
52   - request = mock
53   - expects(:request).returns(request)
54   - request.expects(:xhr?).returns(true)
55   -
56   - assert lightbox?
57   - end
58   -
59   - should 'provide lightbox_remote_button' do
60   - expects(:button).with('type', 'label', { :action => 'popup'}, has_entries({ :class => 'remote-lbOn' })).returns('[button]')
61   -
62   - assert_equal '[button]', lightbox_remote_button('type', 'label', { :action => 'popup'})
63   - end
64   -
65   -end
test/unit/macro_test.rb
... ... @@ -15,7 +15,7 @@ class MacroTest &lt; ActiveSupport::TestCase
15 15  
16 16 def setup
17 17 @macro = Plugin1::Macro.new
18   - @macro_element = Hpricot(MACRO).search('.macro').first
  18 + @macro_element = Nokogiri::HTML.fragment(MACRO).css('.macro').first
19 19 end
20 20  
21 21 attr_reader :macro, :macro_element
... ...
test/unit/modal_helper_test.rb 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +require_relative '../test_helper'
  2 +
  3 +class ModalHelperTest < ActiveSupport::TestCase
  4 +
  5 + include ModalHelper
  6 +
  7 + should 'provide the needed files' do
  8 + assert File.exists?(Rails.root.join('public', 'stylesheets', 'colorbox.css')), 'colorbox.css expected to be in public/stylesheets, but not found'
  9 + assert File.exists?(Rails.root.join('public', 'javascripts', 'jquery.colorbox-min.js')), 'jquery.colorbox-min.js expected to be in public/javascripts, but not found'
  10 + end
  11 +
  12 + should 'provide link to close modal' do
  13 + expects(:button).with(:close, 'text', '#', has_entries({ :class => 'modal-toggle modal-close', :id => 'my-id' })).returns('[close-modal]')
  14 +
  15 + assert_equal '[close-modal]', modal_close_button('text', :id => 'my-id')
  16 + end
  17 +
  18 + should 'merge existing :class option in modal_close_button' do
  19 + expects(:button).with(:close, 'text', '#', has_entries({ :class => 'modal-toggle modal-close my-class', :id => 'my-id' })).returns('[close-modal]')
  20 +
  21 + assert_equal '[close-modal]', modal_close_button('text', :class => 'my-class', :id => 'my-id' )
  22 + end
  23 +
  24 + should 'provide modal_button' do
  25 + expects(:button).with('type', 'label', { :action => 'popup'}, has_entries({ :class => 'modal-toggle' })).returns('[button]')
  26 +
  27 + assert_equal '[button]', modal_button('type', 'label', { :action => 'popup'})
  28 + end
  29 +
  30 + should 'provide modal_icon_button' do
  31 + expects(:icon_button).with('type', 'label', { :action => 'popup'}, has_entries({ :class => 'modal-toggle' })).returns('[button]')
  32 +
  33 + assert_equal '[button]', modal_icon_button('type', 'label', { :action => 'popup'})
  34 + end
  35 +
  36 +end
... ...
test/unit/person_notifier_test.rb
... ... @@ -225,6 +225,35 @@ class PersonNotifierTest &lt; ActiveSupport::TestCase
225 225 assert !jobs.select {|j| !j.failed? && j.last_error.nil? }.empty?
226 226 end
227 227  
  228 + should 'render image tags for both internal and external src' do
  229 + @community.add_member(@member)
  230 + process_delayed_job_queue
  231 + notify
  232 + sent = ActionMailer::Base.deliveries.last
  233 + assert_match /src="\/\/www.gravatar.com\/avatar.*"/, sent.body.to_s
  234 + assert_match /src="http:\/\/.*\/images\/icons-app\/community-icon.png.*"/, sent.body.to_s
  235 + end
  236 +
  237 + should 'do not raise errors in NotifyJob failure to avoid loop' do
  238 + Delayed::Worker.max_attempts = 1
  239 + Delayed::Job.enqueue(PersonNotifier::NotifyJob.new(@member.id))
  240 +
  241 + PersonNotifier.any_instance.stubs(:notify).raises('error')
  242 + PersonNotifier.any_instance.stubs(:dispatch_notification_mail).raises('error')
  243 +
  244 + process_delayed_job_queue
  245 + jobs = PersonNotifier::NotifyJob.find(@member.id)
  246 + assert jobs.select {|j| !j.failed? && j.last_error.nil? }.empty?
  247 + end
  248 +
  249 + should 'list tasks in notification mail' do
  250 + task = @member.tasks.create!
  251 + process_delayed_job_queue
  252 + notify
  253 + sent = ActionMailer::Base.deliveries.last
  254 + assert_match /href=".*\/myprofile\/member\/tasks"/, sent.body.to_s
  255 + end
  256 +
228 257 private
229 258  
230 259 def notify
... ...
test/unit/product_test.rb
... ... @@ -492,7 +492,7 @@ class ProductTest &lt; ActiveSupport::TestCase
492 492 :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => false)
493 493 assert_equal 25, prod.percentage_from_solidarity_economy.first
494 494  
495   - prod = fast_create(Product, :name => 'test product1', :product_category_id => @product_category.id, :enterprise_id => @profile.id)
  495 + prod = fast_create(Product, :name => 'test product1', :product_category_id => @product_category.id, :profile_id => @profile.id)
496 496 prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id,
497 497 :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => true)
498 498 prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id,
... ... @@ -503,7 +503,7 @@ class ProductTest &lt; ActiveSupport::TestCase
503 503 :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => false)
504 504 assert_equal 75, prod.percentage_from_solidarity_economy.first
505 505  
506   - prod = fast_create(Product, :name => 'test product', :product_category_id => @product_category.id, :enterprise_id => @profile.id)
  506 + prod = fast_create(Product, :name => 'test product', :product_category_id => @product_category.id, :profile_id => @profile.id)
507 507 prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id,
508 508 :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => true)
509 509 assert_equal 100, prod.percentage_from_solidarity_economy.first
... ...
test/unit/text_article_test.rb
1 1 require_relative "../test_helper"
2 2  
3 3 class TextArticleTest < ActiveSupport::TestCase
4   -
  4 +
5 5 # mostly dummy test. Can be removed when (if) there are real tests for this
6   - # this class.
  6 + # this class.
7 7 should 'inherit from Article' do
8 8 assert_kind_of Article, TextArticle.new
9 9 end
... ... @@ -44,7 +44,7 @@ class TextArticleTest &lt; ActiveSupport::TestCase
44 44 env = Environment.default
45 45 article.body = "<img src=\"http://#{env.default_hostname}/test.png\" />"
46 46 article.save!
47   - assert_equal "<img src=\"/test.png\" />", article.body
  47 + assert_equal "<img src=\"/test.png\">", article.body
48 48 end
49 49  
50 50 should 'change link to relative path' do
... ... @@ -60,18 +60,18 @@ class TextArticleTest &lt; ActiveSupport::TestCase
60 60 person = create_user('testuser').person
61 61 article = TextArticle.new(:profile => person, :name => 'test')
62 62 env = Environment.default
63   - article.body = "<img src=\"https://#{env.default_hostname}/test.png\" />"
  63 + article.body = "<img src=\"https://#{env.default_hostname}/test.png\">"
64 64 article.save!
65   - assert_equal "<img src=\"/test.png\" />", article.body
  65 + assert_equal "<img src=\"/test.png\">", article.body
66 66 end
67 67  
68 68 should 'change image path to relative for domain with port' do
69 69 person = create_user('testuser').person
70 70 article = TextArticle.new(:profile => person, :name => 'test')
71 71 env = Environment.default
72   - article.body = "<img src=\"http://#{env.default_hostname}:3000/test.png\" />"
  72 + article.body = "<img src=\"http://#{env.default_hostname}:3000/test.png\">"
73 73 article.save!
74   - assert_equal "<img src=\"/test.png\" />", article.body
  74 + assert_equal "<img src=\"/test.png\">", article.body
75 75 end
76 76  
77 77 should 'change image path to relative for domain with www' do
... ... @@ -80,16 +80,16 @@ class TextArticleTest &lt; ActiveSupport::TestCase
80 80 env = Environment.default
81 81 env.force_www = true
82 82 env.save!
83   - article.body = "<img src=\"http://#{env.default_hostname}:3000/test.png\" />"
  83 + article.body = "<img src=\"http://#{env.default_hostname}:3000/test.png\">"
84 84 article.save!
85   - assert_equal "<img src=\"/test.png\" />", article.body
  85 + assert_equal "<img src=\"/test.png\">", article.body
86 86 end
87 87  
88 88 should 'not be translatable if there is no language available on environment' do
89 89 environment = fast_create(Environment)
90 90 environment.languages = nil
91 91 profile = fast_create(Person, :environment_id => environment.id)
92   -
  92 +
93 93 text = TextArticle.new(:profile => profile)
94 94  
95 95 assert !text.translatable?
... ... @@ -102,11 +102,10 @@ class TextArticleTest &lt; ActiveSupport::TestCase
102 102 text = fast_create(TextArticle, :profile_id => profile.id)
103 103  
104 104 assert !text.translatable?
105   -
106 105  
107 106 environment.languages = ['en','pt','fr']
108 107 environment.save
109   - text.reload
  108 + text.reload
110 109 assert text.translatable?
111 110 end
112 111  
... ...
test/unit/thickbox_helper_test.rb
... ... @@ -1,25 +0,0 @@
1   -require_relative "../test_helper"
2   -
3   -class ThickboxHelperTest < ActiveSupport::TestCase
4   - include ThickboxHelper
5   -
6   - def url_for(url)
7   - url
8   - end
9   -
10   - should 'create thickbox links correcly' do
11   - expects(:link_to).with('Title', '/url#TB_inline?height=300&width=500&inlineId=inlineLoginBox&modal=true', :class => 'thickbox')
12   - thickbox_inline_popup_link('Title', '/url', 'inlineLoginBox')
13   - end
14   -
15   - should 'pass along extra options' do
16   - expects(:link_to).with('Title', anything, :class => 'thickbox', :id => 'lalala', :title => 'lelele')
17   - thickbox_inline_popup_link('Title', '/url', 'inlineLoginBox', :id => 'lalala', :title => 'lelele')
18   - end
19   -
20   - should 'generate close button' do
21   - expects(:button_to_function).with(:close, 'Title', 'tb_remove();').returns('[close-button]')
22   - assert_equal '[close-button]', thickbox_close_button('Title')
23   - end
24   -
25   -end
test/unit/tiny_mce_article_test.rb
... ... @@ -9,7 +9,7 @@ class TinyMceArticleTest &lt; ActiveSupport::TestCase
9 9 end
10 10 attr_reader :profile
11 11  
12   - # this test can be removed when we get real tests for TinyMceArticle
  12 + # this test can be removed when we get real tests for TinyMceArticle
13 13 should 'be an article' do
14 14 assert_subclass TextArticle, TinyMceArticle
15 15 end
... ... @@ -44,11 +44,6 @@ class TinyMceArticleTest &lt; ActiveSupport::TestCase
44 44 assert(article.body.is_utf8?, "%s expected to be valid UTF-8 content" % article.body.inspect)
45 45 end
46 46  
47   - should 'fix tinymce mess with itheora comments for IE from tiny mce article body' do
48   - article = create(TinyMceArticle, :profile => profile, :name => 'article', :abstract => 'abstract', :body => "the <!--–-[if IE]--> just for ie... <!--[endif]-->")
49   - assert_equal "the <!–-[if IE]> just for ie... <![endif]-–>", article.body.html_safe
50   - end
51   -
52 47 should 'remove iframe if it is not from a trusted site' do
53 48 article = create(TinyMceArticle, :profile => profile, :name => 'article', :abstract => 'abstract', :body => "<iframe src='http://anything/videos.ogg'></iframe>")
54 49 assert_equal "", article.body
... ... @@ -94,12 +89,6 @@ class TinyMceArticleTest &lt; ActiveSupport::TestCase
94 89 assert_equal '', article.body
95 90 end
96 91  
97   - #TinymMCE convert config={"key":(.*)} in config={&quotkey&quot:(.*)}
98   - should 'not replace &quot with &amp;quot; when adding an Archive.org video' do
99   - article = create(TinyMceArticle, :profile => profile, :name => 'article', :abstract => 'abstract', :body => "<embed flashvars='config={&quot;key&quot;:&quot;\#$b6eb72a0f2f1e29f3d4&quot;}'> </embed>")
100   - assert_equal "<embed flashvars=\"config={&quot;key&quot;:&quot;\#$b6eb72a0f2f1e29f3d4&quot;}\"> </embed>", article.body
101   - end
102   -
103 92 should 'not sanitize html comments' do
104 93 article = TinyMceArticle.new
105 94 article.body = '<p><!-- <asdf> << aasdfa >>> --> <h1> Wellformed html code </h1>'
... ...
test/unit/user_activation_job_test.rb
1 1 require_relative "../test_helper"
2 2  
3   -class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase
  3 +class UserActivationJobTest < ActiveSupport::TestCase
4 4  
5 5 should 'create job on user creation' do
6 6 user = new_user :login => 'test1'
... ...
test/unit/user_test.rb
... ... @@ -526,9 +526,19 @@ class UserTest &lt; ActiveSupport::TestCase
526 526 assert user.activated?
527 527 end
528 528  
529   - should 'delay activation check' do
  529 + should 'delay activation check with default time' do
530 530 user = new_user
531   - assert_match /UserActivationJob/, Delayed::Job.last.handler
  531 + job = Delayed::Job.last
  532 + assert_match /UserActivationJob/, job.handler
  533 + assert_equal 72, ((job.run_at - user.created_at)/1.hour).round
  534 + end
  535 +
  536 + should 'delay activation check with custom time' do
  537 + NOOSFERO_CONF.stubs(:[]).with('hours_until_user_activation_check').returns(240)
  538 + user = new_user
  539 + job = Delayed::Job.last
  540 + assert_match /UserActivationJob/, job.handler
  541 + assert_equal 240, ((job.run_at - user.created_at)/1.hour).round
532 542 end
533 543  
534 544 should 'not create job to check activation to template users' do
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/aol.rb
... ... @@ -8,20 +8,19 @@ class Hash
8 8 end
9 9  
10 10 class Contacts
11   - require 'hpricot'
12 11 class Aol < Base
13 12 URL = "http://www.aol.com/"
14 13 LOGIN_URL = "https://my.screenname.aol.com/_cqr/login/login.psp"
15 14 LOGIN_REFERER_URL = "http://webmail.aol.com/"
16 15 LOGIN_REFERER_PATH = "sitedomain=sns.webmail.aol.com&lang=en&locale=us&authLev=0&uitype=mini&loginId=&redirType=js&xchk=false"
17 16 AOL_NUM = "29970-343" # this seems to change each time they change the protocol
18   -
  17 +
19 18 CONTACT_LIST_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ContactList.aspx?folder=Inbox&showUserFolders=False"
20 19 CONTACT_LIST_CSV_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ABExport.aspx?command=all"
21 20 PROTOCOL_ERROR = "AOL has changed its protocols, please upgrade this library first. If that does not work, dive into the code and submit a patch at http://github.com/cardmagic/contacts"
22   -
  21 +
23 22 def real_connect
24   -
  23 +
25 24 postdata = {
26 25 "loginId" => login,
27 26 "password" => password,
... ... @@ -62,15 +61,15 @@ class Contacts
62 61 until forward.nil?
63 62 data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
64 63 end
65   -
  64 +
66 65 data, resp, cookies, forward, old_url = get("#{LOGIN_URL}?#{LOGIN_REFERER_PATH}", cookies) + [LOGIN_REFERER_URL]
67 66 until forward.nil?
68 67 data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
69 68 end
70 69  
71   - doc = Hpricot(data)
72   - (doc/:input).each do |input|
73   - postdata["usrd"] = input.attributes["value"] if input.attributes["name"] == "usrd"
  70 + doc = Nokogiri::HTML.fragment data
  71 + doc.css('input').each do |input|
  72 + postdata["usrd"] = input["value"] if input["name"] == "usrd"
74 73 end
75 74 # parse data for <input name="usrd" value="2726212" type="hidden"> and add it to the postdata
76 75  
... ... @@ -78,13 +77,13 @@ class Contacts
78 77 postdata["SNS_LDC"] = cookie_hash_from_string(cookies)["SNS_LDC"]
79 78 postdata["LTState"] = cookie_hash_from_string(cookies)["LTState"]
80 79 # raise data.inspect
81   -
  80 +
82 81 data, resp, cookies, forward, old_url = post(LOGIN_URL, postdata.to_query_string, cookies, LOGIN_REFERER_URL) + [LOGIN_REFERER_URL]
83   -
  82 +
84 83 until forward.nil?
85 84 data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
86 85 end
87   -
  86 +
88 87 if data.index("Invalid Screen Name or Password.")
89 88 raise AuthenticationError, "Username and password do not match"
90 89 elsif data.index("Required field must not be blank")
... ... @@ -113,19 +112,19 @@ class Contacts
113 112 until forward.nil?
114 113 data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
115 114 end
116   -
  115 +
117 116 if resp.code_type != Net::HTTPOK
118 117 raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
119 118 end
120 119  
121 120 # parse data and grab <input name="user" value="8QzMPIAKs2" type="hidden">
122   - doc = Hpricot(data)
123   - (doc/:input).each do |input|
124   - postdata["user"] = input.attributes["value"] if input.attributes["name"] == "user"
  121 + doc = Nokogiri::HTML.fragment data
  122 + doc.css('input').each do |input|
  123 + postdata["user"] = input["value"] if input["name"] == "user"
125 124 end
126   -
  125 +
127 126 data, resp, cookies, forward, old_url = get(CONTACT_LIST_CSV_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
128   -
  127 +
129 128 if forward.nil?
130 129 parse data
131 130 else
... ... @@ -134,15 +133,15 @@ class Contacts
134 133 end
135 134 end
136 135 private
137   -
  136 +
138 137 def parse(data, options={})
139 138 data = CSV.parse(data)
140 139 col_names = data.shift
141 140 @contacts = data.map do |person|
142 141 ["#{person[0]} #{person[1]}", person[4]] unless person[4].empty?
143 142 end.compact
144   - end
  143 + end
145 144 end
146 145  
147 146 TYPES[:aol] = Aol
148   -end
149 147 \ No newline at end of file
  148 +end
... ...
vendor/plugins/ruby_bosh/Rakefile
... ... @@ -12,7 +12,7 @@ begin
12 12  
13 13 s.add_dependency("builder")
14 14 s.add_dependency("rest-client")
15   - s.add_dependency("hpricot")
  15 + s.add_dependency("nokogiri")
16 16 s.add_dependency("SystemTimer")
17 17 end
18 18 rescue LoadError
... ...
vendor/plugins/ruby_bosh/lib/ruby_bosh.rb
... ... @@ -2,10 +2,10 @@ require &#39;rest_client&#39;
2 2 require 'builder'
3 3 require 'rexml/document'
4 4 require 'base64'
5   -require 'hpricot'
  5 +require 'nokogiri'
6 6 require 'timeout'
7 7  
8   -class RubyBOSH
  8 +class RubyBOSH
9 9 BOSH_XMLNS = 'http://jabber.org/protocol/httpbind'
10 10 TLS_XMLNS = 'urn:ietf:params:xml:ns:xmpp-tls'
11 11 SASL_XMLNS = 'urn:ietf:params:xml:ns:xmpp-sasl'
... ... @@ -24,12 +24,12 @@ class RubyBOSH
24 24 end
25 25  
26 26 attr_accessor :jid, :rid, :sid, :success
27   - def initialize(jid, pw, service_url, opts={})
  27 + def initialize(jid, pw, service_url, opts={})
28 28 @service_url = service_url
29 29 @jid, @pw = jid, pw
30 30 @host = jid.split("@").last
31 31 @success = false
32   - @timeout = opts[:timeout] || 3 #seconds
  32 + @timeout = opts[:timeout] || 3 #seconds
33 33 @headers = {"Content-Type" => "text/xml; charset=utf-8",
34 34 "Accept" => "text/xml"}
35 35 @wait = opts[:wait] || 5
... ... @@ -47,7 +47,7 @@ class RubyBOSH
47 47  
48 48 def connect
49 49 initialize_bosh_session
50   - if send_auth_request
  50 + if send_auth_request
51 51 send_restart_request
52 52 request_resource_binding
53 53 @success = send_session_request
... ... @@ -55,12 +55,12 @@ class RubyBOSH
55 55  
56 56 raise RubyBOSH::AuthFailed, "could not authenticate #{@jid}" unless success?
57 57 @rid += 1 #updates the rid for the next call from the browser
58   -
  58 +
59 59 [@jid, @sid, @rid]
60 60 end
61 61  
62 62 private
63   - def initialize_bosh_session
  63 + def initialize_bosh_session
64 64 response = deliver(construct_body(:wait => @wait, :to => @host,
65 65 :hold => @hold, :window => @window,
66 66 "xmpp:version" => '1.0'))
... ... @@ -72,7 +72,7 @@ class RubyBOSH
72 72  
73 73 builder = Builder::XmlMarkup.new
74 74 parameters = {:rid => @rid, :xmlns => BOSH_XMLNS,
75   - "xmpp:version" => "1.0",
  75 + "xmpp:version" => "1.0",
76 76 "xmlns:xmpp" => "urn:xmpp:xbosh"}.merge(params)
77 77  
78 78 if block_given?
... ... @@ -82,10 +82,10 @@ class RubyBOSH
82 82 end
83 83 end
84 84  
85   - def send_auth_request
  85 + def send_auth_request
86 86 request = construct_body(:sid => @sid) do |body|
87   - auth_string = "#{@jid}\x00#{@jid.split("@").first.strip}\x00#{@pw}"
88   - body.auth(Base64.encode64(auth_string).gsub(/\s/,''),
  87 + auth_string = "#{@jid}\x00#{@jid.split("@").first.strip}\x00#{@pw}"
  88 + body.auth(Base64.encode64(auth_string).gsub(/\s/,''),
89 89 :xmlns => SASL_XMLNS, :mechanism => 'PLAIN')
90 90 end
91 91  
... ... @@ -100,16 +100,16 @@ class RubyBOSH
100 100  
101 101 def request_resource_binding
102 102 request = construct_body(:sid => @sid) do |body|
103   - body.iq(:id => "bind_#{rand(100000)}", :type => "set",
  103 + body.iq(:id => "bind_#{rand(100000)}", :type => "set",
104 104 :xmlns => "jabber:client") do |iq|
105 105 iq.bind(:xmlns => BIND_XMLNS) do |bind|
106 106 bind.resource("bosh_#{rand(10000)}")
107 107 end
108 108 end
109 109 end
110   -
  110 +
111 111 response = deliver(request)
112   - response.include?("<jid>")
  112 + response.include?("<jid>")
113 113 end
114 114  
115 115 def send_session_request
... ... @@ -117,16 +117,16 @@ class RubyBOSH
117 117 body.iq(:xmlns => CLIENT_XMLNS, :type => "set",
118 118 :id => "sess_#{rand(100000)}") do |iq|
119 119 iq.session(:xmlns => SESSION_XMLNS)
120   - end
  120 + end
121 121 end
122 122  
123 123 response = deliver(request)
124   - response.include?("body")
  124 + response.include?("body")
125 125 end
126 126  
127 127 def parse(_response)
128   - doc = Hpricot(_response.to_s)
129   - doc.search("//body").each do |body|
  128 + doc = Nokogiri::HTML.fragment(_response.to_s)
  129 + doc.search("body").each do |body|
130 130 @sid = body.attributes["sid"].to_s
131 131 end
132 132 _response
... ... @@ -156,6 +156,6 @@ end
156 156  
157 157  
158 158 if __FILE__ == $0
159   - p RubyBOSH.initialize_session(ARGV[0], ARGV[1],
  159 + p RubyBOSH.initialize_session(ARGV[0], ARGV[1],
160 160 "http://localhost:5280/http-bind")
161 161 end
... ...
vendor/plugins/ruby_bosh/ruby_bosh.gemspec
... ... @@ -24,18 +24,15 @@ Gem::Specification.new do |s|
24 24 if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
25 25 s.add_runtime_dependency(%q<builder>, [">= 0"])
26 26 s.add_runtime_dependency(%q<adamwiggins-rest-client>, [">= 0"])
27   - s.add_runtime_dependency(%q<hpricot>, [">= 0"])
28 27 s.add_runtime_dependency(%q<SystemTimer>, [">= 0"])
29 28 else
30 29 s.add_dependency(%q<builder>, [">= 0"])
31 30 s.add_dependency(%q<adamwiggins-rest-client>, [">= 0"])
32   - s.add_dependency(%q<hpricot>, [">= 0"])
33 31 s.add_dependency(%q<SystemTimer>, [">= 0"])
34 32 end
35 33 else
36 34 s.add_dependency(%q<builder>, [">= 0"])
37 35 s.add_dependency(%q<adamwiggins-rest-client>, [">= 0"])
38   - s.add_dependency(%q<hpricot>, [">= 0"])
39 36 s.add_dependency(%q<SystemTimer>, [">= 0"])
40 37 end
41 38 end
... ...