Commit df287a928b81ae1645da5f4041e3df7e45572905

Authored by Thiago Ribeiro
2 parents 180ad529 211e635e
Exists in master

Merge branch 'notification_plugin' into 'master'

Notification plugin

See merge request !1
Showing 96 changed files with 2036 additions and 247 deletions   Show diff stats
app/controllers/public/search_controller.rb
@@ -92,10 +92,10 @@ class SearchController < PublicController @@ -92,10 +92,10 @@ class SearchController < PublicController
92 92
93 def events 93 def events
94 if params[:year].blank? && params[:year].blank? && params[:day].blank? 94 if params[:year].blank? && params[:year].blank? && params[:day].blank?
95 - @date = Date.today 95 + @date = DateTime.now
96 else 96 else
97 - year = (params[:year] ? params[:year].to_i : Date.today.year)  
98 - month = (params[:month] ? params[:month].to_i : Date.today.month) 97 + year = (params[:year] ? params[:year].to_i : DateTime.now.year)
  98 + month = (params[:month] ? params[:month].to_i : DateTime.now.month)
99 day = (params[:day] ? params[:day].to_i : 1) 99 day = (params[:day] ? params[:day].to_i : 1)
100 @date = build_date(year, month, day) 100 @date = build_date(year, month, day)
101 end 101 end
@@ -106,9 +106,7 @@ class SearchController < PublicController @@ -106,9 +106,7 @@ class SearchController < PublicController
106 @events = @category ? 106 @events = @category ?
107 environment.events.by_day(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) : 107 environment.events.by_day(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
108 environment.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page]) 108 environment.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page])
109 - end  
110 -  
111 - if params[:year] || params[:month] 109 + elsif params[:year] || params[:month]
112 @events = @category ? 110 @events = @category ?
113 environment.events.by_month(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) : 111 environment.events.by_month(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
114 environment.events.by_month(@date).paginate(:per_page => per_page, :page => params[:page]) 112 environment.events.by_month(@date).paginate(:per_page => per_page, :page => params[:page])
app/helpers/content_viewer_helper.rb
@@ -51,7 +51,7 @@ module ContentViewerHelper @@ -51,7 +51,7 @@ module ContentViewerHelper
51 elsif date_format == 'past_time' 51 elsif date_format == 'past_time'
52 left_time = true 52 left_time = true
53 end 53 end
54 - content_tag('span', show_date(article.published_at, use_numbers , year, left_time), :class => 'date') 54 + content_tag('span', show_time(article.published_at, use_numbers , year, left_time), :class => 'date')
55 end 55 end
56 56
57 def link_to_comments(article, args = {}) 57 def link_to_comments(article, args = {})
app/helpers/dates_helper.rb
@@ -43,9 +43,14 @@ module DatesHelper @@ -43,9 +43,14 @@ module DatesHelper
43 end 43 end
44 44
45 # formats a datetime for displaying. 45 # formats a datetime for displaying.
46 - def show_time(time)  
47 - if time  
48 - _('%{day} %{month} %{year}, %{hour}:%{minutes}') % { :year => time.year, :month => month_name(time.month), :day => time.day, :hour => time.hour, :minutes => time.strftime("%M") } 46 + def show_time(time, use_numbers = false, year = true, left_time = false)
  47 + if time && use_numbers
  48 + _('%{month}/%{day}/%{year}, %{hour}:%{minutes}') % { :year => (year ? time.year : ''), :month => time.month, :day => time.day, :hour => time.hour, :minutes => time.strftime("%M") }
  49 + elsif time && left_time
  50 + date_format = time_ago_in_words(time)
  51 + elsif time
  52 + date_format = year ? _('%{month_name} %{day}, %{year} %{hour}:%{minutes}') : _('%{month_name} %{day} %{hour}:%{minutes}')
  53 + date_format % { :day => time.day, :month_name => month_name(time.month), :year => time.year, :hour => time.hour, :minutes => time.strftime("%M") }
49 else 54 else
50 '' 55 ''
51 end 56 end
@@ -53,7 +58,7 @@ module DatesHelper @@ -53,7 +58,7 @@ module DatesHelper
53 58
54 def show_period(date1, date2 = nil, use_numbers = false) 59 def show_period(date1, date2 = nil, use_numbers = false)
55 if (date1 == date2) || (date2.nil?) 60 if (date1 == date2) || (date2.nil?)
56 - show_date(date1, use_numbers) 61 + show_time(date1, use_numbers)
57 else 62 else
58 if date1.year == date2.year 63 if date1.year == date2.year
59 if date1.month == date2.month 64 if date1.month == date2.month
@@ -72,8 +77,8 @@ module DatesHelper @@ -72,8 +77,8 @@ module DatesHelper
72 end 77 end
73 else 78 else
74 _('from %{date1} to %{date2}') % { 79 _('from %{date1} to %{date2}') % {
75 - :date1 => show_date(date1, use_numbers),  
76 - :date2 => show_date(date2, use_numbers) 80 + :date1 => show_time(date1, use_numbers),
  81 + :date2 => show_time(date2, use_numbers)
77 } 82 }
78 end 83 end
79 end 84 end
@@ -106,18 +111,18 @@ module DatesHelper @@ -106,18 +111,18 @@ module DatesHelper
106 111
107 def build_date(year, month, day = 1) 112 def build_date(year, month, day = 1)
108 if year.blank? and month.blank? and day.blank? 113 if year.blank? and month.blank? and day.blank?
109 - Date.today 114 + DateTime.now
110 else 115 else
111 if year.blank? 116 if year.blank?
112 - year = Date.today.year 117 + year = DateTime.now.year
113 end 118 end
114 if month.blank? 119 if month.blank?
115 - month = Date.today.month 120 + month = DateTime.now.month
116 end 121 end
117 if day.blank? 122 if day.blank?
118 day = 1 123 day = 1
119 end 124 end
120 - Date.new(year.to_i, month.to_i, day.to_i) 125 + DateTime.new(year.to_i, month.to_i, day.to_i)
121 end 126 end
122 end 127 end
123 128
app/helpers/events_helper.rb
@@ -16,7 +16,7 @@ module EventsHelper @@ -16,7 +16,7 @@ module EventsHelper
16 16
17 content_tag( 'tr', 17 content_tag( 'tr',
18 content_tag('td', 18 content_tag('td',
19 - content_tag('div', show_date(article.start_date) + ( article.end_date.nil? ? '' : (_(" to ") + show_date(article.end_date))),:class => 'event-date' ) + 19 + content_tag('div', show_time(article.start_date) + ( article.end_date.nil? ? '' : (_(" to ") + show_time(article.end_date))),:class => 'event-date' ) +
20 content_tag('div',link_to(article.name,article.url),:class => 'event-title') + 20 content_tag('div',link_to(article.name,article.url),:class => 'event-title') +
21 content_tag('div',(article.address.nil? or article.address == '') ? '' : (_('Place: ') + article.address),:class => 'event-place') 21 content_tag('div',(article.address.nil? or article.address == '') ? '' : (_('Place: ') + article.address),:class => 'event-place')
22 ) 22 )
@@ -30,7 +30,7 @@ module EventsHelper @@ -30,7 +30,7 @@ module EventsHelper
30 # the day itself 30 # the day itself
31 date, 31 date,
32 # is there any events in this date? 32 # is there any events in this date?
33 - events.any? {|event| event.date_range.include?(date)}, 33 + events.any? {|event| event.date_range.cover?(date)},
34 # is this date in the current month? 34 # is this date in the current month?
35 true 35 true
36 ] 36 ]
app/helpers/forms_helper.rb
@@ -151,7 +151,7 @@ module FormsHelper @@ -151,7 +151,7 @@ module FormsHelper
151 datepicker_options[:close_text] ||= _('Done') 151 datepicker_options[:close_text] ||= _('Done')
152 datepicker_options[:constrain_input] ||= true 152 datepicker_options[:constrain_input] ||= true
153 datepicker_options[:current_text] ||= _('Today') 153 datepicker_options[:current_text] ||= _('Today')
154 - datepicker_options[:date_format] ||= 'mm/dd/yy' 154 + datepicker_options[:date_format] ||= 'yy/mm/dd'
155 datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')] 155 datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')]
156 datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')] 156 datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')]
157 datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')] 157 datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')]
@@ -236,7 +236,7 @@ module FormsHelper @@ -236,7 +236,7 @@ module FormsHelper
236 weekHeader: #{datepicker_options[:week_header].to_json}, 236 weekHeader: #{datepicker_options[:week_header].to_json},
237 yearRange: #{datepicker_options[:year_range].to_json}, 237 yearRange: #{datepicker_options[:year_range].to_json},
238 yearSuffix: #{datepicker_options[:year_suffix].to_json} 238 yearSuffix: #{datepicker_options[:year_suffix].to_json}
239 - }) 239 + }).datepicker('setDate', new Date('#{value}'))
240 </script> 240 </script>
241 ".html_safe 241 ".html_safe
242 result 242 result
app/models/article.rb
@@ -635,6 +635,14 @@ class Article &lt; ActiveRecord::Base @@ -635,6 +635,14 @@ class Article &lt; ActiveRecord::Base
635 can_display_hits? && display_hits 635 can_display_hits? && display_hits
636 end 636 end
637 637
  638 + def display_media_panel?
  639 + can_display_media_panel? && environment.enabled?('media_panel')
  640 + end
  641 +
  642 + def can_display_media_panel?
  643 + false
  644 + end
  645 +
638 def image? 646 def image?
639 false 647 false
640 end 648 end
@@ -743,9 +751,10 @@ class Article &lt; ActiveRecord::Base @@ -743,9 +751,10 @@ class Article &lt; ActiveRecord::Base
743 end 751 end
744 752
745 def body_images_paths 753 def body_images_paths
746 - require 'uri'  
747 Nokogiri::HTML.fragment(self.body.to_s).css('img[src]').collect do |i| 754 Nokogiri::HTML.fragment(self.body.to_s).css('img[src]').collect do |i|
748 - (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i['src'])).to_s : i['src'] 755 + src = i['src']
  756 + src = URI.escape src if self.new_record? # xss_terminate runs on save
  757 + (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, src).to_s : src
749 end 758 end
750 end 759 end
751 760
app/models/category.rb
@@ -81,7 +81,7 @@ class Category &lt; ActiveRecord::Base @@ -81,7 +81,7 @@ class Category &lt; ActiveRecord::Base
81 end 81 end
82 82
83 def upcoming_events(limit = 10) 83 def upcoming_events(limit = 10)
84 - self.events.paginate(:conditions => [ 'start_date >= ?', Date.today ], :order => 'start_date', :page => 1, :per_page => limit) 84 + self.events.paginate(:conditions => [ 'start_date >= ?', DateTime.now.beginning_of_day ], :order => 'start_date', :page => 1, :per_page => limit)
85 end 85 end
86 86
87 def display_in_menu? 87 def display_in_menu?
app/models/enterprise_homepage.rb
@@ -35,4 +35,8 @@ class EnterpriseHomepage &lt; Article @@ -35,4 +35,8 @@ class EnterpriseHomepage &lt; Article
35 false 35 false
36 end 36 end
37 37
  38 + def can_display_media_panel?
  39 + true
  40 + end
  41 +
38 end 42 end
app/models/event.rb
@@ -23,7 +23,7 @@ class Event &lt; Article @@ -23,7 +23,7 @@ class Event &lt; Article
23 23
24 def initialize(*args) 24 def initialize(*args)
25 super(*args) 25 super(*args)
26 - self.start_date ||= Date.today 26 + self.start_date ||= DateTime.now
27 end 27 end
28 28
29 validates_presence_of :title, :start_date 29 validates_presence_of :title, :start_date
@@ -35,7 +35,7 @@ class Event &lt; Article @@ -35,7 +35,7 @@ class Event &lt; Article
35 end 35 end
36 36
37 scope :by_day, lambda { |date| 37 scope :by_day, lambda { |date|
38 - { :conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}], 38 + { :conditions => [' start_date >= :start_date AND start_date <= :end_date AND end_date IS NULL OR (start_date <= :end_date AND end_date >= :start_date)', {:start_date => date.beginning_of_day, :end_date => date.end_of_day}],
39 :order => 'start_date ASC' 39 :order => 'start_date ASC'
40 } 40 }
41 } 41 }
@@ -80,7 +80,7 @@ class Event &lt; Article @@ -80,7 +80,7 @@ class Event &lt; Article
80 80
81 def self.date_range(year, month) 81 def self.date_range(year, month)
82 if year.nil? || month.nil? 82 if year.nil? || month.nil?
83 - today = Date.today 83 + today = DateTime.now
84 year = today.year 84 year = today.year
85 month = today.month 85 month = today.month
86 else 86 else
@@ -88,7 +88,7 @@ class Event &lt; Article @@ -88,7 +88,7 @@ class Event &lt; Article
88 month = month.to_i 88 month = month.to_i
89 end 89 end
90 90
91 - first_day = Date.new(year, month, 1) 91 + first_day = DateTime.new(year, month, 1)
92 last_day = first_day + 1.month - 1.day 92 last_day = first_day + 1.month - 1.day
93 93
94 first_day..last_day 94 first_day..last_day
@@ -114,7 +114,7 @@ class Event &lt; Article @@ -114,7 +114,7 @@ class Event &lt; Article
114 end 114 end
115 115
116 def duration 116 def duration
117 - ((self.end_date || self.start_date) - self.start_date).to_i 117 + (((self.end_date || self.start_date) - self.start_date).to_i/60/60/24)
118 end 118 end
119 119
120 alias_method :article_lead, :lead 120 alias_method :article_lead, :lead
@@ -134,6 +134,10 @@ class Event &lt; Article @@ -134,6 +134,10 @@ class Event &lt; Article
134 true 134 true
135 end 135 end
136 136
  137 + def can_display_media_panel?
  138 + true
  139 + end
  140 +
137 include Noosfero::TranslatableContent 141 include Noosfero::TranslatableContent
138 include MaybeAddHttp 142 include MaybeAddHttp
139 143
app/models/textile_article.rb
@@ -24,6 +24,10 @@ class TextileArticle &lt; TextArticle @@ -24,6 +24,10 @@ class TextileArticle &lt; TextArticle
24 true 24 true
25 end 25 end
26 26
  27 + def can_display_media_panel?
  28 + true
  29 + end
  30 +
27 protected 31 protected
28 32
29 def convert_to_html(textile) 33 def convert_to_html(textile)
app/models/tiny_mce_article.rb
@@ -28,4 +28,8 @@ class TinyMceArticle &lt; TextArticle @@ -28,4 +28,8 @@ class TinyMceArticle &lt; TextArticle
28 true 28 true
29 end 29 end
30 30
  31 + def can_display_media_panel?
  32 + true
  33 + end
  34 +
31 end 35 end
app/views/cms/_event.html.erb
@@ -8,9 +8,8 @@ @@ -8,9 +8,8 @@
8 <%= render :partial => 'general_fields' %> 8 <%= render :partial => 'general_fields' %>
9 <%= render :partial => 'translatable' %> 9 <%= render :partial => 'translatable' %>
10 10
11 -<%= labelled_form_field(_('Start date'), pick_date(:article, :start_date)) %> 11 +<%= date_range_field('article[start_date]', 'article[end_date]', @article.start_date, @article.end_date, _('%Y-%m-%d %H:%M'), {:time => true}, {:id => 'article_start_date'} ) %>
12 12
13 -<%= labelled_form_field(_('End date'), pick_date(:article, :end_date)) %>  
14 13
15 <%= labelled_form_field(_('Event website:'), text_field(:article, :link)) %> 14 <%= labelled_form_field(_('Event website:'), text_field(:article, :link)) %>
16 15
app/views/cms/edit.html.erb
1 <%= error_messages_for 'article' %> 1 <%= error_messages_for 'article' %>
2 2
3 -<% show_media_panel = environment.enabled?('media_panel') && [TinyMceArticle, TextileArticle, Event, EnterpriseHomepage].any?{|klass| @article.kind_of?(klass)} %>  
4 -  
5 -<div class='<%= (show_media_panel ? 'with_media_panel' : 'no_media_panel') %>'> 3 +<div class='<%= (@article.display_media_panel? ? 'with_media_panel' : 'no_media_panel') %>'>
6 <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %> 4 <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %>
7 5
8 <%= hidden_field_tag("type", @type) if @type %> 6 <%= hidden_field_tag("type", @type) if @type %>
@@ -68,7 +66,7 @@ @@ -68,7 +66,7 @@
68 <% end %> 66 <% end %>
69 </div> 67 </div>
70 68
71 -<% if show_media_panel %> 69 +<% if @article.display_media_panel? %>
72 <%= render :partial => 'text_editor_sidebar' %> 70 <%= render :partial => 'text_editor_sidebar' %>
73 <% end %> 71 <% end %>
74 72
app/views/content_viewer/_publishing_info.html.erb
1 <span class="publishing-info"> 1 <span class="publishing-info">
2 <span class="date"> 2 <span class="date">
3 - <%= show_date(@page.published_at) %> 3 + <%= show_time(@page.published_at) %>
4 </span> 4 </span>
5 <span class="author"> 5 <span class="author">
6 <%= _(", by %s") % (@page.author ? link_to(@page.author_name, @page.author_url) : @page.author_name) %> 6 <%= _(", by %s") % (@page.author ? link_to(@page.author_name, @page.author_url) : @page.author_name) %>
db/migrate/20150722042714_change_article_date_to_datetime.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +class ChangeArticleDateToDatetime < ActiveRecord::Migration
  2 +
  3 + def up
  4 + change_table :articles do |t|
  5 + t.change :start_date, :datetime
  6 + t.change :end_date, :datetime
  7 + end
  8 +
  9 + change_table :article_versions do |t|
  10 + t.change :start_date, :datetime
  11 + t.change :end_date, :datetime
  12 + end
  13 + end
  14 +
  15 + def down
  16 + change_table :articles do |t|
  17 + t.change :start_date, :date
  18 + t.change :end_date, :date
  19 + end
  20 +
  21 + change_table :article_versions do |t|
  22 + t.change :start_date, :date
  23 + t.change :end_date, :date
  24 + end
  25 + end
  26 +
  27 +end
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 # 11 #
12 # It's strongly recommended to check this file into your version control system. 12 # It's strongly recommended to check this file into your version control system.
13 13
14 -ActiveRecord::Schema.define(:version => 20150712130827) do 14 +ActiveRecord::Schema.define(:version => 20150722042714) do
15 15
16 create_table "abuse_reports", :force => true do |t| 16 create_table "abuse_reports", :force => true do |t|
17 t.integer "reporter_id" 17 t.integer "reporter_id"
@@ -75,8 +75,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150712130827) do @@ -75,8 +75,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150712130827) do
75 t.integer "comments_count" 75 t.integer "comments_count"
76 t.boolean "advertise", :default => true 76 t.boolean "advertise", :default => true
77 t.boolean "published", :default => true 77 t.boolean "published", :default => true
78 - t.date "start_date"  
79 - t.date "end_date" 78 + t.datetime "start_date"
  79 + t.datetime "end_date"
80 t.integer "children_count", :default => 0 80 t.integer "children_count", :default => 0
81 t.boolean "accept_comments", :default => true 81 t.boolean "accept_comments", :default => true
82 t.integer "reference_article_id" 82 t.integer "reference_article_id"
@@ -127,8 +127,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150712130827) do @@ -127,8 +127,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150712130827) do
127 t.integer "comments_count", :default => 0 127 t.integer "comments_count", :default => 0
128 t.boolean "advertise", :default => true 128 t.boolean "advertise", :default => true
129 t.boolean "published", :default => true 129 t.boolean "published", :default => true
130 - t.date "start_date"  
131 - t.date "end_date" 130 + t.datetime "start_date"
  131 + t.datetime "end_date"
132 t.integer "children_count", :default => 0 132 t.integer "children_count", :default => 0
133 t.boolean "accept_comments", :default => true 133 t.boolean "accept_comments", :default => true
134 t.integer "reference_article_id" 134 t.integer "reference_article_id"
features/events.feature
@@ -223,7 +223,7 @@ Feature: events @@ -223,7 +223,7 @@ Feature: events
223 | owner | name | start_date | end_date | 223 | owner | name | start_date | end_date |
224 | josesilva | WikiSym 2009 | 2009-10-25 | 2009-10-27 | 224 | josesilva | WikiSym 2009 | 2009-10-25 | 2009-10-27 |
225 When I am on /profile/josesilva/events/2009/10/26 225 When I am on /profile/josesilva/events/2009/10/26
226 - Then I should see "October 25, 2009 to October 27, 2009" 226 + Then I should see "October 25, 2009 0:00 to October 27, 2009 0:00"
227 227
228 Scenario: show place of the event 228 Scenario: show place of the event
229 Given I am on /profile/josesilva/events/2009/10 229 Given I am on /profile/josesilva/events/2009/10
plugins/community_track/lib/community_track_plugin/step.rb
@@ -29,8 +29,8 @@ class CommunityTrackPlugin::Step &lt; Folder @@ -29,8 +29,8 @@ class CommunityTrackPlugin::Step &lt; Folder
29 29
30 def initialize(*args) 30 def initialize(*args)
31 super(*args) 31 super(*args)
32 - self.start_date ||= Date.today  
33 - self.end_date ||= Date.today + 1.day 32 + self.start_date ||= DateTime.now
  33 + self.end_date ||= DateTime.now + 1.day
34 end 34 end
35 35
36 def set_hidden_position 36 def set_hidden_position
@@ -72,20 +72,20 @@ class CommunityTrackPlugin::Step &lt; Folder @@ -72,20 +72,20 @@ class CommunityTrackPlugin::Step &lt; Folder
72 end 72 end
73 73
74 def active? 74 def active?
75 - (start_date..end_date).include?(Date.today) 75 + (start_date..end_date).cover?(DateTime.now)
76 end 76 end
77 77
78 def finished? 78 def finished?
79 - Date.today > end_date 79 + DateTime.now > end_date
80 end 80 end
81 81
82 def waiting? 82 def waiting?
83 - Date.today < start_date 83 + DateTime.now < start_date
84 end 84 end
85 85
86 def schedule_activation 86 def schedule_activation
87 return if !changes['start_date'] && !changes['end_date'] 87 return if !changes['start_date'] && !changes['end_date']
88 - if Date.today <= end_date || accept_comments 88 + if DateTime.now <= end_date || accept_comments
89 schedule_date = !accept_comments ? start_date : end_date + 1.day 89 schedule_date = !accept_comments ? start_date : end_date + 1.day
90 CommunityTrackPlugin::ActivationJob.find(id).destroy_all 90 CommunityTrackPlugin::ActivationJob.find(id).destroy_all
91 Delayed::Job.enqueue(CommunityTrackPlugin::ActivationJob.new(self.id), :run_at => schedule_date) 91 Delayed::Job.enqueue(CommunityTrackPlugin::ActivationJob.new(self.id), :run_at => schedule_date)
plugins/community_track/test/functional/community_track_plugin_content_viewer_controller_test.rb
@@ -6,7 +6,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -6,7 +6,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
6 def setup 6 def setup
7 @profile = Community.create!(:name => 'Sample community', :identifier => 'sample-community') 7 @profile = Community.create!(:name => 'Sample community', :identifier => 'sample-community')
8 @track = create_track('track', @profile) 8 @track = create_track('track', @profile)
9 - @step = CommunityTrackPlugin::Step.create!(:name => 'step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today, :tool_type => TinyMceArticle.name) 9 + @step = CommunityTrackPlugin::Step.create!(:name => 'step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => DateTime.now.end_of_day, :start_date => DateTime.now.beginning_of_day, :tool_type => TinyMceArticle.name)
10 10
11 user = create_user('testinguser') 11 user = create_user('testinguser')
12 login_as(user.login) 12 login_as(user.login)
plugins/community_track/test/unit/community_track_plugin/step_test.rb
@@ -9,7 +9,7 @@ class StepTest &lt; ActiveSupport::TestCase @@ -9,7 +9,7 @@ class StepTest &lt; ActiveSupport::TestCase
9 @track.add_category(@category) 9 @track.add_category(@category)
10 @track.save! 10 @track.save!
11 11
12 - @step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today) 12 + @step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => DateTime.now.end_of_day, :start_date => DateTime.now.beginning_of_day - 1.day)
13 Delayed::Job.destroy_all 13 Delayed::Job.destroy_all
14 end 14 end
15 15
@@ -22,39 +22,39 @@ class StepTest &lt; ActiveSupport::TestCase @@ -22,39 +22,39 @@ class StepTest &lt; ActiveSupport::TestCase
22 end 22 end
23 23
24 should 'set accept_comments to false on create' do 24 should 'set accept_comments to false on create' do
25 - today = Date.today 25 + today = DateTime.now
26 step = CommunityTrackPlugin::Step.create(:name => 'Step', :body => 'body', :profile => @profile, :parent => @track, :start_date => today, :end_date => today, :published => true) 26 step = CommunityTrackPlugin::Step.create(:name => 'Step', :body => 'body', :profile => @profile, :parent => @track, :start_date => today, :end_date => today, :published => true)
27 refute step.accept_comments 27 refute step.accept_comments
28 end 28 end
29 29
30 should 'do not allow step creation with a parent that is not a track' do 30 should 'do not allow step creation with a parent that is not a track' do
31 - today = Date.today 31 + today = DateTime.now
32 blog = fast_create(Blog) 32 blog = fast_create(Blog)
33 step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => blog, :start_date => today, :end_date => today, :published => true) 33 step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => blog, :start_date => today, :end_date => today, :published => true)
34 refute step.save 34 refute step.save
35 end 35 end
36 36
37 should 'do not allow step creation without a parent' do 37 should 'do not allow step creation without a parent' do
38 - today = Date.today 38 + today = DateTime.now
39 step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => nil, :start_date => today, :end_date => today, :published => true) 39 step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => nil, :start_date => today, :end_date => today, :published => true)
40 refute step.save 40 refute step.save
41 end 41 end
42 42
43 should 'create step if end date is equal to start date' do 43 should 'create step if end date is equal to start date' do
44 - @step.start_date = Date.today  
45 - @step.end_date = Date.today 44 + @step.start_date = DateTime.now
  45 + @step.end_date = DateTime.now
46 assert @step.save 46 assert @step.save
47 end 47 end
48 48
49 should 'create step if end date is after start date' do 49 should 'create step if end date is after start date' do
50 - @step.start_date = Date.today  
51 - @step.end_date = Date.today + 1.day 50 + @step.start_date = DateTime.now
  51 + @step.end_date = DateTime.now + 1.day
52 assert @step.save 52 assert @step.save
53 end 53 end
54 54
55 should 'do not create step if end date is before start date' do 55 should 'do not create step if end date is before start date' do
56 - @step.start_date = Date.today  
57 - @step.end_date = Date.today - 1.day 56 + @step.start_date = DateTime.now
  57 + @step.end_date = DateTime.now - 1.day
58 refute @step.save 58 refute @step.save
59 end 59 end
60 60
@@ -71,20 +71,20 @@ class StepTest &lt; ActiveSupport::TestCase @@ -71,20 +71,20 @@ class StepTest &lt; ActiveSupport::TestCase
71 end 71 end
72 72
73 should 'be active if today is between start and end dates' do 73 should 'be active if today is between start and end dates' do
74 - @step.start_date = Date.today  
75 - @step.end_date = Date.today + 1.day 74 + @step.start_date = DateTime.now
  75 + @step.end_date = DateTime.now + 1.day
76 assert @step.active? 76 assert @step.active?
77 end 77 end
78 78
79 should 'be finished if today is after the end date' do 79 should 'be finished if today is after the end date' do
80 - @step.start_date = Date.today - 2.day  
81 - @step.end_date = Date.today - 1.day 80 + @step.start_date = DateTime.now - 2.day
  81 + @step.end_date = DateTime.now - 1.day
82 assert @step.finished? 82 assert @step.finished?
83 end 83 end
84 84
85 should 'be waiting if today is before the end date' do 85 should 'be waiting if today is before the end date' do
86 - @step.start_date = Date.today + 1.day  
87 - @step.end_date = Date.today + 2.day 86 + @step.start_date = DateTime.now + 1.day
  87 + @step.end_date = DateTime.now + 2.day
88 assert @step.waiting? 88 assert @step.waiting?
89 end 89 end
90 90
@@ -95,17 +95,17 @@ class StepTest &lt; ActiveSupport::TestCase @@ -95,17 +95,17 @@ class StepTest &lt; ActiveSupport::TestCase
95 end 95 end
96 96
97 should 'create delayed job' do 97 should 'create delayed job' do
98 - @step.start_date = Date.today  
99 - @step.end_date = Date.today 98 + @step.start_date = DateTime.now.beginning_of_day
  99 + @step.end_date = DateTime.now.end_of_day
100 @step.accept_comments = false 100 @step.accept_comments = false
101 @step.schedule_activation 101 @step.schedule_activation
102 assert_equal 1, Delayed::Job.count 102 assert_equal 1, Delayed::Job.count
103 - assert_equal @step.start_date, Delayed::Job.first.run_at.to_date 103 + assert_equal @step.start_date, Delayed::Job.first.run_at
104 end 104 end
105 105
106 should 'do not duplicate delayed job' do 106 should 'do not duplicate delayed job' do
107 - @step.start_date = Date.today  
108 - @step.end_date = Date.today 107 + @step.start_date = DateTime.now
  108 + @step.end_date = DateTime.now
109 @step.schedule_activation 109 @step.schedule_activation
110 assert_equal 1, Delayed::Job.count 110 assert_equal 1, Delayed::Job.count
111 @step.schedule_activation 111 @step.schedule_activation
@@ -113,30 +113,30 @@ class StepTest &lt; ActiveSupport::TestCase @@ -113,30 +113,30 @@ class StepTest &lt; ActiveSupport::TestCase
113 end 113 end
114 114
115 should 'create delayed job when a step is saved' do 115 should 'create delayed job when a step is saved' do
116 - @step.start_date = Date.today  
117 - @step.end_date = Date.today 116 + @step.start_date = DateTime.now.beginning_of_day
  117 + @step.end_date = DateTime.now.end_of_day
118 @step.save! 118 @step.save!
119 - assert_equal @step.start_date, Delayed::Job.first.run_at.to_date 119 + assert_equal @step.start_date, Delayed::Job.first.run_at
120 end 120 end
121 121
122 should 'create delayed job even if start date has passed' do 122 should 'create delayed job even if start date has passed' do
123 - @step.start_date = Date.today - 2.days  
124 - @step.end_date = Date.today 123 + @step.start_date = DateTime.now - 2.days
  124 + @step.end_date = DateTime.now.end_of_day
125 @step.accept_comments = false 125 @step.accept_comments = false
126 @step.schedule_activation 126 @step.schedule_activation
127 - assert_equal @step.start_date, Delayed::Job.first.run_at.to_date 127 + assert_equal @step.start_date, Delayed::Job.first.run_at
128 end 128 end
129 129
130 should 'create delayed job if end date has passed' do 130 should 'create delayed job if end date has passed' do
131 - @step.start_date = Date.today - 5.days  
132 - @step.end_date = Date.today - 2.days 131 + @step.start_date = DateTime.now - 5.days
  132 + @step.end_date = DateTime.now - 2.days
133 @step.schedule_activation 133 @step.schedule_activation
134 - assert_equal @step.end_date + 1.day, Delayed::Job.first.run_at.to_date 134 + assert_equal @step.end_date + 1.day, Delayed::Job.first.run_at
135 end 135 end
136 136
137 should 'do not schedule delayed job if save but do not modify date fields' do 137 should 'do not schedule delayed job if save but do not modify date fields' do
138 - @step.start_date = Date.today  
139 - @step.end_date = Date.today 138 + @step.start_date = DateTime.now
  139 + @step.end_date = DateTime.now.end_of_day
140 @step.save! 140 @step.save!
141 assert_equal 1, Delayed::Job.count 141 assert_equal 1, Delayed::Job.count
142 Delayed::Job.destroy_all 142 Delayed::Job.destroy_all
@@ -149,13 +149,13 @@ class StepTest &lt; ActiveSupport::TestCase @@ -149,13 +149,13 @@ class StepTest &lt; ActiveSupport::TestCase
149 refute @step.position 149 refute @step.position
150 @step.save! 150 @step.save!
151 assert_equal 1, @step.position 151 assert_equal 1, @step.position
152 - step2 = CommunityTrackPlugin::Step.new(:name => 'Step2', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today) 152 + step2 = CommunityTrackPlugin::Step.new(:name => 'Step2', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => DateTime.now.end_of_day, :start_date => DateTime.now.beginning_of_day)
153 step2.save! 153 step2.save!
154 assert_equal 2, step2.position 154 assert_equal 2, step2.position
155 end 155 end
156 156
157 should 'accept comments if step is active' do 157 should 'accept comments if step is active' do
158 - @step.start_date = Date.today 158 + @step.start_date = DateTime.now
159 @step.save! 159 @step.save!
160 refute @step.accept_comments 160 refute @step.accept_comments
161 @step.toggle_activation 161 @step.toggle_activation
@@ -164,8 +164,8 @@ class StepTest &lt; ActiveSupport::TestCase @@ -164,8 +164,8 @@ class StepTest &lt; ActiveSupport::TestCase
164 end 164 end
165 165
166 should 'do not accept comments if step is not active' do 166 should 'do not accept comments if step is not active' do
167 - @step.start_date = Date.today + 2.days  
168 - @step.end_date = Date.today + 3.days 167 + @step.start_date = DateTime.now + 2.days
  168 + @step.end_date = DateTime.now + 3.days
169 @step.save! 169 @step.save!
170 refute @step.published 170 refute @step.published
171 @step.toggle_activation 171 @step.toggle_activation
@@ -174,14 +174,14 @@ class StepTest &lt; ActiveSupport::TestCase @@ -174,14 +174,14 @@ class StepTest &lt; ActiveSupport::TestCase
174 end 174 end
175 175
176 should 'do not accept comments if step is not active anymore' do 176 should 'do not accept comments if step is not active anymore' do
177 - @step.start_date = Date.today 177 + @step.end_date = DateTime.now.end_of_day
178 @step.save! 178 @step.save!
179 @step.toggle_activation 179 @step.toggle_activation
180 @step.reload 180 @step.reload
181 assert @step.accept_comments 181 assert @step.accept_comments
182 182
183 - @step.start_date = Date.today - 2.days  
184 - @step.end_date = Date.today - 1.day 183 + @step.start_date = DateTime.now - 2.days
  184 + @step.end_date = DateTime.now - 1.day
185 @step.save! 185 @step.save!
186 @step.toggle_activation 186 @step.toggle_activation
187 @step.reload 187 @step.reload
@@ -203,7 +203,7 @@ class StepTest &lt; ActiveSupport::TestCase @@ -203,7 +203,7 @@ class StepTest &lt; ActiveSupport::TestCase
203 end 203 end
204 204
205 should 'change position to botton if a hidden step becomes visible' do 205 should 'change position to botton if a hidden step becomes visible' do
206 - step1 = CommunityTrackPlugin::Step.new(:name => 'Step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today) 206 + step1 = CommunityTrackPlugin::Step.new(:name => 'Step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => DateTime.now.end_of_day, :start_date => DateTime.now.beginning_of_day)
207 step1.save! 207 step1.save!
208 @step.hidden = true 208 @step.hidden = true
209 @step.save! 209 @step.save!
@@ -215,7 +215,7 @@ class StepTest &lt; ActiveSupport::TestCase @@ -215,7 +215,7 @@ class StepTest &lt; ActiveSupport::TestCase
215 215
216 should 'decrement lower items positions if a step becomes hidden' do 216 should 'decrement lower items positions if a step becomes hidden' do
217 @step.save! 217 @step.save!
218 - step1 = CommunityTrackPlugin::Step.new(:name => 'Step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today) 218 + step1 = CommunityTrackPlugin::Step.new(:name => 'Step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => DateTime.now.end_of_day, :start_date => DateTime.now.beginning_of_day)
219 step1.save! 219 step1.save!
220 assert_equal 2, step1.position 220 assert_equal 2, step1.position
221 @step.hidden = true 221 @step.hidden = true
@@ -225,7 +225,7 @@ class StepTest &lt; ActiveSupport::TestCase @@ -225,7 +225,7 @@ class StepTest &lt; ActiveSupport::TestCase
225 end 225 end
226 226
227 should 'do not publish a hidden step' do 227 should 'do not publish a hidden step' do
228 - @step.start_date = Date.today 228 + @step.start_date = DateTime.now
229 @step.hidden = true 229 @step.hidden = true
230 @step.save! 230 @step.save!
231 refute @step.published 231 refute @step.published
@@ -266,7 +266,7 @@ class StepTest &lt; ActiveSupport::TestCase @@ -266,7 +266,7 @@ class StepTest &lt; ActiveSupport::TestCase
266 end 266 end
267 267
268 should 'enable comments on children when step is activated' do 268 should 'enable comments on children when step is activated' do
269 - @step.start_date = Date.today 269 + @step.start_date = DateTime.now
270 @step.save! 270 @step.save!
271 refute @step.accept_comments 271 refute @step.accept_comments
272 article = fast_create(Article, :parent_id => @step.id, :profile_id => @step.profile.id, :accept_comments => false) 272 article = fast_create(Article, :parent_id => @step.id, :profile_id => @step.profile.id, :accept_comments => false)
@@ -276,8 +276,7 @@ class StepTest &lt; ActiveSupport::TestCase @@ -276,8 +276,7 @@ class StepTest &lt; ActiveSupport::TestCase
276 end 276 end
277 277
278 should 'enable comments on children when step is active' do 278 should 'enable comments on children when step is active' do
279 - @step.start_date = Date.today  
280 - @step.start_date = Date.today 279 + @step.start_date = DateTime.now
281 @step.save! 280 @step.save!
282 refute @step.accept_comments 281 refute @step.accept_comments
283 @step.toggle_activation 282 @step.toggle_activation
plugins/environment_notification/controllers/environment_notification_plugin_admin_controller.rb 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  1 +class EnvironmentNotificationPluginAdminController < AdminController
  2 + before_filter :admin_required, :except => [:hide_notification]
  3 + def index
  4 + @notifications = environment.environment_notifications.order('updated_at DESC')
  5 + end
  6 +
  7 + def new
  8 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.new
  9 + if request.post?
  10 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.new(params[:notifications])
  11 + @notification.message = @notification.message.html_safe
  12 + @notification.environment_id = environment.id
  13 + if @notification.save
  14 + session[:notice] = _("Notification successfully created")
  15 + redirect_to :action => :index
  16 + else
  17 + session[:notice] = _("Notification couldn't be created")
  18 + end
  19 + end
  20 + end
  21 +
  22 + def destroy
  23 + if request.delete?
  24 + notification = environment.environment_notifications.find_by_id(params[:id])
  25 + if notification && notification.destroy
  26 + session[:notice] = _('The notification was deleted.')
  27 + else
  28 + session[:notice] = _('Could not remove the notification')
  29 + end
  30 + end
  31 + redirect_to :action => :index
  32 + end
  33 +
  34 + def edit
  35 + @notification = environment.environment_notifications.find_by_id(params[:id])
  36 + if request.post?
  37 + if @notification.update_attributes(params[:notifications])
  38 + session[:notice] = _('The notification was edited.')
  39 + else
  40 + session[:notice] = _('Could not edit the notification.')
  41 + end
  42 + redirect_to :action => :index
  43 + end
  44 + end
  45 +
  46 + def change_status
  47 + @notification = environment.environment_notifications.find_by_id(params[:id])
  48 +
  49 + @notification.active = !@notification.active
  50 +
  51 + if @notification.save!
  52 + session[:notice] = _('The status of the notification was changed.')
  53 + else
  54 + session[:notice] = _('Could not change the status of the notification.')
  55 + end
  56 +
  57 + redirect_to :action => :index
  58 + end
  59 +
  60 + def hide_notification
  61 + result = false
  62 +
  63 + if logged_in?
  64 + @notification = environment.environment_notifications.find_by_id(params[:notification_id])
  65 +
  66 + if @notification
  67 + @notification.users << current_user
  68 + result = @notification.users.include?(current_user)
  69 + end
  70 + end
  71 +
  72 + render json: result
  73 + end
  74 +
  75 + protected
  76 + def admin_required
  77 + redirect_to :root unless current_user.person.is_admin?
  78 + end
  79 +
  80 +end
plugins/environment_notification/db/migrate/20150721132025_create_notification_table.rb 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +class CreateNotificationTable < ActiveRecord::Migration
  2 + def up
  3 + create_table :environment_notifications do |t|
  4 + t.text :message
  5 + t.integer :environment_id
  6 + t.string :type
  7 + t.boolean :active
  8 + t.boolean :display_only_in_homepage, :default => false
  9 + t.boolean :display_to_all_users, :default => false
  10 + t.column :created_at, :datetime
  11 + t.column :updated_at, :datetime
  12 + end
  13 +
  14 + create_table :environment_notifications_users, id: false do |t|
  15 + t.belongs_to :environment_notification, index: true
  16 + t.belongs_to :user, index: true
  17 + end
  18 + end
  19 +
  20 + def down
  21 + drop_table :environment_notifications
  22 + drop_table :environment_notifications_users
  23 + end
  24 +end
plugins/environment_notification/lib/environment_notification_plugin.rb 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +class EnvironmentNotificationPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + "Environment Notifications Plugin"
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("A plugin for environment notifications.")
  9 + end
  10 +
  11 + def stylesheet?
  12 + true
  13 + end
  14 +
  15 + def js_files
  16 + %w(
  17 + public/environment_notification_plugin.js
  18 + )
  19 + end
  20 +
  21 + def body_beginning
  22 + expanded_template('environment_notification_plugin_admin/show_notification.html.erb')
  23 + end
  24 +
  25 + def admin_panel_links
  26 + {:title => _('Notification Manager'), :url => {:controller => 'environment_notification_plugin_admin', :action => 'index'}}
  27 + end
  28 +
  29 +end
plugins/environment_notification/lib/environment_notifications_user.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class EnvironmentNotificationsUser < ActiveRecord::Base
  2 + self.table_name = "environment_notifications_users"
  3 +
  4 + belongs_to :user
  5 + belongs_to :environment_notification, class_name: 'EnvironmentNotificationPlugin::EnvironmentNotification'
  6 +
  7 + attr_accessible :user_id, :environment_notification_id
  8 +
  9 + validates_uniqueness_of :user_id, :scope => :environment_notification_id
  10 +end
plugins/environment_notification/lib/ext/environment.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +require_dependency 'environment'
  2 +
  3 +class Environment
  4 + has_many :environment_notifications, class_name: 'EnvironmentNotificationPlugin::EnvironmentNotification'
  5 +end
plugins/environment_notification/lib/ext/user.rb 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +require_dependency 'user'
  2 +
  3 +class User
  4 + has_many :environment_notifications_users
  5 + has_many :environment_notifications, :through => :environment_notifications_users
  6 +end
plugins/environment_notification/models/environment_notification_plugin/danger_notification.rb 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +class EnvironmentNotificationPlugin::DangerNotification < EnvironmentNotificationPlugin::EnvironmentNotification
  2 +end
plugins/environment_notification/models/environment_notification_plugin/environment_notification.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +class EnvironmentNotificationPlugin::EnvironmentNotification < ActiveRecord::Base
  2 +
  3 + self.table_name = "environment_notifications"
  4 +
  5 + TYPE_LIST = [
  6 + "EnvironmentNotificationPlugin::WarningNotification",
  7 + "EnvironmentNotificationPlugin::SuccessNotification",
  8 + "EnvironmentNotificationPlugin::InformationNotification",
  9 + "EnvironmentNotificationPlugin::DangerNotification"
  10 + ]
  11 +
  12 + attr_accessible :message, :environment_id, :active, :type, :display_only_in_homepage, :display_to_all_users
  13 +
  14 + has_many :environment_notifications_users
  15 + has_many :users, :through => :environment_notifications_users
  16 +
  17 + validates_presence_of :message
  18 + validates_presence_of :environment_id
  19 + validate :notification_type_must_be_in_type_list
  20 +
  21 + def notification_type_must_be_in_type_list
  22 + unless TYPE_LIST.include?(type)
  23 + errors.add(:type, "invalid notification type")
  24 + end
  25 + end
  26 +
  27 +end
plugins/environment_notification/models/environment_notification_plugin/information_notification.rb 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +class EnvironmentNotificationPlugin::InformationNotification < EnvironmentNotificationPlugin::EnvironmentNotification
  2 +end
plugins/environment_notification/models/environment_notification_plugin/success_notification.rb 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +class EnvironmentNotificationPlugin::SuccessNotification < EnvironmentNotificationPlugin::EnvironmentNotification
  2 +end
plugins/environment_notification/models/environment_notification_plugin/warning_notification.rb 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +class EnvironmentNotificationPlugin::WarningNotification < EnvironmentNotificationPlugin::EnvironmentNotification
  2 +end
plugins/environment_notification/public/environment_notification_plugin.js 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +(function($) {
  2 + "use strict";
  3 +
  4 + function notificationBar() {
  5 + var completeMessage = $(".notification-bar").remove();
  6 + $("#content-inner").before(completeMessage);
  7 + },
  8 +
  9 + function hideNotification(){
  10 + var notification = $(this).parent();
  11 + var id = notification.attr("data-notification");
  12 +
  13 + $.ajax({
  14 + url: noosfero_root()+"/admin/plugin/environment_notification/hide_notification",
  15 + type: "POST",
  16 + data: {notification_id: id},
  17 + success: function(response) {
  18 + notification.fadeOut();
  19 + }
  20 + });
  21 + }
  22 +
  23 + function mceRestrict() {
  24 + tinyMCE.init({
  25 + menubar : false,
  26 + selector: "textarea",
  27 + plugins: [
  28 + "autolink link"
  29 + ],
  30 + toolbar: "bold italic underline | link"
  31 + });
  32 + }
  33 +
  34 + jQuery(document).ready(function(){
  35 + notificationBar();
  36 + $(".notification-close").on("click", hideNotification);
  37 + mceRestrict();
  38 + });
  39 +
  40 +})(jQuery);
0 \ No newline at end of file 41 \ No newline at end of file
plugins/environment_notification/public/images/close.png 0 → 100644

240 Bytes

plugins/environment_notification/public/images/hide.png 0 → 100644

389 Bytes

plugins/environment_notification/public/images/show.png 0 → 100644

364 Bytes

plugins/environment_notification/style.css 0 → 100644
@@ -0,0 +1,141 @@ @@ -0,0 +1,141 @@
  1 +.notification-bar {
  2 + display: block;
  3 +}
  4 +
  5 +.notification:hover {
  6 + opacity: 0.8;
  7 +}
  8 +
  9 +#notification-manager {
  10 + overflow: auto;
  11 +}
  12 +
  13 +.notification .notification-close {
  14 + background: url(public/images/close.png) no-repeat;
  15 + background-position: center;
  16 + width: 20px;
  17 + height: 20px;
  18 +}
  19 +
  20 +.warningnotification,
  21 +.informationnotification,
  22 +.successnotification,
  23 +.dangernotification {
  24 + margin-bottom: 10px;
  25 + padding: 7px 10px;
  26 + border-radius: 5px;
  27 + border: 1px solid blue;
  28 + font-size: 16px;
  29 + color: white;
  30 + overflow: auto;
  31 +}
  32 +
  33 +.warningnotification p,
  34 +.informationnotification p,
  35 +.successnotification p,
  36 +.dangernotification p {
  37 + margin: 0px;
  38 +}
  39 +
  40 +.warningnotification {
  41 + background: #EEA236;
  42 + border: 1px solid #EEA236;
  43 +}
  44 +
  45 +.informationnotification {
  46 + background: #5BC0DE;
  47 + border: 1px solid #46B8DA;
  48 +}
  49 +
  50 +.successnotification {
  51 + background: #5CB85C;
  52 + border: 1px solid #4CAE4C;
  53 +}
  54 +
  55 +.dangernotification {
  56 + background: #C9302C;
  57 + border: 1px solid #AC2925;
  58 +}
  59 +
  60 +a.button.icon-deactivate {
  61 + background: url(public/images/hide.png) no-repeat;
  62 + background-position: center;
  63 +}
  64 +
  65 +a.button.icon-activate {
  66 + background: url(public/images/show.png) no-repeat;
  67 + background-position: center;
  68 +}
  69 +
  70 +.notification-line {
  71 + display: inline;
  72 + padding-top: 10px;
  73 + vertical-align: middle;
  74 + border-bottom: 1px solid #ccc;
  75 +}
  76 +
  77 +.notification-title-bar {
  78 + float: left;
  79 + width: 100%;
  80 + font-style: 14px;
  81 + font-weight: 700;
  82 + border-bottom: 2px solid black;
  83 + padding: 9px 0;
  84 +}
  85 +
  86 +.notification-title {
  87 + width: 80%;
  88 + float: left;
  89 + text-align: center;
  90 +}
  91 +
  92 +.action-title {
  93 + width: 20%;
  94 + float: left;
  95 + text-align: center;
  96 +}
  97 +
  98 +.notification-action {
  99 + width: 18%;
  100 + float: left;
  101 + height: 30px;
  102 + padding-top: 9px;
  103 +}
  104 +
  105 +.main-bar .button,
  106 +.notification-action .button {
  107 + border-radius: 3px;
  108 +}
  109 +
  110 +.notification-message {
  111 + width: 82%;
  112 + float: left;
  113 +}
  114 +
  115 +.new-notification {
  116 + float: right;
  117 + width: auto;
  118 +}
  119 +
  120 +.back-button {
  121 + float: left;
  122 +}
  123 +
  124 +.main-bar {
  125 + display: inline;
  126 + width: 100%;
  127 +}
  128 +
  129 +.notification-bar .notification .notification-message {
  130 + width: 90%;
  131 + float: left;
  132 +}
  133 +
  134 +.notification-bar .notification .notification-close {
  135 + background: url(public/images/close.png) no-repeat;
  136 + background-position: center;
  137 + width: 20px;
  138 + height: 20px;
  139 + float: right;
  140 + cursor: pointer;
  141 +}
plugins/environment_notification/test/functional/environment_notification_plugin_admin_controller_test.rb 0 → 100644
@@ -0,0 +1,153 @@ @@ -0,0 +1,153 @@
  1 +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper'
  2 +require(
  3 + File.expand_path(File.dirname(__FILE__)) +
  4 + '/../../controllers/environment_notification_plugin_admin_controller'
  5 +)
  6 +
  7 +class EnvironmentNotificationPluginAdminController; def rescue_action(e) raise e end;
  8 +end
  9 +
  10 +class EnvironmentNotificationPluginAdminControllerTest < ActionController::TestCase
  11 + def setup
  12 + @controller = EnvironmentNotificationPluginAdminController.new
  13 + @request = ActionController::TestRequest.new
  14 + @response = ActionController::TestResponse.new
  15 + @person = create_user('person').person
  16 +
  17 + @environment = Environment.default
  18 + @environment.enable_plugin('EnvironmentNotificationPlugin')
  19 + @environment.save!
  20 +
  21 + login_as(@person.user.login)
  22 + end
  23 +
  24 + attr_accessor :person
  25 +
  26 + should 'an admin be able to create a notification' do
  27 + @environment.add_admin(@person)
  28 + post :new, :notifications => {
  29 + :message => "Message",
  30 + :active => true,
  31 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  32 + }
  33 + assert_redirected_to :action => 'index'
  34 + notification = EnvironmentNotificationPlugin::EnvironmentNotification.last
  35 + assert_equal "Message", notification.message
  36 + assert notification.active
  37 + assert_equal "EnvironmentNotificationPlugin::DangerNotification", notification.type
  38 + end
  39 +
  40 + should 'an user not to be able to create a notification' do
  41 + post :new, :notifications => {
  42 + :message => "Message",
  43 + :active => true,
  44 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  45 + }
  46 + assert_redirected_to :root
  47 + assert_nil EnvironmentNotificationPlugin::EnvironmentNotification.last
  48 + end
  49 +
  50 + should 'an admin be able to edit a notification' do
  51 + @environment.add_admin(@person)
  52 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  53 + :environment_id => @environment.id,
  54 + :message => "Message",
  55 + :active => true,
  56 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  57 + )
  58 + post :edit, :id => @notification.id, :notifications => {
  59 + :message => "Edited Message",
  60 + :active => false,
  61 + :type => "EnvironmentNotificationPlugin::WarningNotification"
  62 + }
  63 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.last
  64 + assert_redirected_to :action => 'index'
  65 + assert_equal "Edited Message", @notification.message
  66 + assert !@notification.active
  67 + assert_equal "EnvironmentNotificationPlugin::WarningNotification", @notification.type
  68 + end
  69 +
  70 + should 'an user not to be able to edit a notification' do
  71 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  72 + :environment_id => @environment.id,
  73 + :message => "Message",
  74 + :active => true,
  75 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  76 + )
  77 + post :edit, :notifications => {
  78 + :message => "Edited Message",
  79 + :active => false,
  80 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  81 + }
  82 + @notification.reload
  83 + assert_redirected_to :root
  84 + assert_equal "Message", @notification.message
  85 + assert @notification.active
  86 + end
  87 +
  88 + should 'an admin be able to destroy a notification' do
  89 + @environment.add_admin(@person)
  90 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  91 + :environment_id => @environment.id,
  92 + :message => "Message",
  93 + :active => true,
  94 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  95 + )
  96 + delete :destroy, :id => @notification.id
  97 + assert_nil EnvironmentNotificationPlugin::EnvironmentNotification.find_by_id(@notification.id)
  98 + end
  99 +
  100 + should 'an user not to be able to destroy a notification' do
  101 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  102 + :environment_id => @environment.id,
  103 + :message => "Message",
  104 + :active => true,
  105 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  106 + )
  107 + delete :destroy, :id => @notification.id
  108 +
  109 + assert_redirected_to :root
  110 + assert_not_nil EnvironmentNotificationPlugin::EnvironmentNotification.find_by_id(@notification.id)
  111 + end
  112 +
  113 + should 'an admin be able to change Notification status' do
  114 + @environment.add_admin(@person)
  115 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  116 + :environment_id => @environment.id,
  117 + :message => "Message",
  118 + :active => true,
  119 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  120 + )
  121 + post :change_status, :id => @notification.id
  122 + assert_redirected_to :action => 'index'
  123 +
  124 + @notification.reload
  125 + assert !@notification.active
  126 + end
  127 +
  128 + should 'an user not be able to change Notification status' do
  129 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  130 + :environment_id => @environment.id,
  131 + :message => "Message",
  132 + :active => true,
  133 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  134 + )
  135 + post :change_status, :id => @notification.id
  136 + assert_redirected_to :root
  137 +
  138 + @notification.reload
  139 + assert @notification.active
  140 + end
  141 +
  142 + should 'a logged in user be able to permanently hide notifications' do
  143 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  144 + :environment_id => @environment.id,
  145 + :message => "Message",
  146 + :active => true,
  147 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  148 + )
  149 + post :hide_notification, :notification_id => @notification.id
  150 + assert_equal "true", @response.body
  151 + assert_equal true, @notification.users.include?(@person.user)
  152 + end
  153 +end
plugins/environment_notification/test/functional/home_controller_test.rb 0 → 100644
@@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
  1 +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper'
  2 +require 'home_controller'
  3 +
  4 +class HomeController; def rescue_action(e) raise e end;
  5 +end
  6 +
  7 +class HomeControllerTest < ActionController::TestCase
  8 + def setup
  9 + @controller = HomeController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 + @person = create_user('person').person
  13 +
  14 + @environment = Environment.default
  15 + @environment.enable_plugin('EnvironmentNotificationPlugin')
  16 + @environment.save!
  17 + end
  18 +
  19 + attr_accessor :person
  20 +
  21 + should 'an active notification be displayed on home page for a logged in user' do
  22 + login_as(@person.user.login)
  23 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  24 + :environment_id => @environment.id,
  25 + :message => "Hello, this is a Notification Message",
  26 + :active => true,
  27 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  28 + )
  29 + get :index
  30 + assert_match /Hello, this is a Notification Message/, @response.body
  31 + end
  32 +
  33 +
  34 + should 'an active notification not be displayed on home page for unlogged user' do
  35 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  36 + :environment_id => @environment.id,
  37 + :message => "Hello, this is a Notification Message",
  38 + :active => true,
  39 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  40 + )
  41 + get :index
  42 + assert_no_match /Hello, this is a Notification Message/, @response.body
  43 + end
  44 +
  45 + should 'an active notification be displayed on home page for unlogged user' do
  46 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  47 + :environment_id => @environment.id,
  48 + :message => "Hello, this is a Notification Message",
  49 + :display_to_all_users => true,
  50 + :active => true,
  51 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  52 + )
  53 + get :index
  54 + assert_match /Hello, this is a Notification Message/, @response.body
  55 + end
  56 +
  57 + should 'only display the notification with display_to_all_users option for unlogged user ' do
  58 + @notification1 = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  59 + :environment_id => @environment.id,
  60 + :message => "Hello, this is an old Notification Message",
  61 + :active => true,
  62 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  63 + )
  64 +
  65 + @notification2 = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  66 + :environment_id => @environment.id,
  67 + :message => "Hello, this is a new Notification Message",
  68 + :display_to_all_users => true,
  69 + :active => true,
  70 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  71 + )
  72 +
  73 +
  74 + get :index
  75 + assert_no_match /Hello, this is a Notification Message/, @response.body
  76 + assert_match /Hello, this is a new Notification Message/, @response.body
  77 + end
  78 +
  79 + should 'an inactive notification not be displayed on home page' do
  80 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  81 + :environment_id => @environment.id,
  82 + :message => "Hello, this is a Notification Message",
  83 + :active => false,
  84 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  85 + )
  86 + get :index
  87 + assert_no_match /Hello, this is a Notification Message/, @response.body
  88 + end
  89 +
  90 +
  91 + should 'an active notification not be displayed to a logged in user after been closed by him' do
  92 + login_as(@person.user.login)
  93 + @notification = EnvironmentNotificationPlugin::EnvironmentNotification.create(
  94 + :environment_id => @environment.id,
  95 + :message => "Hello, this is a Notification Message",
  96 + :active => true,
  97 + :type => "EnvironmentNotificationPlugin::DangerNotification"
  98 + )
  99 + @notification.users << @person.user
  100 + @notification.save!
  101 + assert_equal true, @notification.users.include?(@person.user)
  102 + get :index
  103 + assert_no_match /Hello, this is a Notification Message/, @response.body
  104 + end
  105 +end
plugins/environment_notification/views/environment_notification_plugin_admin/_form.html.erb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +<% abstract_options = {:value => @notification.message, :style => 'width: 100%; height: 200px;'} %>
  2 +
  3 +<%= button :back, _('Back'), :controller => 'environment_notification_plugin_admin' %>
  4 +
  5 +<%= form_for :notifications do |f| %>
  6 +
  7 + <%= render :file => 'shared/tiny_mce' %>
  8 +
  9 + <%= labelled_form_field(_("Enter your message here:"), f.text_area(:message, abstract_options)) %>
  10 +
  11 + <%= labelled_form_field(_('Notifications Status'), select(:notifications, :active, options_for_select_with_title({"Active" => true, "Inactive" => false}, @notification.active))) %>
  12 +
  13 + <%= labelled_form_field(_('Notifications Type'), select(:notifications, :type, options_for_select_with_title({"Information" => "EnvironmentNotificationPlugin::InformationNotification", "Warning" => "EnvironmentNotificationPlugin::WarningNotification", "Success" => "EnvironmentNotificationPlugin::SuccessNotification", "Danger" => "EnvironmentNotificationPlugin::DangerNotification"}, @notification.type))) %>
  14 +
  15 + <div>
  16 + <%= labelled_check_box(_("Display only in the homepage"), 'notifications[display_only_in_homepage]', '1', @notification.display_only_in_homepage?) %>
  17 + </div>
  18 +
  19 + <div>
  20 + <%= labelled_check_box(_("Display to not logged users too"), 'notifications[display_to_all_users]', '1', @notification.display_to_all_users?) %>
  21 + </div>
  22 +
  23 + <% button_bar do %>
  24 + <%= submit_button 'save', _('Save'), :cancel => { :action => 'index' } %>
  25 + <% end %>
  26 +
  27 +<% end %>
plugins/environment_notification/views/environment_notification_plugin_admin/edit.html.erb 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<%= render :partial => "form" %>
plugins/environment_notification/views/environment_notification_plugin_admin/index.html.erb 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +<div id="notification-manager">
  2 + <div class="notification-manager-title">
  3 + <h1><%= _("Environment Notifications") %></h1>
  4 + </div>
  5 + <div class="buttons-bar">
  6 + <div class="new-notification">
  7 + <%= button :new, _('New Notification'), {:action => :new}, :method => :get %>
  8 + </div>
  9 + <div class="back-button">
  10 + <%= button :back, _('Back to control panel'), {:controller => 'admin_panel', :action => :index}, :method => :get %>
  11 + </div>
  12 + </div>
  13 +
  14 + <div class="notification-title-bar">
  15 + <div class="notification-title">
  16 + <%= _('Notifications') %>
  17 + </div>
  18 + <div class="action-title">
  19 + <%= _('Actions') %>
  20 + </div>
  21 + </div>
  22 +
  23 + <% @notifications.each do |notification| %>
  24 + <div class="notification-line">
  25 + <div class="notification-message">
  26 + <%= truncate(notification.message, length: 50) %>
  27 + </div>
  28 + <div class="notification-action">
  29 + <% if notification.active? %>
  30 + <%= button_without_text :deactivate, _('Deactivate'), {:action => :change_status, :id => notification}, :method => :post, :confirm => _("Do you want to change the status of this notification?") %>
  31 + <% else %>
  32 + <%= button_without_text :activate, _('Activate'), {:action => :change_status, :id => notification}, :method => :post, :confirm => _("Do you want to change the status of this notification?") %>
  33 + <% end %>
  34 + <%= button_without_text :edit, _('Edit'), {:action => 'edit', :id => notification.id} if !remove_content_button(:edit, notification) %>
  35 + <%= button_without_text :delete, _('Delete'), {:action => :destroy, :id => notification}, :method => :delete, :confirm => _("Do you want to delete this notification?") %>
  36 + </div>
  37 + </div>
  38 + <% end %>
  39 +</div>
  40 +
plugins/environment_notification/views/environment_notification_plugin_admin/new.html.erb 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<%= render :partial => "form" %>
plugins/environment_notification/views/environment_notification_plugin_admin/show_notification.html.erb 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +<div class="notification-bar">
  2 + <% if logged_in? %>
  3 + <% @notifications = environment.environment_notifications.order('updated_at DESC').where(active: true) %>
  4 + <% @deactivated = current_user.environment_notifications %>
  5 + <% @notifications = @notifications - @deactivated %>
  6 + <% else %>
  7 + <% @notifications = environment.environment_notifications.order('updated_at DESC').where(active: true) %>
  8 + <% end %>
  9 +
  10 + <% @notifications.each do |notification| %>
  11 + <% if controller_path == "home" || !notification.display_only_in_homepage? %>
  12 + <% if logged_in? || notification.display_to_all_users? %>
  13 + <div class="<%= notification.type.gsub("EnvironmentNotificationPlugin::", "").downcase %> notification" data-notification="<%=notification.id%>">
  14 + <div class="notification-message">
  15 + <%= notification.message %>
  16 + </div>
  17 + <% if logged_in? %>
  18 + <div class="notification-close"></div>
  19 + <% end %>
  20 + </div>
  21 + <% end %>
  22 + <% end %>
  23 + <% end %>
  24 +</div>
plugins/event/lib/event_plugin/event_block.rb
@@ -30,13 +30,13 @@ class EventPlugin::EventBlock &lt; Block @@ -30,13 +30,13 @@ class EventPlugin::EventBlock &lt; Block
30 events = user.nil? ? events.public : events.display_filter(user,nil) 30 events = user.nil? ? events.public : events.display_filter(user,nil)
31 31
32 if future_only 32 if future_only
33 - events = events.where('start_date >= ?', Date.today) 33 + events = events.where('start_date >= ?', DateTime.now.beginning_of_day)
34 end 34 end
35 35
36 if date_distance_limit > 0 36 if date_distance_limit > 0
37 events = events.by_range([ 37 events = events.by_range([
38 - Date.today - date_distance_limit,  
39 - Date.today + date_distance_limit 38 + DateTime.now.beginning_of_day - date_distance_limit,
  39 + DateTime.now.beginning_of_day + date_distance_limit
40 ]) 40 ])
41 end 41 end
42 42
plugins/event/test/functional/event_block_test.rb
1 require File.dirname(__FILE__) + '/../../../../test/test_helper' 1 require File.dirname(__FILE__) + '/../../../../test/test_helper'
2 2
  3 +
3 # Re-raise errors caught by the controller. 4 # Re-raise errors caught by the controller.
4 class HomeController 5 class HomeController
5 - #append_view_path File.join(File.dirname(__FILE__) + '/../../views') 6 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
6 def rescue_action(e) 7 def rescue_action(e)
7 raise e 8 raise e
8 end 9 end
@@ -15,7 +16,7 @@ class HomeControllerTest &lt; ActionController::TestCase @@ -15,7 +16,7 @@ class HomeControllerTest &lt; ActionController::TestCase
15 @env.enable_plugin('EventPlugin') 16 @env.enable_plugin('EventPlugin')
16 17
17 @p1 = fast_create(Person, :environment_id => @env.id) 18 @p1 = fast_create(Person, :environment_id => @env.id)
18 - @e1a = fast_create(Event, :name=>'Event p1 A', :profile_id=>@p1.id) 19 + @e1a = Event.create!(:name=>'Event p1 A', :profile =>@p1)
19 20
20 box = Box.create!(:owner => @env) 21 box = Box.create!(:owner => @env)
21 @block = EventPlugin::EventBlock.create!(:box => box) 22 @block = EventPlugin::EventBlock.create!(:box => box)
@@ -27,6 +28,7 @@ class HomeControllerTest &lt; ActionController::TestCase @@ -27,6 +28,7 @@ class HomeControllerTest &lt; ActionController::TestCase
27 28
28 should 'see events microdata sturcture' do 29 should 'see events microdata sturcture' do
29 get :index 30 get :index
  31 +#raise response.body.inspect
30 assert_select '.event-plugin_event-block ul.events' 32 assert_select '.event-plugin_event-block ul.events'
31 assert_select ev 33 assert_select ev
32 assert_select ev + 'a[itemprop="url"]' 34 assert_select ev + 'a[itemprop="url"]'
@@ -41,15 +43,15 @@ class HomeControllerTest &lt; ActionController::TestCase @@ -41,15 +43,15 @@ class HomeControllerTest &lt; ActionController::TestCase
41 43
42 should 'see event duration' do 44 should 'see event duration' do
43 @e1a.slug = 'event1a' 45 @e1a.slug = 'event1a'
44 - @e1a.start_date = Date.today  
45 - @e1a.end_date = Date.today + 1.day 46 + @e1a.start_date = DateTime.now
  47 + @e1a.end_date = DateTime.now + 1.day
46 @e1a.save! 48 @e1a.save!
47 get :index 49 get :index
48 assert_select ev + 'time.duration[itemprop="endDate"]', /1 day/ 50 assert_select ev + 'time.duration[itemprop="endDate"]', /1 day/
49 51
50 @e1a.slug = 'event1a' 52 @e1a.slug = 'event1a'
51 - @e1a.start_date = Date.today  
52 - @e1a.end_date = Date.today + 2.day 53 + @e1a.start_date = DateTime.now
  54 + @e1a.end_date = DateTime.now + 2.day
53 @e1a.save! 55 @e1a.save!
54 get :index 56 get :index
55 assert_select ev + 'time.duration[itemprop="endDate"]', /2 days/ 57 assert_select ev + 'time.duration[itemprop="endDate"]', /2 days/
@@ -60,8 +62,8 @@ class HomeControllerTest &lt; ActionController::TestCase @@ -60,8 +62,8 @@ class HomeControllerTest &lt; ActionController::TestCase
60 assert_select ev + 'time.duration[itemprop="endDate"]', false 62 assert_select ev + 'time.duration[itemprop="endDate"]', false
61 63
62 @e1a.slug = 'event1a' 64 @e1a.slug = 'event1a'
63 - @e1a.start_date = Date.today  
64 - @e1a.end_date = Date.today 65 + @e1a.start_date = DateTime.now
  66 + @e1a.end_date = DateTime.now
65 @e1a.save! 67 @e1a.save!
66 get :index 68 get :index
67 assert_select ev + 'time.duration[itemprop="endDate"]', false 69 assert_select ev + 'time.duration[itemprop="endDate"]', false
plugins/event/views/blocks/event.html.erb
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 <ul class="events"> 3 <ul class="events">
4 <% block.events(user).map do |event| %> 4 <% block.events(user).map do |event| %>
5 - <% days_left = ( event.start_date - Date.today ).round %> 5 + <% days_left = ( (event.start_date - DateTime.now)/60/60/24 ).round %>
6 <li itemscope="itemscope" itemtype="http://data-vocabulary.org/Event" class="event"> 6 <li itemscope="itemscope" itemtype="http://data-vocabulary.org/Event" class="event">
7 <%= render( 7 <%= render(
8 :file => 'event_plugin/event_block_item', 8 :file => 'event_plugin/event_block_item',
plugins/metadata/lib/ext/article.rb
@@ -12,9 +12,9 @@ class Article @@ -12,9 +12,9 @@ class Article
12 end, 12 end,
13 title: proc{ |a, plugin| "#{a.title} - #{a.profile.name}" }, 13 title: proc{ |a, plugin| "#{a.title} - #{a.profile.name}" },
14 image: proc do |a, plugin| 14 image: proc do |a, plugin|
15 - img = a.body_images_paths  
16 - img = "#{a.profile.environment.top_url}#{a.profile.image.public_filename}" if a.profile.image if img.blank?  
17 - img ||= MetadataPlugin.config[:open_graph][:environment_logo] rescue nil if img.blank? 15 + img = a.body_images_paths.map! &:html_safe
  16 + img = "#{a.profile.environment.top_url}#{a.profile.image.public_filename}".html_safe if a.profile.image if img.blank?
  17 + img ||= MetadataPlugin.config[:open_graph][:environment_logo].html_safe rescue nil if img.blank?
18 img 18 img
19 end, 19 end,
20 see_also: [], 20 see_also: [],
@@ -31,10 +31,10 @@ class Article @@ -31,10 +31,10 @@ class Article
31 card: 'summary', 31 card: 'summary',
32 description: proc do |a, plugin| 32 description: proc do |a, plugin|
33 description = a.body.to_s || a.environment.name 33 description = a.body.to_s || a.environment.name
34 - CGI.escapeHTML(plugin.helpers.truncate(plugin.helpers.strip_tags(description), length: 200)) 34 + plugin.helpers.truncate plugin.helpers.strip_tags(description), length: 200
35 end, 35 end,
36 title: proc{ |a, plugin| "#{a.title} - #{a.profile.name}" }, 36 title: proc{ |a, plugin| "#{a.title} - #{a.profile.name}" },
37 - image: proc{ |a, plugin| a.body_images_paths }, 37 + image: proc{ |a, plugin| a.body_images_paths.map! &:html_safe },
38 } 38 }
39 39
40 metadata_spec namespace: :article, key_attr: :property, tags: { 40 metadata_spec namespace: :article, key_attr: :property, tags: {
plugins/metadata/lib/ext/product.rb
@@ -14,8 +14,8 @@ class Product @@ -14,8 +14,8 @@ class Product
14 description: proc{ |p, plugin| ActionView::Base.full_sanitizer.sanitize p.description }, 14 description: proc{ |p, plugin| ActionView::Base.full_sanitizer.sanitize p.description },
15 15
16 image: proc do |p, plugin| 16 image: proc do |p, plugin|
17 - img = "#{p.environment.top_url}#{p.image.public_filename}" if p.image  
18 - img = "#{p.environment.top_url}#{p.profile.image.public_filename}" if img.blank? and p.profile.image 17 + img = "#{p.environment.top_url}#{p.image.public_filename}".html_safe if p.image
  18 + img = "#{p.environment.top_url}#{p.profile.image.public_filename}".html_safe if img.blank? and p.profile.image
19 img ||= MetadataPlugin.config[:open_graph][:environment_logo] rescue nil if img.blank? 19 img ||= MetadataPlugin.config[:open_graph][:environment_logo] rescue nil if img.blank?
20 img 20 img
21 end, 21 end,
plugins/metadata/lib/ext/profile.rb
@@ -5,8 +5,8 @@ class Profile @@ -5,8 +5,8 @@ class Profile
5 metadata_spec namespace: :og, tags: { 5 metadata_spec namespace: :og, tags: {
6 type: proc{ |p, plugin| plugin.context.params[:og_type] || MetadataPlugin.og_types[:profile] || :profile }, 6 type: proc{ |p, plugin| plugin.context.params[:og_type] || MetadataPlugin.og_types[:profile] || :profile },
7 image: proc do |p, plugin| 7 image: proc do |p, plugin|
8 - img = "#{p.environment.top_url}#{p.image.public_filename}" if p.image  
9 - img ||= MetadataPlugin.config[:open_graph][:environment_logo] rescue nil if img.blank? 8 + img = "#{p.environment.top_url}#{p.image.public_filename}".html_safe if p.image
  9 + img ||= MetadataPlugin.config[:open_graph][:environment_logo].html_safe rescue nil if img.blank?
10 img 10 img
11 end, 11 end,
12 title: proc{ |p, plugin| if p.nickname.present? then p.nickname else p.name end }, 12 title: proc{ |p, plugin| if p.nickname.present? then p.nickname else p.name end },
plugins/metadata/lib/ext/uploaded_file.rb
@@ -13,7 +13,7 @@ class UploadedFile @@ -13,7 +13,7 @@ class UploadedFile
13 plugin.og_url_for url 13 plugin.og_url_for url
14 end, 14 end,
15 title: proc{ |u, plugin| u.title }, 15 title: proc{ |u, plugin| u.title },
16 - image: proc{ |u, plugin| "#{u.environment.top_url}#{u.public_filename}" if u.image? }, 16 + image: proc{ |u, plugin| "#{u.environment.top_url}#{u.public_filename}".html_safe if u.image? },
17 description: proc{ |u, plugin| u.abstract || u.title }, 17 description: proc{ |u, plugin| u.abstract || u.title },
18 } 18 }
19 19
plugins/metadata/lib/metadata_plugin/base.rb
@@ -50,7 +50,8 @@ class MetadataPlugin::Base &lt; Noosfero::Plugin @@ -50,7 +50,8 @@ class MetadataPlugin::Base &lt; Noosfero::Plugin
50 Array(values).each do |value| 50 Array(values).each do |value|
51 value = value.call(object, plugin) if value.is_a? Proc rescue nil 51 value = value.call(object, plugin) if value.is_a? Proc rescue nil
52 next if value.blank? 52 next if value.blank?
53 - r << tag(:meta, key_attr => key, value_attr => CGI.escape_html(value.to_s)) 53 + value = h value unless value.html_safe?
  54 + r << tag(:meta, {key_attr => key, value_attr => value.to_s}, false, false)
54 end 55 end
55 end 56 end
56 end 57 end
plugins/metadata/lib/metadata_plugin/url_helper.rb
@@ -7,7 +7,8 @@ module MetadataPlugin::UrlHelper @@ -7,7 +7,8 @@ module MetadataPlugin::UrlHelper
7 def og_url_for options 7 def og_url_for options
8 options.delete :port 8 options.delete :port
9 options[:host] = self.og_domain 9 options[:host] = self.og_domain
10 - Noosfero::Application.routes.url_helpers.url_for options 10 + url = Noosfero::Application.routes.url_helpers.url_for options
  11 + url.html_safe
11 end 12 end
12 13
13 def og_profile_url profile 14 def og_profile_url profile
plugins/metadata/test/functional/content_viewer_controller_test.rb
@@ -48,6 +48,14 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -48,6 +48,14 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
48 assert_tag tag: 'meta', attributes: { property: 'og:image', content: /\/images\/x.png/ } 48 assert_tag tag: 'meta', attributes: { property: 'og:image', content: /\/images\/x.png/ }
49 end 49 end
50 50
  51 + should 'escape utf8 characters correctly' do
  52 + a = TinyMceArticle.create(name: 'Article to be shared with images', body: 'This article should be shared with all social networks <img src="/images/ç.png" />', profile: profile)
  53 +
  54 + get :view_page, profile: profile.identifier, page: [ a.name.to_slug ]
  55 + assert_tag tag: 'meta', attributes: { property: 'og:image', content: /\/images\/%C3%A7.png/ }
  56 + end
  57 +
  58 +
51 should 'render not_found page properly' do 59 should 'render not_found page properly' do
52 assert_equal false, Article.exists?(:slug => 'non-existing-page') 60 assert_equal false, Article.exists?(:slug => 'non-existing-page')
53 assert_nothing_raised do 61 assert_nothing_raised do
plugins/site_tour/controllers/public/site_tour_plugin_public_controller.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class SiteTourPluginPublicController < PublicController
  2 +
  3 + before_filter :login_required
  4 +
  5 + def mark_action
  6 + user.site_tour_plugin_actions += [params[:action_name]].flatten
  7 + user.site_tour_plugin_actions.uniq!
  8 + render :json => {:ok => user.save}
  9 + end
  10 +
  11 +end
plugins/site_tour/controllers/site_tour_plugin_admin_controller.rb 0 → 100644
@@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
  1 +require 'csv'
  2 +
  3 +class SiteTourPluginAdminController < PluginAdminController
  4 +
  5 + no_design_blocks
  6 +
  7 + def index
  8 + settings = params[:settings]
  9 + settings ||= {}
  10 +
  11 + @settings = Noosfero::Plugin::Settings.new(environment, SiteTourPlugin, settings)
  12 + @settings.actions_csv = convert_to_csv(@settings.actions)
  13 + @settings.group_triggers_csv = convert_to_csv(@settings.group_triggers)
  14 +
  15 + if request.post?
  16 + @settings.actions = convert_actions_from_csv(settings[:actions_csv])
  17 + @settings.settings.delete(:actions_csv)
  18 +
  19 + @settings.group_triggers = convert_group_triggers_from_csv(settings[:group_triggers_csv])
  20 + @settings.settings.delete(:group_triggers_csv)
  21 +
  22 + @settings.save!
  23 + session[:notice] = 'Settings succefully saved.'
  24 + redirect_to :action => 'index'
  25 + end
  26 + end
  27 +
  28 + protected
  29 +
  30 + def convert_to_csv(actions)
  31 + CSV.generate do |csv|
  32 + (actions||[]).each { |action| csv << action.values }
  33 + end
  34 + end
  35 +
  36 + def convert_actions_from_csv(actions_csv)
  37 + return [] if actions_csv.blank?
  38 + CSV.parse(actions_csv).map do |action|
  39 + {:language => action[0], :group_name => action[1], :selector => action[2], :description => action[3]}
  40 + end
  41 + end
  42 +
  43 + def convert_group_triggers_from_csv(group_triggers_csv)
  44 + return [] if group_triggers_csv.blank?
  45 + CSV.parse(group_triggers_csv).map do |group|
  46 + {:group_name => group[0], :selector => group[1], :event => group[2]}
  47 + end
  48 + end
  49 +
  50 +end
plugins/site_tour/lib/ext/person.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +class Person
  2 +
  3 + settings_items :site_tour_plugin_actions, :type => Array, :default => []
  4 +
  5 +end
plugins/site_tour/lib/site_tour_plugin.rb 0 → 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +class SiteTourPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + 'SiteTourPlugin'
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("A site tour to show users how to use the application.")
  9 + end
  10 +
  11 + def stylesheet?
  12 + true
  13 + end
  14 +
  15 + def js_files
  16 + ['intro.min.js', 'main.js']
  17 + end
  18 +
  19 + def user_data_extras
  20 + proc do
  21 + logged_in? ? {:site_tour_plugin_actions => user.site_tour_plugin_actions}:{}
  22 + end
  23 + end
  24 +
  25 + def body_ending
  26 + proc do
  27 + tour_file = "/plugins/site_tour/tour/#{language}/tour.js"
  28 + js_file = File.exists?(Rails.root.join("public#{tour_file}").to_s) ? tour_file : ""
  29 + settings = Noosfero::Plugin::Settings.new(environment, SiteTourPlugin)
  30 + actions = (settings.actions||[]).select {|action| action[:language] == language}
  31 +
  32 + render(:file => 'tour_actions', :locals => { :actions => actions, :group_triggers => settings.group_triggers, :js_file => js_file})
  33 + end
  34 + end
  35 +
  36 + def self.extra_blocks
  37 + { SiteTourPlugin::TourBlock => {} }
  38 + end
  39 +
  40 + def self.actions_csv_default_setting
  41 + 'en,tour_plugin,.site-tour-plugin_tour-block .tour-button,"Click to start tour!"'
  42 + end
  43 +
  44 +end
plugins/site_tour/lib/site_tour_plugin/site_tour_helper.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +module SiteTourPlugin::SiteTourHelper
  2 +
  3 + def parse_tour_description(description)
  4 + p = profile rescue nil
  5 + if !p.nil? && description.present?
  6 + description.gsub('{profile.identifier}', p.identifier).
  7 + gsub('{profile.name}', p.name).
  8 + gsub('{profile.url}', url_for(p.url))
  9 + else
  10 + description
  11 + end
  12 + end
  13 +
  14 +end
plugins/site_tour/lib/site_tour_plugin/tour_block.rb 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +class SiteTourPlugin::TourBlock < Block
  2 +
  3 + settings_items :actions, :type => Array, :default => [{:group_name => 'tour_plugin', :selector => '.site-tour-plugin_tour-block .tour-button', :description => _('Click to start tour!')}]
  4 + settings_items :group_triggers, :type => Array, :default => []
  5 + settings_items :display_button, :type => :boolean, :default => true
  6 +
  7 + attr_accessible :actions, :display_button, :group_triggers
  8 +
  9 + before_save do |block|
  10 + block.actions.reject! {|i| i[:group_name].blank? && i[:selector].blank? && i[:description].blank?}
  11 + block.group_triggers.reject! {|i| i[:group_name].blank? && i[:selector].blank?}
  12 + end
  13 +
  14 + def self.description
  15 + _('Site Tour Block')
  16 + end
  17 +
  18 + def help
  19 + _('Configure a step-by-step tour.')
  20 + end
  21 +
  22 + def content(args={})
  23 + block = self
  24 + proc do
  25 + render :file => 'blocks/tour', :locals => {:block => block}
  26 + end
  27 + end
  28 +
  29 +end
plugins/site_tour/po/pt/site_tour.po 0 → 100644
@@ -0,0 +1,119 @@ @@ -0,0 +1,119 @@
  1 +msgid ""
  2 +msgstr ""
  3 +"Project-Id-Version: 1.2~rc1-2843-g999a037\n"
  4 +"POT-Creation-Date: 2015-08-06 08:53-0300\n"
  5 +"PO-Revision-Date: 2015-02-03 17:27-0300\n"
  6 +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
  7 +"Language-Team: LANGUAGE <LL@li.org>\n"
  8 +"Language: \n"
  9 +"MIME-Version: 1.0\n"
  10 +"Content-Type: text/plain; charset=UTF-8\n"
  11 +"Content-Transfer-Encoding: 8bit\n"
  12 +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
  13 +
  14 +#: plugins/site_tour/lib/site_tour_plugin.rb:8
  15 +msgid "A site tour to show users how to use the application."
  16 +msgstr "Um plugin para apresentar aos usuários um tour da aplicação"
  17 +
  18 +#: plugins/site_tour/lib/site_tour_plugin/tour_block.rb:3
  19 +msgid "Click to start tour!"
  20 +msgstr "Clique para iniciar o tour!"
  21 +
  22 +#: plugins/site_tour/lib/site_tour_plugin/tour_block.rb:15
  23 +msgid "Site Tour Block"
  24 +msgstr "Bloco para Site Tour"
  25 +
  26 +#: plugins/site_tour/lib/site_tour_plugin/tour_block.rb:19
  27 +msgid "Configure a step-by-step tour."
  28 +msgstr "Configure o passo a passo do tour."
  29 +
  30 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block_item.html.erb:13
  31 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block_group_item.html.erb:15
  32 +msgid "Delete"
  33 +msgstr "Apagar"
  34 +
  35 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:4
  36 +msgid "Display help button"
  37 +msgstr "Mostrar o botão de ajuda"
  38 +
  39 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:8
  40 +msgid "Tooltip Actions"
  41 +msgstr "Ações do Tooltip"
  42 +
  43 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:9
  44 +msgid ""
  45 +"Special fields for description: {profile.name}, {profile.identifier}, "
  46 +"{profile.url}."
  47 +msgstr ""
  48 +"Campos especiais para a descrição: {profile.name}, {profile.identifier}, "
  49 +"{profile.url}"
  50 +
  51 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:11
  52 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:29
  53 +msgid "Group Name"
  54 +msgstr "Nome do Grupo"
  55 +
  56 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:12
  57 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:30
  58 +msgid "Selector"
  59 +msgstr "Seletor"
  60 +
  61 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:13
  62 +msgid "Description"
  63 +msgstr "Descrição"
  64 +
  65 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:23
  66 +msgid "New Tooltip"
  67 +msgstr "Novo Tooltip"
  68 +
  69 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:27
  70 +msgid "Group Triggers"
  71 +msgstr "Gatilhos dos Grupos"
  72 +
  73 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:31
  74 +msgid "Event"
  75 +msgstr "Evento"
  76 +
  77 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:41
  78 +msgid "New Group Trigger"
  79 +msgstr "Novo Gatilho de Grupo"
  80 +
  81 +#: plugins/site_tour/views/blocks/tour.html.erb:4
  82 +msgid "Help"
  83 +msgstr "Ajuda"
  84 +
  85 +#: plugins/site_tour/views/tour_actions.html.erb:16
  86 +msgid "Next"
  87 +msgstr "Próximo"
  88 +
  89 +#: plugins/site_tour/views/tour_actions.html.erb:17
  90 +msgid "Back"
  91 +msgstr "Anterior"
  92 +
  93 +#: plugins/site_tour/views/tour_actions.html.erb:18
  94 +msgid "Skip"
  95 +msgstr "Pular"
  96 +
  97 +#: plugins/site_tour/views/tour_actions.html.erb:19
  98 +msgid "Finish"
  99 +msgstr "Fim"
  100 +
  101 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:1
  102 +msgid "Site Tour Settings"
  103 +msgstr "Configurações do Site Tour"
  104 +
  105 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:5
  106 +msgid "Tooltips (CSV format: language, group name, selector, description)"
  107 +msgstr "Tooltips (Formato CSV: idioma, nome do grupo, seletor, descrição)"
  108 +
  109 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:6
  110 +msgid ""
  111 +"Group Triggers (CSV format: group name, selector, event (e.g. mouseenter, "
  112 +"click))"
  113 +msgstr ""
  114 +"Gatilhos dos grupos (Formato CSV: nome do grupo, seletor, evento (e.g. "
  115 +"mouseenter, click))"
  116 +
  117 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:9
  118 +msgid "Save"
  119 +msgstr "Salvar"
plugins/site_tour/po/site_tour.pot 0 → 100644
@@ -0,0 +1,121 @@ @@ -0,0 +1,121 @@
  1 +# SOME DESCRIPTIVE TITLE.
  2 +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
  3 +# This file is distributed under the same license as the PACKAGE package.
  4 +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
  5 +#
  6 +#, fuzzy
  7 +msgid ""
  8 +msgstr ""
  9 +"Project-Id-Version: 1.2~rc1-2843-g999a037\n"
  10 +"POT-Creation-Date: 2015-08-06 08:53-0300\n"
  11 +"PO-Revision-Date: 2015-02-03 17:27-0300\n"
  12 +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
  13 +"Language-Team: LANGUAGE <LL@li.org>\n"
  14 +"Language: \n"
  15 +"MIME-Version: 1.0\n"
  16 +"Content-Type: text/plain; charset=UTF-8\n"
  17 +"Content-Transfer-Encoding: 8bit\n"
  18 +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
  19 +
  20 +#: plugins/site_tour/lib/site_tour_plugin.rb:8
  21 +msgid "A site tour to show users how to use the application."
  22 +msgstr ""
  23 +
  24 +#: plugins/site_tour/lib/site_tour_plugin/tour_block.rb:3
  25 +msgid "Click to start tour!"
  26 +msgstr ""
  27 +
  28 +#: plugins/site_tour/lib/site_tour_plugin/tour_block.rb:15
  29 +msgid "Site Tour Block"
  30 +msgstr ""
  31 +
  32 +#: plugins/site_tour/lib/site_tour_plugin/tour_block.rb:19
  33 +msgid "Configure a step-by-step tour."
  34 +msgstr ""
  35 +
  36 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block_item.html.erb:13
  37 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block_group_item.html.erb:15
  38 +msgid "Delete"
  39 +msgstr ""
  40 +
  41 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:4
  42 +msgid "Display help button"
  43 +msgstr ""
  44 +
  45 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:8
  46 +msgid "Tooltip Actions"
  47 +msgstr ""
  48 +
  49 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:9
  50 +msgid ""
  51 +"Special fields for description: {profile.name}, {profile.identifier}, "
  52 +"{profile.url}."
  53 +msgstr ""
  54 +
  55 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:11
  56 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:29
  57 +msgid "Group Name"
  58 +msgstr ""
  59 +
  60 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:12
  61 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:30
  62 +msgid "Selector"
  63 +msgstr ""
  64 +
  65 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:13
  66 +msgid "Description"
  67 +msgstr ""
  68 +
  69 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:23
  70 +msgid "New Tooltip"
  71 +msgstr ""
  72 +
  73 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:27
  74 +msgid "Group Triggers"
  75 +msgstr ""
  76 +
  77 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:31
  78 +msgid "Event"
  79 +msgstr ""
  80 +
  81 +#: plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb:41
  82 +msgid "New Group Trigger"
  83 +msgstr ""
  84 +
  85 +#: plugins/site_tour/views/blocks/tour.html.erb:4
  86 +msgid "Help"
  87 +msgstr ""
  88 +
  89 +#: plugins/site_tour/views/tour_actions.html.erb:16
  90 +msgid "Next"
  91 +msgstr ""
  92 +
  93 +#: plugins/site_tour/views/tour_actions.html.erb:17
  94 +msgid "Back"
  95 +msgstr ""
  96 +
  97 +#: plugins/site_tour/views/tour_actions.html.erb:18
  98 +msgid "Skip"
  99 +msgstr ""
  100 +
  101 +#: plugins/site_tour/views/tour_actions.html.erb:19
  102 +msgid "Finish"
  103 +msgstr ""
  104 +
  105 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:1
  106 +msgid "Site Tour Settings"
  107 +msgstr ""
  108 +
  109 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:5
  110 +msgid "Tooltips (CSV format: language, group name, selector, description)"
  111 +msgstr ""
  112 +
  113 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:6
  114 +msgid ""
  115 +"Group Triggers (CSV format: group name, selector, event (e.g. mouseenter, "
  116 +"click))"
  117 +msgstr ""
  118 +
  119 +#: plugins/site_tour/views/site_tour_plugin_admin/index.html.erb:9
  120 +msgid "Save"
  121 +msgstr ""
plugins/site_tour/public/edit_tour_block.css 0 → 100644
@@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
  1 +#edit-tour-block #tooltip-actions h3 {
  2 + margin-bottom: 5px;
  3 +}
  4 +
  5 +#edit-tour-block .special-attributes {
  6 + color: rgb(157, 157, 157);
  7 +}
  8 +
  9 +#edit-tour-block .list-items {
  10 + margin-bottom: 25px;
  11 +}
  12 +
  13 +#edit-tour-block .droppable-items {
  14 + padding-left: 0;
  15 + margin-top: -12px;
  16 +}
  17 +
  18 +#edit-tour-block .droppable-items li {
  19 + list-style-type: none;
  20 +}
  21 +
  22 +#edit-tour-block .item-row {
  23 + line-height: 25px;
  24 + margin-bottom: 5px;
  25 + padding: 0;
  26 + cursor: pointer;
  27 + width: 97%;
  28 +}
  29 +
  30 +#edit-tour-block .item-row:hover {
  31 + background: #ddd url(/images/drag-and-drop.png) no-repeat;
  32 + background-position: 98% 15px;
  33 +}
  34 +
  35 +#edit-tour-block .item-row li {
  36 + list-style-type: none;
  37 + display: inline;
  38 + margin-left: 5px;
  39 +}
  40 +
  41 +#edit-tour-block {
  42 + width: 620px;
  43 + position: relative;
  44 +}
  45 +
  46 +#edit-tour-block #new-template {
  47 + display: none;
  48 +}
  49 +
  50 +#edit-tour-block .list-header {
  51 + width: 98%;
  52 + padding: 0 1px 10px 10px;
  53 + margin-bottom: 5px;
  54 + cursor: pointer;
  55 +}
  56 +
  57 +#edit-tour-block .list-header li {
  58 + list-style-type: none;
  59 + display: inline;
  60 + font-weight: bold;
  61 + font-size: 12px;
  62 + text-align: center;
  63 +}
  64 +
  65 +#edit-tour-block .list-header .list-name {
  66 + margin-left: 20px;
  67 +}
  68 +#edit-tour-block .list-header .list-selector {
  69 + margin-left: 63px;
  70 +}
  71 +#edit-tour-block .list-header .list-description, #edit-tour-block .list-header .list-event {
  72 + margin-left: 68px;
  73 +}
plugins/site_tour/public/edit_tour_block.js 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +jQuery(document).ready(function(){
  2 + jQuery('#edit-tour-block').on('click', '.add-item', function() {
  3 + var container = jQuery(this).closest('.list-items');
  4 + var new_action = container.find('#new-template>li').clone();
  5 + new_action.show();
  6 + container.find('.droppable-items').append(new_action);
  7 + });
  8 +
  9 + jQuery('#edit-tour-block').on('click', '.delete-tour-block-item', function() {
  10 + jQuery(this).parent().parent().remove();
  11 + return false;
  12 + });
  13 +
  14 + jQuery("#edit-tour-block .droppable-items").sortable({
  15 + revert: true,
  16 + axis: "y"
  17 + });
  18 +});
plugins/site_tour/public/intro.min.js 0 → 100644
@@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
  1 +(function(w,p){"object"===typeof exports?p(exports):"function"===typeof define&&define.amd?define(["exports"],p):p(w)})(this,function(w){function p(a){this._targetElement=a;this._options={nextLabel:"Next &rarr;",prevLabel:"&larr; Back",skipLabel:"Skip",doneLabel:"Done",tooltipPosition:"bottom",tooltipClass:"",highlightClass:"",exitOnEsc:!0,exitOnOverlayClick:!0,showStepNumbers:!0,keyboardNavigation:!0,showButtons:!0,showBullets:!0,showProgress:!1,scrollToElement:!0,overlayOpacity:0.8,positionPrecedence:["bottom",
  2 +"top","right","left"],disableInteraction:!1}}function J(a){var b=[],c=this;if(this._options.steps)for(var d=[],e=0,d=this._options.steps.length;e<d;e++){var f=A(this._options.steps[e]);f.step=b.length+1;"string"===typeof f.element&&(f.element=document.querySelector(f.element));if("undefined"===typeof f.element||null==f.element){var h=document.querySelector(".introjsFloatingElement");null==h&&(h=document.createElement("div"),h.className="introjsFloatingElement",document.body.appendChild(h));f.element=
  3 +h;f.position="floating"}null!=f.element&&b.push(f)}else{d=a.querySelectorAll("*[data-intro]");if(1>d.length)return!1;e=0;for(f=d.length;e<f;e++){var h=d[e],k=parseInt(h.getAttribute("data-step"),10);0<k&&(b[k-1]={element:h,intro:h.getAttribute("data-intro"),step:parseInt(h.getAttribute("data-step"),10),tooltipClass:h.getAttribute("data-tooltipClass"),highlightClass:h.getAttribute("data-highlightClass"),position:h.getAttribute("data-position")||this._options.tooltipPosition})}e=k=0;for(f=d.length;e<
  4 +f;e++)if(h=d[e],null==h.getAttribute("data-step")){for(;"undefined"!=typeof b[k];)k++;b[k]={element:h,intro:h.getAttribute("data-intro"),step:k+1,tooltipClass:h.getAttribute("data-tooltipClass"),highlightClass:h.getAttribute("data-highlightClass"),position:h.getAttribute("data-position")||this._options.tooltipPosition}}}e=[];for(d=0;d<b.length;d++)b[d]&&e.push(b[d]);b=e;b.sort(function(a,b){return a.step-b.step});c._introItems=b;K.call(c,a)&&(x.call(c),a.querySelector(".introjs-skipbutton"),a.querySelector(".introjs-nextbutton"),
  5 +c._onKeyDown=function(b){if(27===b.keyCode&&!0==c._options.exitOnEsc)y.call(c,a),void 0!=c._introExitCallback&&c._introExitCallback.call(c);else if(37===b.keyCode)C.call(c);else if(39===b.keyCode)x.call(c);else if(13===b.keyCode){var d=b.target||b.srcElement;d&&0<d.className.indexOf("introjs-prevbutton")?C.call(c):d&&0<d.className.indexOf("introjs-skipbutton")?y.call(c,a):x.call(c);b.preventDefault?b.preventDefault():b.returnValue=!1}},c._onResize=function(a){t.call(c,document.querySelector(".introjs-helperLayer"));
  6 +t.call(c,document.querySelector(".introjs-tooltipReferenceLayer"))},window.addEventListener?(this._options.keyboardNavigation&&window.addEventListener("keydown",c._onKeyDown,!0),window.addEventListener("resize",c._onResize,!0)):document.attachEvent&&(this._options.keyboardNavigation&&document.attachEvent("onkeydown",c._onKeyDown),document.attachEvent("onresize",c._onResize)));return!1}function A(a){if(null==a||"object"!=typeof a||"undefined"!=typeof a.nodeType)return a;var b={},c;for(c in a)b[c]=
  7 +A(a[c]);return b}function x(){this._direction="forward";"undefined"===typeof this._currentStep?this._currentStep=0:++this._currentStep;if(this._introItems.length<=this._currentStep)"function"===typeof this._introCompleteCallback&&this._introCompleteCallback.call(this),y.call(this,this._targetElement);else{var a=this._introItems[this._currentStep];"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this,a.element);G.call(this,a)}}function C(){this._direction=
  8 +"backward";if(0===this._currentStep)return!1;var a=this._introItems[--this._currentStep];"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this,a.element);G.call(this,a)}function y(a){var b=a.querySelector(".introjs-overlay");if(null!=b){b.style.opacity=0;setTimeout(function(){b.parentNode&&b.parentNode.removeChild(b)},500);var c=a.querySelector(".introjs-helperLayer");c&&c.parentNode.removeChild(c);(c=a.querySelector(".introjs-tooltipReferenceLayer"))&&c.parentNode.removeChild(c);
  9 +(a=a.querySelector(".introjs-disableInteraction"))&&a.parentNode.removeChild(a);(a=document.querySelector(".introjsFloatingElement"))&&a.parentNode.removeChild(a);if(a=document.querySelector(".introjs-showElement"))a.className=a.className.replace(/introjs-[a-zA-Z]+/g,"").replace(/^\s+|\s+$/g,"");if((a=document.querySelectorAll(".introjs-fixParent"))&&0<a.length)for(c=a.length-1;0<=c;c--)a[c].className=a[c].className.replace(/introjs-fixParent/g,"").replace(/^\s+|\s+$/g,"");window.removeEventListener?
  10 +window.removeEventListener("keydown",this._onKeyDown,!0):document.detachEvent&&document.detachEvent("onkeydown",this._onKeyDown);this._currentStep=void 0}}function H(a,b,c,d){var e="";b.style.top=null;b.style.right=null;b.style.bottom=null;b.style.left=null;b.style.marginLeft=null;b.style.marginTop=null;c.style.display="inherit";"undefined"!=typeof d&&null!=d&&(d.style.top=null,d.style.left=null);if(this._introItems[this._currentStep]){e=this._introItems[this._currentStep];e="string"===typeof e.tooltipClass?
  11 +e.tooltipClass:this._options.tooltipClass;b.className=("introjs-tooltip "+e).replace(/^\s+|\s+$/g,"");currentTooltipPosition=this._introItems[this._currentStep].position;if(("auto"==currentTooltipPosition||"auto"==this._options.tooltipPosition)&&"floating"!=currentTooltipPosition){var e=currentTooltipPosition,f=this._options.positionPrecedence.slice(),h=F(),p=k(b).height+10,s=k(b).width+20,l=k(a),m="floating";l.left+s>h.width||0>l.left+l.width/2-s?(q(f,"bottom"),q(f,"top")):(l.height+l.top+p>h.height&&
  12 +q(f,"bottom"),0>l.top-p&&q(f,"top"));l.width+l.left+s>h.width&&q(f,"right");0>l.left-s&&q(f,"left");0<f.length&&(m=f[0]);e&&"auto"!=e&&-1<f.indexOf(e)&&(m=e);currentTooltipPosition=m}e=k(a);f=k(b).height;h=F();switch(currentTooltipPosition){case "top":b.style.left="15px";b.style.top="-"+(f+10)+"px";c.className="introjs-arrow bottom";break;case "right":b.style.left=k(a).width+20+"px";e.top+f>h.height&&(c.className="introjs-arrow left-bottom",b.style.top="-"+(f-e.height-20)+"px");c.className="introjs-arrow left";
  13 +break;case "left":!0==this._options.showStepNumbers&&(b.style.top="15px");e.top+f>h.height?(b.style.top="-"+(f-e.height-20)+"px",c.className="introjs-arrow right-bottom"):c.className="introjs-arrow right";b.style.right=e.width+20+"px";break;case "floating":c.style.display="none";a=k(b);b.style.left="50%";b.style.top="50%";b.style.marginLeft="-"+a.width/2+"px";b.style.marginTop="-"+a.height/2+"px";"undefined"!=typeof d&&null!=d&&(d.style.left="-"+(a.width/2+18)+"px",d.style.top="-"+(a.height/2+18)+
  14 +"px");break;case "bottom-right-aligned":c.className="introjs-arrow top-right";b.style.right="0px";b.style.bottom="-"+(k(b).height+10)+"px";break;case "bottom-middle-aligned":d=k(a);a=k(b);c.className="introjs-arrow top-middle";b.style.left=d.width/2-a.width/2+"px";b.style.bottom="-"+(a.height+10)+"px";break;default:b.style.bottom="-"+(k(b).height+10)+"px",b.style.left=k(a).width/2-k(b).width/2+"px",c.className="introjs-arrow top"}}}function q(a,b){-1<a.indexOf(b)&&a.splice(a.indexOf(b),1)}function t(a){if(a&&
  15 +this._introItems[this._currentStep]){var b=this._introItems[this._currentStep],c=k(b.element),d=10;"floating"==b.position&&(d=0);a.setAttribute("style","width: "+(c.width+d)+"px; height:"+(c.height+d)+"px; top:"+(c.top-5)+"px;left: "+(c.left-5)+"px;")}}function L(){var a=document.querySelector(".introjs-disableInteraction");null===a&&(a=document.createElement("div"),a.className="introjs-disableInteraction",this._targetElement.appendChild(a));t.call(this,a)}function G(a){"undefined"!==typeof this._introChangeCallback&&
  16 +this._introChangeCallback.call(this,a.element);var b=this,c=document.querySelector(".introjs-helperLayer"),d=document.querySelector(".introjs-tooltipReferenceLayer"),e="introjs-helperLayer";k(a.element);"string"===typeof a.highlightClass&&(e+=" "+a.highlightClass);"string"===typeof this._options.highlightClass&&(e+=" "+this._options.highlightClass);if(null!=c){var f=d.querySelector(".introjs-helperNumberLayer"),h=d.querySelector(".introjs-tooltiptext"),p=d.querySelector(".introjs-arrow"),s=d.querySelector(".introjs-tooltip"),
  17 +l=d.querySelector(".introjs-skipbutton"),m=d.querySelector(".introjs-prevbutton"),r=d.querySelector(".introjs-nextbutton");c.className=e;s.style.opacity=0;s.style.display="none";if(null!=f){var g=this._introItems[0<=a.step-2?a.step-2:0];if(null!=g&&"forward"==this._direction&&"floating"==g.position||"backward"==this._direction&&"floating"==a.position)f.style.opacity=0}t.call(b,c);t.call(b,d);if((g=document.querySelectorAll(".introjs-fixParent"))&&0<g.length)for(e=g.length-1;0<=e;e--)g[e].className=
  18 +g[e].className.replace(/introjs-fixParent/g,"").replace(/^\s+|\s+$/g,"");g=document.querySelector(".introjs-showElement");g.className=g.className.replace(/introjs-[a-zA-Z]+/g,"").replace(/^\s+|\s+$/g,"");b._lastShowElementTimer&&clearTimeout(b._lastShowElementTimer);b._lastShowElementTimer=setTimeout(function(){null!=f&&(f.innerHTML=a.step);h.innerHTML=a.intro;s.style.display="block";H.call(b,a.element,s,p,f);d.querySelector(".introjs-bullets li > a.active").className="";d.querySelector('.introjs-bullets li > a[data-stepnumber="'+
  19 +a.step+'"]').className="active";d.querySelector(".introjs-progress .introjs-progressbar").setAttribute("style","width:"+I.call(b)+"%;");s.style.opacity=1;f&&(f.style.opacity=1);-1===r.tabIndex?l.focus():r.focus()},350)}else{var q=document.createElement("div"),m=document.createElement("div"),c=document.createElement("div"),n=document.createElement("div"),w=document.createElement("div"),D=document.createElement("div"),E=document.createElement("div"),u=document.createElement("div");q.className=e;m.className=
  20 +"introjs-tooltipReferenceLayer";t.call(b,q);t.call(b,m);this._targetElement.appendChild(q);this._targetElement.appendChild(m);c.className="introjs-arrow";w.className="introjs-tooltiptext";w.innerHTML=a.intro;D.className="introjs-bullets";!1===this._options.showBullets&&(D.style.display="none");for(var q=document.createElement("ul"),e=0,B=this._introItems.length;e<B;e++){var A=document.createElement("li"),z=document.createElement("a");z.onclick=function(){b.goToStep(this.getAttribute("data-stepnumber"))};
  21 +e===a.step-1&&(z.className="active");z.href="javascript:void(0);";z.innerHTML="&nbsp;";z.setAttribute("data-stepnumber",this._introItems[e].step);A.appendChild(z);q.appendChild(A)}D.appendChild(q);E.className="introjs-progress";!1===this._options.showProgress&&(E.style.display="none");e=document.createElement("div");e.className="introjs-progressbar";e.setAttribute("style","width:"+I.call(this)+"%;");E.appendChild(e);u.className="introjs-tooltipbuttons";!1===this._options.showButtons&&(u.style.display=
  22 +"none");n.className="introjs-tooltip";n.appendChild(w);n.appendChild(D);n.appendChild(E);!0==this._options.showStepNumbers&&(g=document.createElement("span"),g.className="introjs-helperNumberLayer",g.innerHTML=a.step,m.appendChild(g));n.appendChild(c);m.appendChild(n);r=document.createElement("a");r.onclick=function(){b._introItems.length-1!=b._currentStep&&x.call(b)};r.href="javascript:void(0);";r.innerHTML=this._options.nextLabel;m=document.createElement("a");m.onclick=function(){0!=b._currentStep&&
  23 +C.call(b)};m.href="javascript:void(0);";m.innerHTML=this._options.prevLabel;l=document.createElement("a");l.className="introjs-button introjs-skipbutton";l.href="javascript:void(0);";l.innerHTML=this._options.skipLabel;l.onclick=function(){b._introItems.length-1==b._currentStep&&"function"===typeof b._introCompleteCallback&&b._introCompleteCallback.call(b);b._introItems.length-1!=b._currentStep&&"function"===typeof b._introExitCallback&&b._introExitCallback.call(b);y.call(b,b._targetElement)};u.appendChild(l);
  24 +1<this._introItems.length&&(u.appendChild(m),u.appendChild(r));n.appendChild(u);H.call(b,a.element,n,c,g)}!0===this._options.disableInteraction&&L.call(b);m.removeAttribute("tabIndex");r.removeAttribute("tabIndex");0==this._currentStep&&1<this._introItems.length?(m.className="introjs-button introjs-prevbutton introjs-disabled",m.tabIndex="-1",r.className="introjs-button introjs-nextbutton",l.innerHTML=this._options.skipLabel):this._introItems.length-1==this._currentStep||1==this._introItems.length?
  25 +(l.innerHTML=this._options.doneLabel,m.className="introjs-button introjs-prevbutton",r.className="introjs-button introjs-nextbutton introjs-disabled",r.tabIndex="-1"):(m.className="introjs-button introjs-prevbutton",r.className="introjs-button introjs-nextbutton",l.innerHTML=this._options.skipLabel);r.focus();a.element.className+=" introjs-showElement";g=v(a.element,"position");"absolute"!==g&&"relative"!==g&&(a.element.className+=" introjs-relativePosition");for(g=a.element.parentNode;null!=g&&"body"!==
  26 +g.tagName.toLowerCase();){c=v(g,"z-index");n=parseFloat(v(g,"opacity"));u=v(g,"transform")||v(g,"-webkit-transform")||v(g,"-moz-transform")||v(g,"-ms-transform")||v(g,"-o-transform");if(/[0-9]+/.test(c)||1>n||"none"!==u)g.className+=" introjs-fixParent";g=g.parentNode}M(a.element)||!0!==this._options.scrollToElement||(n=a.element.getBoundingClientRect(),g=F().height,c=n.bottom-(n.bottom-n.top),n=n.bottom-g,0>c||a.element.clientHeight>g?window.scrollBy(0,c-30):window.scrollBy(0,n+100));"undefined"!==
  27 +typeof this._introAfterChangeCallback&&this._introAfterChangeCallback.call(this,a.element)}function v(a,b){var c="";a.currentStyle?c=a.currentStyle[b]:document.defaultView&&document.defaultView.getComputedStyle&&(c=document.defaultView.getComputedStyle(a,null).getPropertyValue(b));return c&&c.toLowerCase?c.toLowerCase():c}function F(){if(void 0!=window.innerWidth)return{width:window.innerWidth,height:window.innerHeight};var a=document.documentElement;return{width:a.clientWidth,height:a.clientHeight}}
  28 +function M(a){a=a.getBoundingClientRect();return 0<=a.top&&0<=a.left&&a.bottom+80<=window.innerHeight&&a.right<=window.innerWidth}function K(a){var b=document.createElement("div"),c="",d=this;b.className="introjs-overlay";if("body"===a.tagName.toLowerCase())c+="top: 0;bottom: 0; left: 0;right: 0;position: fixed;",b.setAttribute("style",c);else{var e=k(a);e&&(c+="width: "+e.width+"px; height:"+e.height+"px; top:"+e.top+"px;left: "+e.left+"px;",b.setAttribute("style",c))}a.appendChild(b);b.onclick=
  29 +function(){!0==d._options.exitOnOverlayClick&&(y.call(d,a),void 0!=d._introExitCallback&&d._introExitCallback.call(d))};setTimeout(function(){c+="opacity: "+d._options.overlayOpacity.toString()+";";b.setAttribute("style",c)},10);return!0}function k(a){var b={};b.width=a.offsetWidth;b.height=a.offsetHeight;for(var c=0,d=0;a&&!isNaN(a.offsetLeft)&&!isNaN(a.offsetTop);)c+=a.offsetLeft,d+=a.offsetTop,a=a.offsetParent;b.top=d;b.left=c;return b}function I(){return 100*(parseInt(this._currentStep+1,10)/
  30 +this._introItems.length)}var B=function(a){if("object"===typeof a)return new p(a);if("string"===typeof a){if(a=document.querySelector(a))return new p(a);throw Error("There is no element with given selector.");}return new p(document.body)};B.version="1.0.0";B.fn=p.prototype={clone:function(){return new p(this)},setOption:function(a,b){this._options[a]=b;return this},setOptions:function(a){var b=this._options,c={},d;for(d in b)c[d]=b[d];for(d in a)c[d]=a[d];this._options=c;return this},start:function(){J.call(this,
  31 +this._targetElement);return this},goToStep:function(a){this._currentStep=a-2;"undefined"!==typeof this._introItems&&x.call(this);return this},nextStep:function(){x.call(this);return this},previousStep:function(){C.call(this);return this},exit:function(){y.call(this,this._targetElement);return this},refresh:function(){t.call(this,document.querySelector(".introjs-helperLayer"));t.call(this,document.querySelector(".introjs-tooltipReferenceLayer"));return this},onbeforechange:function(a){if("function"===
  32 +typeof a)this._introBeforeChangeCallback=a;else throw Error("Provided callback for onbeforechange was not a function");return this},onchange:function(a){if("function"===typeof a)this._introChangeCallback=a;else throw Error("Provided callback for onchange was not a function.");return this},onafterchange:function(a){if("function"===typeof a)this._introAfterChangeCallback=a;else throw Error("Provided callback for onafterchange was not a function");return this},oncomplete:function(a){if("function"===
  33 +typeof a)this._introCompleteCallback=a;else throw Error("Provided callback for oncomplete was not a function.");return this},onexit:function(a){if("function"===typeof a)this._introExitCallback=a;else throw Error("Provided callback for onexit was not a function.");return this}};return w.introJs=B});
plugins/site_tour/public/introjs.min.css 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +.introjs-overlay{position:absolute;z-index:999999;background-color:#000;opacity:0;background:-moz-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9)));background:-webkit-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-o-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-ms-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#66000000',endColorstr='#e6000000',GradientType=1);-ms-filter:"alpha(opacity=50)";filter:alpha(opacity=50);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-fixParent{z-index:auto!important;opacity:1.0!important;position:absolute!important;-webkit-transform:none!important;-moz-transform:none!important;-ms-transform:none!important;-o-transform:none!important;transform:none!important}.introjs-showElement,tr.introjs-showElement>td,tr.introjs-showElement>th{z-index:9999999!important}.introjs-disableInteraction{z-index:99999999!important;position:absolute}.introjs-relativePosition,tr.introjs-showElement>td,tr.introjs-showElement>th{position:relative}.introjs-helperLayer{position:absolute;z-index:9999998;background-color:#FFF;background-color:rgba(255,255,255,.9);border:1px solid #777;border:1px solid rgba(0,0,0,.5);border-radius:4px;box-shadow:0 2px 15px rgba(0,0,0,.4);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-tooltipReferenceLayer{position:absolute;z-index:10000000;background-color:transparent;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-helperLayer *,.introjs-helperLayer *:before,.introjs-helperLayer *:after{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;-o-box-sizing:content-box;box-sizing:content-box}.introjs-helperNumberLayer{position:absolute;top:-16px;left:-16px;z-index:9999999999!important;padding:2px;font-family:Arial,verdana,tahoma;font-size:13px;font-weight:bold;color:white;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.3);background:#ff3019;background:-webkit-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ff3019),color-stop(100%,#cf0404));background:-moz-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-ms-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-o-linear-gradient(top,#ff3019 0,#cf0404 100%);background:linear-gradient(to bottom,#ff3019 0,#cf0404 100%);width:20px;height:20px;line-height:20px;border:3px solid white;border-radius:50%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3019',endColorstr='#cf0404',GradientType=0);filter:progid:DXImageTransform.Microsoft.Shadow(direction=135,strength=2,color=ff0000);box-shadow:0 2px 5px rgba(0,0,0,.4)}.introjs-arrow{border:5px solid white;content:'';position:absolute}.introjs-arrow.top{top:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-right{top:-10px;right:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-middle{top:-10px;left:50%;margin-left:-5px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.right{right:-10px;top:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.right-bottom{bottom:10px;right:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.bottom{bottom:-10px;border-top-color:white;border-right-color:transparent;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left{left:-10px;top:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left-bottom{left:-10px;bottom:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-tooltip{position:absolute;padding:10px;background-color:white;min-width:200px;max-width:300px;border-radius:3px;box-shadow:0 1px 10px rgba(0,0,0,.4);-webkit-transition:opacity .1s ease-out;-moz-transition:opacity .1s ease-out;-ms-transition:opacity .1s ease-out;-o-transition:opacity .1s ease-out;transition:opacity .1s ease-out}.introjs-tooltipbuttons{text-align:right;white-space:nowrap}.introjs-button{position:relative;overflow:visible;display:inline-block;padding:.3em .8em;border:1px solid #d4d4d4;margin:0;text-decoration:none;text-shadow:1px 1px 0 #fff;font:11px/normal sans-serif;color:#333;white-space:nowrap;cursor:pointer;outline:0;background-color:#ececec;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f4f4f4),to(#ececec));background-image:-moz-linear-gradient(#f4f4f4,#ececec);background-image:-o-linear-gradient(#f4f4f4,#ececec);background-image:linear-gradient(#f4f4f4,#ececec);-webkit-background-clip:padding;-moz-background-clip:padding;-o-background-clip:padding-box;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em;zoom:1;*display:inline;margin-top:10px}.introjs-button:hover{border-color:#bcbcbc;text-decoration:none;box-shadow:0 1px 1px #e3e3e3}.introjs-button:focus,.introjs-button:active{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ececec),to(#f4f4f4));background-image:-moz-linear-gradient(#ececec,#f4f4f4);background-image:-o-linear-gradient(#ececec,#f4f4f4);background-image:linear-gradient(#ececec,#f4f4f4)}.introjs-button::-moz-focus-inner{padding:0;border:0}.introjs-skipbutton{margin-right:5px;color:#7a7a7a}.introjs-prevbutton{-webkit-border-radius:.2em 0 0 .2em;-moz-border-radius:.2em 0 0 .2em;border-radius:.2em 0 0 .2em;border-right:0}.introjs-nextbutton{-webkit-border-radius:0 .2em .2em 0;-moz-border-radius:0 .2em .2em 0;border-radius:0 .2em .2em 0}.introjs-disabled,.introjs-disabled:hover,.introjs-disabled:focus{color:#9a9a9a;border-color:#d4d4d4;box-shadow:none;cursor:default;background-color:#f4f4f4;background-image:none;text-decoration:none}.introjs-bullets{text-align:center}.introjs-bullets ul{clear:both;margin:15px auto 0;padding:0;display:inline-block}.introjs-bullets ul li{list-style:none;float:left;margin:0 2px}.introjs-bullets ul li a{display:block;width:6px;height:6px;background:#ccc;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;text-decoration:none}.introjs-bullets ul li a:hover{background:#999}.introjs-bullets ul li a.active{background:#999}.introjs-progress{overflow:hidden;height:10px;margin:10px 0 5px 0;border-radius:4px;background-color:#ecf0f1}.introjs-progressbar{float:left;width:0;height:100%;font-size:10px;line-height:10px;text-align:center;background-color:#08c}.introjsFloatingElement{position:absolute;height:0;width:0;left:50%;top:50%}
0 \ No newline at end of file 2 \ No newline at end of file
plugins/site_tour/public/main.js 0 → 100644
@@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
  1 +var siteTourPlugin = (function() {
  2 +
  3 + var actions = [];
  4 + var groupTriggers = [];
  5 + var userData = {};
  6 + var intro;
  7 + var options = {};
  8 +
  9 + function hasMark(name) {
  10 + return jQuery.cookie("_noosfero_.sitetour." + name) ||
  11 + jQuery.inArray(name, userData.site_tour_plugin_actions)>=0;
  12 + }
  13 +
  14 + function mark(name) {
  15 + jQuery.cookie("_noosfero_.sitetour." + name, 1, {expires: 365});
  16 + if(userData.login) {
  17 + jQuery.post('/plugin/site_tour/public/mark_action', {action_name: name}, function(data) { });
  18 + }
  19 + }
  20 +
  21 + function clearAll() {
  22 + jQuery('.site-tour-plugin').removeAttr('data-intro data-intro-name data-step');
  23 + }
  24 +
  25 + function configureIntro(force, actions) {
  26 + clearAll();
  27 + for(var i=0; i<actions.length; i++) {
  28 + var action = actions[i];
  29 +
  30 + if(force || !hasMark(action.name)) {
  31 + var el = jQuery(action.selector).filter(function() {
  32 + return jQuery(this).is(":visible") && jQuery(this).css('visibility') != 'hidden';
  33 + });
  34 + el.addClass('site-tour-plugin');
  35 + el.attr('data-intro', action.text);
  36 + el.attr('data-intro-name', action.name);
  37 + if(action.step) {
  38 + el.attr('data-step', action.step);
  39 + }
  40 + }
  41 + }
  42 + }
  43 +
  44 + function actionsOnload() {
  45 + var groups = jQuery.map(groupTriggers, function(g) { return g.name; });
  46 + return jQuery.grep(actions, function(n, i) { return jQuery.inArray(n.name, groups); });
  47 + }
  48 +
  49 + function actionsByGroup(group) {
  50 + return jQuery.grep(actions, function(n, i) { return n.name===group });
  51 + }
  52 +
  53 + function forceParam() {
  54 + return jQuery.deparam.querystring()['siteTourPlugin']==='force';
  55 + }
  56 +
  57 + return {
  58 + setOption: function(key, value) {
  59 + options[key] = value;
  60 + },
  61 + add: function (name, selector, text, step) {
  62 + actions.push({name: name, selector: selector, text: text, step: step});
  63 + },
  64 + addGroupTrigger: function(name, selector, ev) {
  65 + groupTriggers.push({name: name, selector: selector, event: ev});
  66 + plugin = this;
  67 + var handler = function() {
  68 + configureIntro(forceParam(), actionsByGroup(name));
  69 + intro.start();
  70 + jQuery(document).off(ev, selector, handler);
  71 + };
  72 + jQuery(document).on(ev, selector, handler);
  73 + },
  74 + start: function(data, force) {
  75 + force = typeof force !== 'undefined' ? force : false || forceParam();
  76 + userData = data;
  77 +
  78 + intro = introJs();
  79 + intro.setOption('tooltipPosition', 'auto');
  80 + intro.setOption('showStepNumbers', 'false');
  81 + intro.setOptions(options);
  82 + intro.onafterchange(function(targetElement) {
  83 + var name = jQuery(targetElement).attr('data-intro-name');
  84 + mark(name);
  85 + });
  86 + configureIntro(force, actionsOnload());
  87 + intro.start();
  88 + },
  89 + force: function() {
  90 + this.start({}, true);
  91 + }
  92 + }
  93 +})();
  94 +
  95 +jQuery( document ).ready(function( $ ) {
  96 + $(window).bind('userDataLoaded', function(event, data) {
  97 + siteTourPlugin.start(data);
  98 + });
  99 +});
plugins/site_tour/public/style.css 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +introjs.min.css
0 \ No newline at end of file 2 \ No newline at end of file
plugins/site_tour/public/tour/en/tour.js.dist 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +jQuery( document ).ready(function( $ ) {
  2 + siteTourPlugin.add('login_button','.action-home-index #link_login', "Click to login!");
  3 + siteTourPlugin.add('login_button','.action-home-index .signup', "Click to signup!");
  4 + siteTourPlugin.add('logout_button','.action-home-index #logout', "Click to logout");
  5 + siteTourPlugin.add('navigation_bar','#navigation', "Click to navigate");
  6 +});
plugins/site_tour/test/functional/site_tour_plugin_admin_controller_test.rb 0 → 100644
@@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class SiteTourPluginAdminControllerTest < ActionController::TestCase
  4 +
  5 + def setup
  6 + @environment = Environment.default
  7 + login_as(create_admin_user(@environment))
  8 + end
  9 +
  10 + attr_reader :environment
  11 +
  12 + should 'parse csv and save actions array in plugin settings' do
  13 + actions_csv = "en,tour_plugin,.tour-button,Click"
  14 + post :index, :settings => {"actions_csv" => actions_csv}
  15 + @settings = Noosfero::Plugin::Settings.new(environment.reload, SiteTourPlugin)
  16 + assert_equal [{:language => 'en', :group_name => 'tour_plugin', :selector => '.tour-button', :description => 'Click'}], @settings.actions
  17 + end
  18 +
  19 + should 'parse csv and save group triggers array in plugin settings' do
  20 + group_triggers_csv = "tour_plugin,.tour-button,mouseenter"
  21 + post :index, :settings => {"group_triggers_csv" => group_triggers_csv}
  22 + @settings = Noosfero::Plugin::Settings.new(environment.reload, SiteTourPlugin)
  23 + assert_equal [{:group_name => 'tour_plugin', :selector => '.tour-button', :event => 'mouseenter'}], @settings.group_triggers
  24 + end
  25 +
  26 + should 'do not store actions_csv' do
  27 + actions_csv = "en,tour_plugin,.tour-button,Click"
  28 + post :index, :settings => {"actions_csv" => actions_csv}
  29 + @settings = Noosfero::Plugin::Settings.new(environment.reload, SiteTourPlugin)
  30 + assert_equal nil, @settings.settings[:actions_csv]
  31 + end
  32 +
  33 + should 'do not store group_triggers_csv' do
  34 + group_triggers_csv = "tour_plugin,.tour-button,click"
  35 + post :index, :settings => {"group_triggers_csv" => group_triggers_csv}
  36 + @settings = Noosfero::Plugin::Settings.new(environment.reload, SiteTourPlugin)
  37 + assert_equal nil, @settings.settings[:group_triggers_csv]
  38 + end
  39 +
  40 + should 'convert actions array to csv to enable user edition' do
  41 + @settings = Noosfero::Plugin::Settings.new(environment.reload, SiteTourPlugin)
  42 + @settings.actions = [{:language => 'en', :group_name => 'tour_plugin', :selector => '.tour-button', :description => 'Click'}]
  43 + @settings.save!
  44 +
  45 + get :index
  46 + assert_tag :tag => 'textarea', :attributes => {:class => 'actions-csv'}, :content => "\nen,tour_plugin,.tour-button,Click\n"
  47 + end
  48 +
  49 + should 'convert group_triggers array to csv to enable user edition' do
  50 + @settings = Noosfero::Plugin::Settings.new(environment.reload, SiteTourPlugin)
  51 + @settings.group_triggers = [{:group_name => 'tour_plugin', :selector => '.tour-button', :event => 'click'}]
  52 + @settings.save!
  53 +
  54 + get :index
  55 + assert_tag :tag => 'textarea', :attributes => {:class => 'groups-csv'}, :content => "\ntour_plugin,.tour-button,click\n"
  56 + end
  57 +
  58 +end
plugins/site_tour/test/functional/site_tour_plugin_public_controller_test.rb 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class SiteTourPluginPublicControllerTest < ActionController::TestCase
  4 +
  5 + def setup
  6 + @person = create_user('testuser').person
  7 + end
  8 +
  9 + attr_accessor :person
  10 +
  11 + should 'not be able to mark an action if is not logged in' do
  12 + xhr :post, :mark_action, :action_name => 'test'
  13 + assert_response 401
  14 + end
  15 +
  16 + should 'be able to mark one action' do
  17 + login_as(person.identifier)
  18 + xhr :post, :mark_action, :action_name => 'test'
  19 + assert_equal({'ok' => true}, ActiveSupport::JSON.decode(response.body))
  20 + assert_equal ['test'], person.reload.site_tour_plugin_actions
  21 + end
  22 +
  23 + should 'be able to mark multiple actions' do
  24 + login_as(person.identifier)
  25 + xhr :post, :mark_action, :action_name => ['test1', 'test2']
  26 + assert_equal({'ok' => true}, ActiveSupport::JSON.decode(response.body))
  27 + assert_equal ['test1', 'test2'], person.reload.site_tour_plugin_actions
  28 + end
  29 +
  30 +end
plugins/site_tour/test/test_helper.rb 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
plugins/site_tour/test/unit/site_tour_helper_test.rb 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class SiteTourHelperTest < ActionView::TestCase
  4 +
  5 + include SiteTourPlugin::SiteTourHelper
  6 +
  7 + should 'parse tooltip description' do
  8 + assert_equal 'test', parse_tour_description("test")
  9 + end
  10 +
  11 + should 'replace profile attributes in tooltip description' do
  12 + profile = fast_create(Profile)
  13 + expects(:profile).returns(profile).at_least_once
  14 + assert_equal "name #{profile.name}, identifier #{profile.identifier}, url #{url_for profile.url}", parse_tour_description("name {profile.name}, identifier {profile.identifier}, url {profile.url}")
  15 + end
  16 +
  17 +end
plugins/site_tour/test/unit/site_tour_plugin_test.rb 0 → 100644
@@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class SiteTourPluginTest < ActionView::TestCase
  4 +
  5 + def setup
  6 + @plugin = SiteTourPlugin.new
  7 + end
  8 +
  9 + attr_accessor :plugin
  10 +
  11 + should 'include site tour plugin actions in user data for logged in users' do
  12 + expects(:logged_in?).returns(true)
  13 + person = create_user('testuser').person
  14 + person.site_tour_plugin_actions = ['login', 'navigation']
  15 + expects(:user).returns(person)
  16 +
  17 + assert_equal({:site_tour_plugin_actions => ['login', 'navigation']}, instance_eval(&plugin.user_data_extras))
  18 + end
  19 +
  20 + should 'return empty hash when user is not logged in' do
  21 + expects(:logged_in?).returns(false)
  22 + assert_equal({}, instance_eval(&plugin.user_data_extras))
  23 + end
  24 +
  25 + should 'include javascript related to tour instructions if file exists' do
  26 + file = '/plugins/site_tour/tour/pt/tour.js'
  27 + expects(:language).returns('pt')
  28 + File.expects(:exists?).with(Rails.root.join("public#{file}").to_s).returns(true)
  29 + expects(:environment).returns(Environment.default)
  30 + assert_tag_in_string instance_exec(&plugin.body_ending), :tag => 'script'
  31 + end
  32 +
  33 + should 'not include javascript file that not exists' do
  34 + file = '/plugins/site_tour/tour/pt/tour.js'
  35 + expects(:language).returns('pt')
  36 + File.expects(:exists?).with(Rails.root.join("public#{file}").to_s).returns(false)
  37 + expects(:environment).returns(Environment.default)
  38 + assert_no_tag_in_string instance_exec(&plugin.body_ending), :tag => "script"
  39 + end
  40 +
  41 + should 'render javascript tag with tooltip actions and group triggers' do
  42 + expects(:language).returns('en').at_least_once
  43 +
  44 + settings = Noosfero::Plugin::Settings.new(Environment.default, SiteTourPlugin)
  45 + settings.actions = [{:language => 'en', :group_name => 'test', :selector => 'body', :description => 'Test'}]
  46 + settings.group_triggers = [{:group_name => 'test', :selector => 'body', :event => 'click'}]
  47 + settings.save!
  48 +
  49 + expects(:environment).returns(Environment.default)
  50 + body_ending = instance_exec(&plugin.body_ending)
  51 + assert_match /siteTourPlugin\.add\('test', 'body', 'Test', 1\);/, body_ending
  52 + assert_match /siteTourPlugin\.addGroupTrigger\('test', 'body', 'click'\);/, body_ending
  53 + end
  54 +
  55 + should 'start each tooltip group with the correct step order' do
  56 + expects(:language).returns('en').at_least_once
  57 +
  58 + settings = Noosfero::Plugin::Settings.new(Environment.default, SiteTourPlugin)
  59 + settings.actions = [
  60 + {:language => 'en', :group_name => 'test_a', :selector => 'body', :description => 'Test A1'},
  61 + {:language => 'en', :group_name => 'test_a', :selector => 'body', :description => 'Test A2'},
  62 + {:language => 'en', :group_name => 'test_b', :selector => 'body', :description => 'Test B1'},
  63 + ]
  64 + settings.save!
  65 +
  66 + expects(:environment).returns(Environment.default)
  67 + body_ending = instance_exec(&plugin.body_ending)
  68 + assert_match /siteTourPlugin\.add\('test_a', 'body', 'Test A1', 1\);/, body_ending
  69 + assert_match /siteTourPlugin\.add\('test_a', 'body', 'Test A2', 2\);/, body_ending
  70 + assert_match /siteTourPlugin\.add\('test_b', 'body', 'Test B1', 3\);/, body_ending
  71 + end
  72 +
  73 +end
plugins/site_tour/test/unit/tour_block_test.rb 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class TrackListBlockTest < ActionView::TestCase
  4 +
  5 + ActionView::Base.send :include, ApplicationHelper
  6 +
  7 + def setup
  8 + @block = fast_create(SiteTourPlugin::TourBlock)
  9 + end
  10 +
  11 + attr_accessor :block
  12 +
  13 + should 'do not save empty actions' do
  14 + block.actions = [{:group_name => '', :selector => nil, :description => ' '}]
  15 + block.save!
  16 + assert_equal [], block.actions
  17 + end
  18 +
  19 + should 'render script tag in visualization mode' do
  20 + controller.expects(:boxes_editor?).returns(false)
  21 + assert_tag_in_string instance_eval(&block.content), :tag => 'script'
  22 + end
  23 +
  24 + should 'do not render script tag when editing' do
  25 + controller.expects(:boxes_editor?).returns(true)
  26 + controller.expects(:uses_design_blocks?).returns(true)
  27 + assert_no_tag_in_string instance_eval(&block.content), :tag => 'script'
  28 + end
  29 +
  30 + should 'display help button' do
  31 + controller.expects(:boxes_editor?).returns(false)
  32 + assert_tag_in_string instance_eval(&block.content), :tag => 'a', :attributes => {:class => 'button icon-help with-text tour-button'}
  33 + end
  34 +
  35 + should 'do not display help button when display_button is false' do
  36 + block.display_button = false
  37 + controller.expects(:boxes_editor?).returns(false)
  38 + assert_no_tag_in_string instance_eval(&block.content), :tag => 'a', :attributes => {:class => 'button icon-help with-text tour-button'}
  39 + end
  40 +
  41 +end
plugins/site_tour/views/blocks/tour.html.erb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<%= block_title(block.title) %>
  2 +
  3 +<% if block.display_button %>
  4 + <%= button :help, _('Help'), '#', :class => 'tour-button', :onclick => 'siteTourPlugin.force();' %>
  5 +<% end %>
  6 +
  7 +<% edit_mode = controller.send(:boxes_editor?) && controller.send(:uses_design_blocks?) %>
  8 +
  9 +<% unless edit_mode %>
  10 + <%= render :file => 'tour_actions', :locals => {:actions => block.actions, :group_triggers => block.group_triggers} %>
  11 +<% end %>
plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block.html.erb 0 → 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +<%= javascript_include_tag '/plugins/site_tour/edit_tour_block.js' %>
  2 +<%= stylesheet_link_tag '/plugins/site_tour/edit_tour_block.css' %>
  3 +
  4 +<%= labelled_form_field check_box(:block, :display_button) + _('Display help button'), '' %>
  5 +
  6 +<div id='edit-tour-block'>
  7 + <div id="tooltip-actions" class="list-items">
  8 + <h3><%= _('Tooltip Actions') %></h3>
  9 + <div class="special-attributes"><%= _('Special fields for description: {profile.name}, {profile.identifier}, {profile.url}.') %></div>
  10 + <ul class='list-header'>
  11 + <li class='list-name'><%= _('Group Name') %></li>
  12 + <li class='list-selector'><%= _('Selector') %></li>
  13 + <li class='list-description'><%= _('Description') %></li>
  14 + </ul>
  15 + <ul id="droppable-tour-actions" class="droppable-items">
  16 + <% for action in @block.actions do %>
  17 + <%= render :partial => 'box_organizer/site_tour_plugin/tour_block_item', :locals => {:action => action} %>
  18 + <% end %>
  19 + </ul>
  20 + <div id="new-template">
  21 + <%= render :partial => 'box_organizer/site_tour_plugin/tour_block_item', :locals => {:action => {} } %>
  22 + </div>
  23 + <%= link_to_function(_('New Tooltip'), :class => 'add-item button icon-add with-text') %>
  24 + </div>
  25 +
  26 + <div id="group-triggers" class="list-items">
  27 + <h3><%= _('Group Triggers') %></h3>
  28 + <ul class='list-header'>
  29 + <li class='list-name'><%= _('Group Name') %></li>
  30 + <li class='list-selector'><%= _('Selector') %></li>
  31 + <li class='list-event'><%= _('Event') %></li>
  32 + </ul>
  33 + <ul id="droppable-tour-group-triggers" class="droppable-items">
  34 + <% for group in @block.group_triggers do %>
  35 + <%= render :partial => 'box_organizer/site_tour_plugin/tour_block_group_item', :locals => {:group => group} %>
  36 + <% end %>
  37 + </ul>
  38 + <div id="new-template">
  39 + <%= render :partial => 'box_organizer/site_tour_plugin/tour_block_group_item', :locals => {:group => {} } %>
  40 + </div>
  41 + <%= link_to_function(_('New Group Trigger'), :class => 'add-item button icon-add with-text') %>
  42 + </div>
  43 +
  44 +</div>
plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block_group_item.html.erb 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +<li>
  2 + <ul class="item-row">
  3 + <li>
  4 + <%= text_field_tag 'block[group_triggers][][group_name]', group[:group_name], :class => 'group-name', :maxlength => 20 %>
  5 + </li>
  6 + <li>
  7 + <%= text_field_tag 'block[group_triggers][][selector]', group[:selector], :class => 'selector' %>
  8 + </li>
  9 + <li>
  10 + <%= select_tag 'block[group_triggers][][event]',
  11 + options_for_select(['mouseenter', 'mouseleave', 'mouseover', 'mouseout', 'click', 'change', 'select', 'keydown', 'keyup', 'keypress', 'focus', 'blur', 'submit', 'drag', 'drop'], group[:event]),
  12 + :class => 'description' %>
  13 + </li>
  14 + <li>
  15 + <%= button_without_text(:delete, _('Delete'), "#" , :class=>"delete-tour-block-item") %>
  16 + </li>
  17 + </ul>
  18 +</li>
  19 +
plugins/site_tour/views/box_organizer/site_tour_plugin/_tour_block_item.html.erb 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +<li>
  2 + <ul class="item-row">
  3 + <li>
  4 + <%= text_field_tag 'block[actions][][group_name]', action[:group_name], :class => 'group-name', :maxlength => 20 %>
  5 + </li>
  6 + <li>
  7 + <%= text_field_tag 'block[actions][][selector]', action[:selector], :class => 'selector' %>
  8 + </li>
  9 + <li>
  10 + <%= text_field_tag 'block[actions][][description]', action[:description], :class => 'description' %>
  11 + </li>
  12 + <li>
  13 + <%= button_without_text(:delete, _('Delete'), "#" , :class=>"delete-tour-block-item") %>
  14 + </li>
  15 + </ul>
  16 +</li>
plugins/site_tour/views/environment_design/site_tour_plugin 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +../box_organizer/site_tour_plugin
0 \ No newline at end of file 2 \ No newline at end of file
plugins/site_tour/views/profile_design/site_tour_plugin 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +../box_organizer/site_tour_plugin
0 \ No newline at end of file 2 \ No newline at end of file
plugins/site_tour/views/site_tour_plugin_admin/index.html.erb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<h1><%= _('Site Tour Settings')%></h1>
  2 +
  3 +<%= form_for(:settings) do |f| %>
  4 +
  5 + <%= labelled_form_field _('Tooltips (CSV format: language, group name, selector, description)'), f.text_area(:actions_csv, :style => 'width: 100%', :class => 'actions-csv') %>
  6 + <%= labelled_form_field _('Group Triggers (CSV format: group name, selector, event (e.g. mouseenter, click))'), f.text_area(:group_triggers_csv, :style => 'width: 100%', :class => 'groups-csv', :rows => 7) %>
  7 +
  8 + <% button_bar do %>
  9 + <%= submit_button(:save, _('Save'), :cancel => {:controller => 'plugins', :action => 'index'}) %>
  10 + <% end %>
  11 +
  12 +<% end %>
  13 +
plugins/site_tour/views/tour_actions.html.erb 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +<% extend SiteTourPlugin::SiteTourHelper %>
  2 +<% js_file = defined?(:js_file) ? js_file : nil %>
  3 +<%= javascript_include_tag(js_file) if js_file.present? %>
  4 +
  5 +<% if actions.present? %>
  6 +<script>
  7 + jQuery( document ).ready(function( $ ) {
  8 + <% actions.each_with_index do |action, index| %>
  9 + <%= "siteTourPlugin.add('#{j action[:group_name]}', '#{j action[:selector]}', '#{j parse_tour_description(action[:description])}', #{index + 1});" %>
  10 + <% end %>
  11 +
  12 + <% (group_triggers||[]).each do |group| %>
  13 + <%= "siteTourPlugin.addGroupTrigger('#{j group[:group_name]}', '#{j group[:selector]}', '#{j group[:event]}');" %>
  14 + <% end %>
  15 +
  16 + siteTourPlugin.setOption('nextLabel', '<%= _('Next') %>');
  17 + siteTourPlugin.setOption('prevLabel', '<%= _('Back') %>');
  18 + siteTourPlugin.setOption('skipLabel', '<%= _('Skip') %>');
  19 + siteTourPlugin.setOption('doneLabel', '<%= _('Finish') %>');
  20 + });
  21 +</script>
  22 +<% end %>
po/de/noosfero-doc.po
@@ -7,8 +7,8 @@ msgid &quot;&quot; @@ -7,8 +7,8 @@ msgid &quot;&quot;
7 msgstr "" 7 msgstr ""
8 "Project-Id-Version: PACKAGE VERSION\n" 8 "Project-Id-Version: PACKAGE VERSION\n"
9 "POT-Creation-Date: 2013-12-10 15:48-0300\n" 9 "POT-Creation-Date: 2013-12-10 15:48-0300\n"
10 -"PO-Revision-Date: 2015-02-23 11:32+0200\n"  
11 -"Last-Translator: Michal Čihař <michal@cihar.com>\n" 10 +"PO-Revision-Date: 2015-08-14 09:48+0200\n"
  11 +"Last-Translator: Phillip Rohmberger <rohmberger@hotmail.de>\n"
12 "Language-Team: German " 12 "Language-Team: German "
13 "<https://hosted.weblate.org/projects/noosfero/documentation/de/>\n" 13 "<https://hosted.weblate.org/projects/noosfero/documentation/de/>\n"
14 "Language: de\n" 14 "Language: de\n"
@@ -16,7 +16,7 @@ msgstr &quot;&quot; @@ -16,7 +16,7 @@ msgstr &quot;&quot;
16 "Content-Type: text/plain; charset=UTF-8\n" 16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n" 17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=2; plural=n != 1;\n" 18 "Plural-Forms: nplurals=2; plural=n != 1;\n"
19 -"X-Generator: Weblate 2.3-dev\n" 19 +"X-Generator: Weblate 2.4-dev\n"
20 20
21 # type: Content of: <h1> 21 # type: Content of: <h1>
22 #. type: Content of: <h1> 22 #. type: Content of: <h1>
@@ -28,7 +28,7 @@ msgstr &quot;&quot; @@ -28,7 +28,7 @@ msgstr &quot;&quot;
28 #. type: Content of: <p> 28 #. type: Content of: <p>
29 #: doc/noosfero/plugins/send_email.en.xhtml:2 29 #: doc/noosfero/plugins/send_email.en.xhtml:2
30 msgid "Allows to send e-mails through an e-mail form." 30 msgid "Allows to send e-mails through an e-mail form."
31 -msgstr "" 31 +msgstr "Ermöglicht das Senden von E-mails über ein E-mail-Formular."
32 32
33 # type: Content of: <h2> 33 # type: Content of: <h2>
34 #. type: Content of: <h2> 34 #. type: Content of: <h2>
@@ -36,7 +36,7 @@ msgstr &quot;&quot; @@ -36,7 +36,7 @@ msgstr &quot;&quot;
36 #: doc/noosfero/plugins/google_cse.en.xhtml:3 36 #: doc/noosfero/plugins/google_cse.en.xhtml:3
37 #: doc/noosfero/plugins/google_analytics.en.xhtml:3 37 #: doc/noosfero/plugins/google_analytics.en.xhtml:3
38 msgid "Usage" 38 msgid "Usage"
39 -msgstr "" 39 +msgstr "Verwendung"
40 40
41 # type: Content of: <ul><li> 41 # type: Content of: <ul><li>
42 #. type: Content of: <ul><li> 42 #. type: Content of: <ul><li>
@@ -52,6 +52,7 @@ msgstr &quot;&quot; @@ -52,6 +52,7 @@ msgstr &quot;&quot;
52 msgid "" 52 msgid ""
53 "Add a &#8220;to&#8221; and &#8220;message&#8221; field and a submit button" 53 "Add a &#8220;to&#8221; and &#8220;message&#8221; field and a submit button"
54 msgstr "" 54 msgstr ""
  55 +"Fügt ein ``to``- und ein ``message``-Feld, mit einem ``submit`` Knopf hinzu"
55 56
56 # type: Content of: <ul><li> 57 # type: Content of: <ul><li>
57 #. type: Content of: <ul><li> 58 #. type: Content of: <ul><li>
public/designs/templates/lefttopright/javascripts/template.js
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -$(document).ready(function() {  
2 - var box_4_height = $(".box-4").height();  
3 -  
4 - // Make box-2(the most left one) stay align with box-4  
5 - $(".box-2").css("margin-top", "-"+box_4_height+"px");  
6 -});  
public/designs/templates/lefttopright/stylesheets/style.css
1 #boxes { 1 #boxes {
2 - display: table;  
3 width: 100%; 2 width: 100%;
  3 + height: 100%;
4 } 4 }
5 5
6 -.box-1 {  
7 - width: 58%;  
8 - float: left;  
9 - margin: 1% 1% 0% 1%; 6 +.box-4 {
  7 + position: relative;
  8 + float: right;
  9 + width: 78.5%;
  10 + max-height: 400px;
  11 + overflow: hidden;
  12 + margin-left: 1%;
10 } 13 }
11 14
12 -  
13 -.box-2 { 15 +.box-3 {
  16 + width: 20.5%;
  17 + height: 100%;
  18 + min-height: 410px;
14 position: relative; 19 position: relative;
15 float: left; 20 float: left;
16 - width: 20%;  
17 } 21 }
18 22
19 -.box-3 { 23 +.box-2 {
20 position: relative; 24 position: relative;
21 float: right; 25 float: right;
22 - width: 20%; 26 + width: 20.5%;
23 margin-top: 1%; 27 margin-top: 1%;
24 } 28 }
25 29
26 -.box-4 {  
27 - float: left;  
28 - width: 79%;  
29 - margin-left: 21%;  
30 -}  
31 -  
32 -#profile-activity ul,  
33 -#profile-network ul,  
34 -#profile-wall ul {  
35 - width: 460px;  
36 -}  
37 -#profile-activity ul.comment-replies,  
38 -#profile-network ul.comment-replies,  
39 -#profile-wall ul.comment-replies {  
40 - width: auto;  
41 -}  
42 - 30 +.box-1 {
  31 + position: relative;
  32 + float: right;
  33 + width: 57%;
  34 + margin: 1% 1% 0% 1%;
  35 +}
43 \ No newline at end of file 36 \ No newline at end of file
public/designs/themes/base/style.scss
@@ -1505,7 +1505,8 @@ table#recaptcha_table tr:hover td { @@ -1505,7 +1505,8 @@ table#recaptcha_table tr:hover td {
1505 1505
1506 .event-date { 1506 .event-date {
1507 background: url('/images/calendar_date_select/calendar-icon.png') no-repeat left center; 1507 background: url('/images/calendar_date_select/calendar-icon.png') no-repeat left center;
1508 - padding: 5px; 1508 + padding: 2px;
  1509 + padding-left: 15px;
1509 } 1510 }
1510 1511
1511 .event-link { 1512 .event-link {
test/functional/events_controller_test.rb
@@ -8,12 +8,12 @@ class EventsControllerTest &lt; ActionController::TestCase @@ -8,12 +8,12 @@ class EventsControllerTest &lt; ActionController::TestCase
8 attr_reader :profile 8 attr_reader :profile
9 9
10 should 'list today events by default' do 10 should 'list today events by default' do
11 - profile.events << Event.new(:name => 'Joao Birthday', :start_date => Date.today)  
12 - profile.events << Event.new(:name => 'Maria Birthday', :start_date => Date.today) 11 + profile.events << Event.new(:name => 'Joao Birthday', :start_date => DateTime.now)
  12 + profile.events << Event.new(:name => 'Maria Birthday', :start_date => DateTime.now)
13 13
14 get :events, :profile => profile.identifier 14 get :events, :profile => profile.identifier
15 15
16 - today = Date.today.strftime("%B %d, %Y") 16 + today = DateTime.now.strftime("%B %d, %Y")
17 assert_tag :tag => 'div', :attributes => {:id => "agenda-items"}, 17 assert_tag :tag => 'div', :attributes => {:id => "agenda-items"},
18 :descendant => {:tag => 'h3', :content => "Events for #{today}"}, 18 :descendant => {:tag => 'h3', :content => "Events for #{today}"},
19 :descendant => {:tag => 'tr', :content => "Joao Birthday"}, 19 :descendant => {:tag => 'tr', :content => "Joao Birthday"},
@@ -23,15 +23,15 @@ class EventsControllerTest &lt; ActionController::TestCase @@ -23,15 +23,15 @@ class EventsControllerTest &lt; ActionController::TestCase
23 should 'display calendar of current month' do 23 should 'display calendar of current month' do
24 get :events, :profile => profile.identifier 24 get :events, :profile => profile.identifier
25 25
26 - month = Date.today.strftime("%B %Y") 26 + month = DateTime.now.strftime("%B %Y")
27 assert_tag :tag => 'table', :attributes => {:class => /current-month/}, :descendant => {:tag => 'caption', :content => /#{month}/} 27 assert_tag :tag => 'table', :attributes => {:class => /current-month/}, :descendant => {:tag => 'caption', :content => /#{month}/}
28 end 28 end
29 29
30 should 'display links to previous and next month' do 30 should 'display links to previous and next month' do
31 get :events, :profile => profile.identifier 31 get :events, :profile => profile.identifier
32 32
33 - prev_month = Date.today - 1.month  
34 - next_month = Date.today + 1.month 33 + prev_month = DateTime.now - 1.month
  34 + next_month = DateTime.now + 1.month
35 prev_month_name = prev_month.strftime("%B") 35 prev_month_name = prev_month.strftime("%B")
36 next_month_name = next_month.strftime("%B") 36 next_month_name = next_month.strftime("%B")
37 assert_tag :tag =>'a', :attributes => {:href => "/profile/#{profile.identifier}/events/#{prev_month.year}/#{prev_month.month}"}, :content => prev_month_name 37 assert_tag :tag =>'a', :attributes => {:href => "/profile/#{profile.identifier}/events/#{prev_month.year}/#{prev_month.month}"}, :content => prev_month_name
@@ -40,14 +40,14 @@ class EventsControllerTest &lt; ActionController::TestCase @@ -40,14 +40,14 @@ class EventsControllerTest &lt; ActionController::TestCase
40 40
41 should 'see the events paginated' do 41 should 'see the events paginated' do
42 30.times do |i| 42 30.times do |i|
43 - profile.events << Event.new(:name => "Lesson #{i}", :start_date => Date.today) 43 + profile.events << Event.new(:name => "Lesson #{i}", :start_date => DateTime.now)
44 end 44 end
45 get :events, :profile => profile.identifier 45 get :events, :profile => profile.identifier
46 assert_equal 20, assigns(:events).size 46 assert_equal 20, assigns(:events).size
47 end 47 end
48 48
49 should 'show events of specific day' do 49 should 'show events of specific day' do
50 - profile.events << Event.new(:name => 'Joao Birthday', :start_date => Date.new(2009, 10, 28)) 50 + profile.events << Event.new(:name => 'Joao Birthday', :start_date => DateTime.new(2009, 10, 28))
51 51
52 get :events_by_day, :profile => profile.identifier, :year => 2009, :month => 10, :day => 28 52 get :events_by_day, :profile => profile.identifier, :year => 2009, :month => 10, :day => 28
53 53
test/functional/search_controller_test.rb
@@ -305,7 +305,7 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -305,7 +305,7 @@ class SearchControllerTest &lt; ActionController::TestCase
305 305
306 should 'search for events' do 306 should 'search for events' do
307 person = create_user('teste').person 307 person = create_user('teste').person
308 - event = create_event(person, :name => 'an event to be found', :start_date => Date.today) 308 + event = create_event(person, :name => 'an event to be found', :start_date => DateTime.now)
309 309
310 get :events, :query => 'event to be found' 310 get :events, :query => 'event to be found'
311 311
@@ -314,10 +314,10 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -314,10 +314,10 @@ class SearchControllerTest &lt; ActionController::TestCase
314 314
315 should 'return events of the day' do 315 should 'return events of the day' do
316 person = create_user('someone').person 316 person = create_user('someone').person
317 - ten_days_ago = Date.today - 10.day 317 + ten_days_ago = DateTime.now - 10.day
318 318
319 ev1 = create_event(person, :name => 'event 1', :category_ids => [@category.id], :start_date => ten_days_ago) 319 ev1 = create_event(person, :name => 'event 1', :category_ids => [@category.id], :start_date => ten_days_ago)
320 - ev2 = create_event(person, :name => 'event 2', :category_ids => [@category.id], :start_date => Date.today - 2.month) 320 + ev2 = create_event(person, :name => 'event 2', :category_ids => [@category.id], :start_date => DateTime.now - 2.month)
321 321
322 get :events, :day => ten_days_ago.day, :month => ten_days_ago.month, :year => ten_days_ago.year 322 get :events, :day => ten_days_ago.day, :month => ten_days_ago.month, :year => ten_days_ago.year
323 assert_equal [ev1], assigns(:events) 323 assert_equal [ev1], assigns(:events)
@@ -325,9 +325,11 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -325,9 +325,11 @@ class SearchControllerTest &lt; ActionController::TestCase
325 325
326 should 'return events of the day with category' do 326 should 'return events of the day with category' do
327 person = create_user('someone').person 327 person = create_user('someone').person
328 - ten_days_ago = Date.today - 10.day 328 + ten_days_ago = DateTime.now - 10.day
329 329
330 - ev1 = create_event(person, :name => 'event 1', :category_ids => [@category.id], :start_date => ten_days_ago) 330 + ev1 = create_event(person, :name => 'event 1', :start_date => ten_days_ago)
  331 + ev1.categories = [@category]
  332 +
331 ev2 = create_event(person, :name => 'event 2', :start_date => ten_days_ago) 333 ev2 = create_event(person, :name => 'event 2', :start_date => ten_days_ago)
332 334
333 get :events, :day => ten_days_ago.day, :month => ten_days_ago.month, :year => ten_days_ago.year, :category_path => @category.path.split('/') 335 get :events, :day => ten_days_ago.day, :month => ten_days_ago.month, :year => ten_days_ago.year, :category_path => @category.path.split('/')
@@ -337,8 +339,8 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -337,8 +339,8 @@ class SearchControllerTest &lt; ActionController::TestCase
337 339
338 should 'return events of today when no date specified' do 340 should 'return events of today when no date specified' do
339 person = create_user('someone').person 341 person = create_user('someone').person
340 - ev1 = create_event(person, :name => 'event 1', :category_ids => [@category.id], :start_date => Date.today)  
341 - ev2 = create_event(person, :name => 'event 2', :category_ids => [@category.id], :start_date => Date.today - 2.month) 342 + ev1 = create_event(person, :name => 'event 1', :category_ids => [@category.id], :start_date => DateTime.now)
  343 + ev2 = create_event(person, :name => 'event 2', :category_ids => [@category.id], :start_date => DateTime.now - 2.month)
342 344
343 get :events 345 get :events
344 346
@@ -349,9 +351,9 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -349,9 +351,9 @@ class SearchControllerTest &lt; ActionController::TestCase
349 person = create_user('someone').person 351 person = create_user('someone').person
350 352
351 ev1 = create_event(person, :name => 'event 1', :category_ids => [@category.id], 353 ev1 = create_event(person, :name => 'event 1', :category_ids => [@category.id],
352 - :start_date => Date.today + 2.month) 354 + :start_date => DateTime.now + 2.month)
353 ev2 = create_event(person, :name => 'event 2', :category_ids => [@category.id], 355 ev2 = create_event(person, :name => 'event 2', :category_ids => [@category.id],
354 - :start_date => Date.today + 2.day) 356 + :start_date => DateTime.now + 2.day)
355 357
356 get :events 358 get :events
357 359
@@ -362,8 +364,8 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -362,8 +364,8 @@ class SearchControllerTest &lt; ActionController::TestCase
362 should 'list events for a given month' do 364 should 'list events for a given month' do
363 person = create_user('testuser').person 365 person = create_user('testuser').person
364 366
365 - create_event(person, :name => 'upcoming event 1', :category_ids => [@category.id], :start_date => Date.new(2008, 1, 25))  
366 - create_event(person, :name => 'upcoming event 2', :category_ids => [@category.id], :start_date => Date.new(2008, 4, 27)) 367 + create_event(person, :name => 'upcoming event 1', :category_ids => [@category.id], :start_date => DateTime.new(2008, 1, 25))
  368 + create_event(person, :name => 'upcoming event 2', :category_ids => [@category.id], :start_date => DateTime.new(2008, 4, 27))
367 369
368 get :events, :year => '2008', :month => '1' 370 get :events, :year => '2008', :month => '1'
369 371
@@ -373,7 +375,7 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -373,7 +375,7 @@ class SearchControllerTest &lt; ActionController::TestCase
373 should 'see the events paginated' do 375 should 'see the events paginated' do
374 person = create_user('testuser').person 376 person = create_user('testuser').person
375 30.times do |i| 377 30.times do |i|
376 - create_event(person, :name => "Event #{i}", :start_date => Date.today) 378 + create_event(person, :name => "Event #{i}", :start_date => DateTime.now)
377 end 379 end
378 get :events 380 get :events
379 assert_equal 20, assigns(:events).size 381 assert_equal 20, assigns(:events).size
@@ -416,7 +418,7 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -416,7 +418,7 @@ class SearchControllerTest &lt; ActionController::TestCase
416 end 418 end
417 419
418 should 'display current year/month by default as caption of current month' do 420 should 'display current year/month by default as caption of current month' do
419 - Date.expects(:today).returns(Date.new(2008, 8, 1)).at_least_once 421 + DateTime.expects(:now).returns(DateTime.new(2008, 8, 1)).at_least_once
420 422
421 get :events 423 get :events
422 assert_tag :tag => 'table', :attributes => {:class => /current-month/}, :descendant => {:tag => 'caption', :content => /August 2008/} 424 assert_tag :tag => 'table', :attributes => {:class => /current-month/}, :descendant => {:tag => 'caption', :content => /August 2008/}
@@ -475,7 +477,7 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -475,7 +477,7 @@ class SearchControllerTest &lt; ActionController::TestCase
475 477
476 should 'show events of specific day' do 478 should 'show events of specific day' do
477 person = create_user('anotheruser').person 479 person = create_user('anotheruser').person
478 - event = create_event(person, :name => 'Joao Birthday', :start_date => Date.new(2009, 10, 28)) 480 + event = create_event(person, :name => 'Joao Birthday', :start_date => DateTime.new(2009, 10, 28))
479 481
480 get :events_by_day, :year => 2009, :month => 10, :day => 28 482 get :events_by_day, :year => 2009, :month => 10, :day => 28
481 483
@@ -484,8 +486,8 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -484,8 +486,8 @@ class SearchControllerTest &lt; ActionController::TestCase
484 486
485 should 'ignore filter of events if category not exists' do 487 should 'ignore filter of events if category not exists' do
486 person = create_user('anotheruser').person 488 person = create_user('anotheruser').person
487 - create_event(person, :name => 'Joao Birthday', :start_date => Date.new(2009, 10, 28), :category_ids => [@category.id])  
488 - create_event(person, :name => 'Maria Birthday', :start_date => Date.new(2009, 10, 28)) 489 + create_event(person, :name => 'Joao Birthday', :start_date => DateTime.new(2009, 10, 28), :category_ids => [@category.id])
  490 + create_event(person, :name => 'Maria Birthday', :start_date => DateTime.new(2009, 10, 28))
489 491
490 id_of_unexistent_category = Category.last.id + 10 492 id_of_unexistent_category = Category.last.id + 10
491 493
@@ -772,7 +774,7 @@ class SearchControllerTest &lt; ActionController::TestCase @@ -772,7 +774,7 @@ class SearchControllerTest &lt; ActionController::TestCase
772 protected 774 protected
773 775
774 def create_event(profile, options) 776 def create_event(profile, options)
775 - ev = build(Event, { :name => 'some event', :start_date => Date.new(2008,1,1) }.merge(options)) 777 + ev = build(Event, { :name => 'some event', :start_date => DateTime.new(2008,1,1) }.merge(options))
776 ev.profile = profile 778 ev.profile = profile
777 ev.save! 779 ev.save!
778 ev 780 ev
test/unit/article_test.rb
@@ -1497,6 +1497,17 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1497,6 +1497,17 @@ class ArticleTest &lt; ActiveSupport::TestCase
1497 assert_includes a.body_images_paths, 'http://test.com/noosfero.png' 1497 assert_includes a.body_images_paths, 'http://test.com/noosfero.png'
1498 end 1498 end
1499 1499
  1500 + should 'escape utf8 characters correctly' do
  1501 + Environment.any_instance.stubs(:default_hostname).returns('noosfero.org')
  1502 + a = build TinyMceArticle, profile: @profile
  1503 + a.body = 'Noosfero <img src="http://noosfero.com/cabeça.png" /> '
  1504 + assert_includes a.body_images_paths, 'http://noosfero.com/cabe%C3%A7a.png'
  1505 +
  1506 + # check if after save (that is, after xss_terminate run)
  1507 + a.save!
  1508 + assert_includes a.body_images_paths, 'http://noosfero.com/cabe%C3%A7a.png'
  1509 + end
  1510 +
1500 should 'get absolute images paths in article body' do 1511 should 'get absolute images paths in article body' do
1501 Environment.any_instance.stubs(:default_hostname).returns('noosfero.org') 1512 Environment.any_instance.stubs(:default_hostname).returns('noosfero.org')
1502 a = build TinyMceArticle, :profile => @profile 1513 a = build TinyMceArticle, :profile => @profile
@@ -2180,4 +2191,27 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -2180,4 +2191,27 @@ class ArticleTest &lt; ActiveSupport::TestCase
2180 article.destroy 2191 article.destroy
2181 end 2192 end
2182 2193
  2194 + should 'have can_display_media_panel with default false' do
  2195 + a = Article.new
  2196 + assert !a.can_display_media_panel?
  2197 + end
  2198 +
  2199 + should 'display media panel when allowed by the environment' do
  2200 + a = Article.new
  2201 + a.expects(:can_display_media_panel?).returns(true)
  2202 + environment = mock
  2203 + a.expects(:environment).returns(environment)
  2204 + environment.expects(:enabled?).with('media_panel').returns(true)
  2205 + assert a.display_media_panel?
  2206 + end
  2207 +
  2208 + should 'not display media panel when not allowed by the environment' do
  2209 + a = Article.new
  2210 + a.expects(:can_display_media_panel?).returns(true)
  2211 + environment = mock
  2212 + a.expects(:environment).returns(environment)
  2213 + environment.expects(:enabled?).with('media_panel').returns(false)
  2214 + assert !a.display_media_panel?
  2215 + end
  2216 +
2183 end 2217 end
test/unit/content_viewer_helper_test.rb
@@ -16,14 +16,14 @@ class ContentViewerHelperTest &lt; ActionView::TestCase @@ -16,14 +16,14 @@ class ContentViewerHelperTest &lt; ActionView::TestCase
16 blog = fast_create(Blog, :name => 'Blog test', :profile_id => profile.id) 16 blog = fast_create(Blog, :name => 'Blog test', :profile_id => profile.id)
17 post = create(TextileArticle, :name => 'post test', :profile => profile, :parent => blog) 17 post = create(TextileArticle, :name => 'post test', :profile => profile, :parent => blog)
18 result = article_title(post) 18 result = article_title(post)
19 - assert_tag_in_string result, :tag => 'span', :content => show_date(post.published_at) 19 + assert_tag_in_string result, :tag => 'span', :content => show_time(post.published_at)
20 end 20 end
21 21
22 should 'display published-at for forum posts' do 22 should 'display published-at for forum posts' do
23 forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id) 23 forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id)
24 post = TextileArticle.create!(:name => 'post test', :profile => profile, :parent => forum) 24 post = TextileArticle.create!(:name => 'post test', :profile => profile, :parent => forum)
25 result = article_title(post) 25 result = article_title(post)
26 - assert_tag_in_string result, :tag => 'span', :content => show_date(post.published_at) 26 + assert_tag_in_string result, :tag => 'span', :content => show_time(post.published_at)
27 end 27 end
28 28
29 should 'not display published-at for non-blog and non-forum posts' do 29 should 'not display published-at for non-blog and non-forum posts' do
test/unit/dates_helper_test.rb
@@ -21,23 +21,23 @@ class DatesHelperTest &lt; ActiveSupport::TestCase @@ -21,23 +21,23 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
21 should 'generate period with two dates' do 21 should 'generate period with two dates' do
22 date1 = mock 22 date1 = mock
23 date1.stubs(:year).returns('A') 23 date1.stubs(:year).returns('A')
24 - expects(:show_date).with(date1, anything).returns('XXX') 24 + expects(:show_time).with(date1, anything).returns('XXX')
25 date2 = mock 25 date2 = mock
26 date2.stubs(:year).returns('B') 26 date2.stubs(:year).returns('B')
27 - expects(:show_date).with(date2, anything).returns('YYY') 27 + expects(:show_time).with(date2, anything).returns('YYY')
28 expects(:_).with('from %{date1} to %{date2}').returns('from %{date1} to %{date2}') 28 expects(:_).with('from %{date1} to %{date2}').returns('from %{date1} to %{date2}')
29 assert_equal 'from XXX to YYY', show_period(date1, date2) 29 assert_equal 'from XXX to YYY', show_period(date1, date2)
30 end 30 end
31 31
32 should 'generate period with in two diferent years' do 32 should 'generate period with in two diferent years' do
33 - date1 = Date.new(1920, 1, 2)  
34 - date2 = Date.new(1992, 4, 6)  
35 - assert_equal 'from January 2, 1920 to April 6, 1992', show_period(date1, date2) 33 + date1 = DateTime.new(1920, 1, 2)
  34 + date2 = DateTime.new(1992, 4, 6)
  35 + assert_equal 'from January 2, 1920 0:00 to April 6, 1992 0:00', show_period(date1, date2)
36 end 36 end
37 37
38 should 'generate period with in two diferent months of the same year' do 38 should 'generate period with in two diferent months of the same year' do
39 - date1 = Date.new(2013, 2, 1)  
40 - date2 = Date.new(2013, 3, 1) 39 + date1 = DateTime.new(2013, 2, 1)
  40 + date2 = DateTime.new(2013, 3, 1)
41 assert_equal 'from February 1 to March 1, 2013', show_period(date1, date2) 41 assert_equal 'from February 1 to March 1, 2013', show_period(date1, date2)
42 end 42 end
43 43
@@ -49,13 +49,13 @@ class DatesHelperTest &lt; ActiveSupport::TestCase @@ -49,13 +49,13 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
49 49
50 should 'generate period with two equal dates' do 50 should 'generate period with two equal dates' do
51 date1 = mock 51 date1 = mock
52 - expects(:show_date).with(date1, anything).returns('XXX') 52 + expects(:show_time).with(date1, anything).returns('XXX')
53 assert_equal 'XXX', show_period(date1, date1) 53 assert_equal 'XXX', show_period(date1, date1)
54 end 54 end
55 55
56 should 'generate period with one date only' do 56 should 'generate period with one date only' do
57 date1 = mock 57 date1 = mock
58 - expects(:show_date).with(date1, anything).returns('XXX') 58 + expects(:show_time).with(date1, anything).returns('XXX')
59 assert_equal 'XXX', show_period(date1) 59 assert_equal 'XXX', show_period(date1)
60 end 60 end
61 61
@@ -84,7 +84,7 @@ class DatesHelperTest &lt; ActiveSupport::TestCase @@ -84,7 +84,7 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
84 end 84 end
85 85
86 should 'fallback to current year/month in show_month' do 86 should 'fallback to current year/month in show_month' do
87 - Date.expects(:today).returns(Date.new(2008,11,1)).at_least_once 87 + DateTime.expects(:now).returns(DateTime.new(2008,11,1)).at_least_once
88 assert_equal 'November 2008', show_month(nil, nil) 88 assert_equal 'November 2008', show_month(nil, nil)
89 assert_equal 'November 2008', show_month('', '') 89 assert_equal 'November 2008', show_month('', '')
90 end 90 end
@@ -118,16 +118,16 @@ class DatesHelperTest &lt; ActiveSupport::TestCase @@ -118,16 +118,16 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
118 end 118 end
119 119
120 should 'format time' do 120 should 'format time' do
121 - assert_equal '22 November 2008, 15:34', show_time(Time.mktime(2008, 11, 22, 15, 34, 0, 0)) 121 + assert_equal 'November 22, 2008 15:34', show_time(Time.mktime(2008, 11, 22, 15, 34, 0, 0))
122 end 122 end
123 123
124 should 'format time with 2 digits minutes' do 124 should 'format time with 2 digits minutes' do
125 - assert_equal '22 November 2008, 15:04', show_time(Time.mktime(2008, 11, 22, 15, 04, 0, 0)) 125 + assert_equal 'November 22, 2008 15:04', show_time(Time.mktime(2008, 11, 22, 15, 04, 0, 0))
126 end 126 end
127 127
128 should 'translate time' do 128 should 'translate time' do
129 time = Time.parse('25 May 2009, 12:47') 129 time = Time.parse('25 May 2009, 12:47')
130 - assert_equal '25 May 2009, 12:47', show_time(time) 130 + assert_equal 'May 25, 2009 12:47', show_time(time)
131 end 131 end
132 132
133 should 'handle nil time' do 133 should 'handle nil time' do
test/unit/enterprise_homepage_test.rb
@@ -26,4 +26,9 @@ class EnterpriseHomepageTest &lt; ActiveSupport::TestCase @@ -26,4 +26,9 @@ class EnterpriseHomepageTest &lt; ActiveSupport::TestCase
26 assert_equal false, a.can_display_hits? 26 assert_equal false, a.can_display_hits?
27 end 27 end
28 28
  29 + should 'have can_display_media_panel with default true' do
  30 + a = EnterpriseHomepage.new
  31 + assert a.can_display_media_panel?
  32 + end
  33 +
29 end 34 end
test/unit/event_test.rb
@@ -29,15 +29,9 @@ class EventTest &lt; ActiveSupport::TestCase @@ -29,15 +29,9 @@ class EventTest &lt; ActiveSupport::TestCase
29 assert_equal 'South Noosfero street, 88', e.address 29 assert_equal 'South Noosfero street, 88', e.address
30 end 30 end
31 31
32 - should 'have a start date' do  
33 - e = Event.new  
34 - e.start_date = Date.today  
35 - assert_kind_of Date, e.start_date  
36 - end  
37 -  
38 should 'set start date default value as today' do 32 should 'set start date default value as today' do
39 e = Event.new 33 e = Event.new
40 - assert_equal Date.today, e.start_date 34 + assert_in_delta DateTime.now.to_i, e.start_date.to_i, 1
41 end 35 end
42 36
43 should 'require start date' do 37 should 'require start date' do
@@ -45,38 +39,32 @@ class EventTest &lt; ActiveSupport::TestCase @@ -45,38 +39,32 @@ class EventTest &lt; ActiveSupport::TestCase
45 e.start_date = nil 39 e.start_date = nil
46 e.valid? 40 e.valid?
47 assert e.errors[:start_date.to_s].present? 41 assert e.errors[:start_date.to_s].present?
48 - e.start_date = Date.today 42 + e.start_date = DateTime.now
49 e.valid? 43 e.valid?
50 refute e.errors[:start_date.to_s].present? 44 refute e.errors[:start_date.to_s].present?
51 end 45 end
52 46
53 - should 'have a end date' do  
54 - e = Event.new  
55 - e.end_date = Date.today  
56 - assert_kind_of Date, e.end_date  
57 - end  
58 -  
59 should 'use its own icon' do 47 should 'use its own icon' do
60 assert_equal 'event', Event.icon_name 48 assert_equal 'event', Event.icon_name
61 end 49 end
62 50
63 should 'not allow end date before start date' do 51 should 'not allow end date before start date' do
64 - e = build(Event, :start_date => Date.new(2008, 01, 01), :end_date => Date.new(2007,01,01)) 52 + e = build(Event, :start_date => DateTime.new(2008, 01, 01), :end_date => DateTime.new(2007,01,01))
65 e.valid? 53 e.valid?
66 assert e.errors[:start_date.to_s].present? 54 assert e.errors[:start_date.to_s].present?
67 55
68 - e.end_date = Date.new(2008,01,05) 56 + e.end_date = DateTime.new(2008,01,05)
69 e.valid? 57 e.valid?
70 refute e.errors[:start_date.to_s].present? 58 refute e.errors[:start_date.to_s].present?
71 end 59 end
72 60
73 should 'find by range of dates' do 61 should 'find by range of dates' do
74 profile = create_user('testuser').person 62 profile = create_user('testuser').person
75 - e1 = create(Event, :name => 'e1', :start_date => Date.new(2008,1,1), :profile => profile)  
76 - e2 = create(Event, :name => 'e2', :start_date => Date.new(2008,2,1), :profile => profile)  
77 - e3 = create(Event, :name => 'e3', :start_date => Date.new(2008,3,1), :profile => profile) 63 + e1 = create(Event, :name => 'e1', :start_date => DateTime.new(2008,1,1), :profile => profile)
  64 + e2 = create(Event, :name => 'e2', :start_date => DateTime.new(2008,2,1), :profile => profile)
  65 + e3 = create(Event, :name => 'e3', :start_date => DateTime.new(2008,3,1), :profile => profile)
78 66
79 - found = Event.by_range(Date.new(2008, 1, 1)..Date.new(2008, 2, 28)) 67 + found = Event.by_range(DateTime.new(2008, 1, 1)..DateTime.new(2008, 2, 28))
80 assert_includes found, e1 68 assert_includes found, e1
81 assert_includes found, e2 69 assert_includes found, e2
82 assert_not_includes found, e3 70 assert_not_includes found, e3
@@ -84,32 +72,33 @@ class EventTest &lt; ActiveSupport::TestCase @@ -84,32 +72,33 @@ class EventTest &lt; ActiveSupport::TestCase
84 72
85 should 'filter events by range' do 73 should 'filter events by range' do
86 profile = create_user('testuser').person 74 profile = create_user('testuser').person
87 - e1 = create(Event, :name => 'e1', :start_date => Date.new(2008,1,15), :profile => profile)  
88 - assert_includes profile.events.by_range(Date.new(2008, 1, 10)..Date.new(2008, 1, 20)), e1 75 + e1 = create(Event, :name => 'e1', :start_date => DateTime.new(2008,1,15), :profile => profile)
  76 + assert_includes profile.events.by_range(DateTime.new(2008, 1, 10)..DateTime.new(2008, 1, 20)), e1
89 end 77 end
90 78
91 should 'provide period for searching in month' do 79 should 'provide period for searching in month' do
92 - assert_equal Date.new(2008, 1, 1)..Date.new(2008,1,31), Event.date_range(2008, 1)  
93 - assert_equal Date.new(2008, 2, 1)..Date.new(2008,2,29), Event.date_range(2008, 2)  
94 - assert_equal Date.new(2007, 2, 1)..Date.new(2007,2,28), Event.date_range(2007, 2) 80 + assert_equal DateTime.new(2008, 1, 1)..DateTime.new(2008,1,31), Event.date_range(2008, 1)
  81 + assert_equal DateTime.new(2008, 2, 1)..DateTime.new(2008,2,29), Event.date_range(2008, 2)
  82 + assert_equal DateTime.new(2007, 2, 1)..DateTime.new(2007,2,28), Event.date_range(2007, 2)
95 end 83 end
96 84
97 should 'support string arguments to Event#date_range' do 85 should 'support string arguments to Event#date_range' do
98 - assert_equal Date.new(2008,1,1)..Date.new(2008,1,31), Event.date_range('2008', '1') 86 + assert_equal DateTime.new(2008,1,1)..DateTime.new(2008,1,31), Event.date_range('2008', '1')
99 end 87 end
100 88
101 should 'provide range of dates for event with both dates filled' do 89 should 'provide range of dates for event with both dates filled' do
102 - e = build(Event, :start_date => Date.new(2008, 1, 1), :end_date => Date.new(2008, 1, 5))  
103 - assert_equal (Date.new(2008,1,1)..Date.new(2008,1,5)), e.date_range 90 + e = build(Event, :start_date => DateTime.new(2008, 1, 1), :end_date => DateTime.new(2008, 1, 5))
  91 + assert_equal (DateTime.new(2008,1,1)..DateTime.new(2008,1,5)), e.date_range
104 end 92 end
105 93
106 should 'provide range of dates for event with only start date' do 94 should 'provide range of dates for event with only start date' do
107 - e = build(Event, :start_date => Date.new(2008, 1, 1))  
108 - assert_equal (Date.new(2008,1,1)..Date.new(2008,1,1)), e.date_range 95 + e = build(Event, :start_date => DateTime.new(2008, 1, 1))
  96 + assert_equal (DateTime.new(2008,1,1)..DateTime.new(2008,1,1)), e.date_range
109 end 97 end
110 98
111 should 'provide nice display format' do 99 should 'provide nice display format' do
112 - event = build(Event, :start_date => Date.new(2008,1,1), :end_date => Date.new(2008,1,1), :link => 'http://www.myevent.org', :body => '<p>my somewhat short description</p>') 100 + date = Time.zone.local(2008, 1, 1, 0, 0, 0)
  101 + event = build(Event, :start_date => date, :end_date => date, :link => 'http://www.myevent.org', :body => '<p>my somewhat short description</p>')
113 display = instance_eval(&event.to_html) 102 display = instance_eval(&event.to_html)
114 103
115 assert_tag_in_string display, :content => Regexp.new("January 1, 2008") 104 assert_tag_in_string display, :content => Regexp.new("January 1, 2008")
@@ -148,7 +137,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -148,7 +137,7 @@ class EventTest &lt; ActiveSupport::TestCase
148 profile = create_user('testuser').person 137 profile = create_user('testuser').person
149 event = create(Event, :profile => profile, :name => 'test', 138 event = create(Event, :profile => profile, :name => 'test',
150 :body => '<p>first paragraph </p><p>second paragraph </p>', 139 :body => '<p>first paragraph </p><p>second paragraph </p>',
151 - :link => 'www.colivre.coop.br', :start_date => Date.today) 140 + :link => 'www.colivre.coop.br', :start_date => DateTime.now)
152 141
153 assert_match '<p>first paragraph </p>', event.first_paragraph 142 assert_match '<p>first paragraph </p>', event.first_paragraph
154 end 143 end
@@ -161,7 +150,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -161,7 +150,7 @@ class EventTest &lt; ActiveSupport::TestCase
161 150
162 should 'filter HTML in body' do 151 should 'filter HTML in body' do
163 profile = create_user('testuser').person 152 profile = create_user('testuser').person
164 - e = create(Event, :profile => profile, :name => 'test', :body => '<p>a paragraph (valid)</p><script type="text/javascript">/* this is invalid */</script>"', :link => 'www.colivre.coop.br', :start_date => Date.today) 153 + e = create(Event, :profile => profile, :name => 'test', :body => '<p>a paragraph (valid)</p><script type="text/javascript">/* this is invalid */</script>"', :link => 'www.colivre.coop.br', :start_date => DateTime.now)
165 154
166 assert_tag_in_string e.body, :tag => 'p', :content => 'a paragraph (valid)' 155 assert_tag_in_string e.body, :tag => 'p', :content => 'a paragraph (valid)'
167 assert_no_tag_in_string e.body, :tag => 'script' 156 assert_no_tag_in_string e.body, :tag => 'script'
@@ -169,7 +158,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -169,7 +158,7 @@ class EventTest &lt; ActiveSupport::TestCase
169 158
170 should 'filter HTML in name' do 159 should 'filter HTML in name' do
171 profile = create_user('testuser').person 160 profile = create_user('testuser').person
172 - e = create(Event, :profile => profile, :name => '<p>a paragraph (valid)</p><script type="text/javascript">/* this is invalid */</script>"', :link => 'www.colivre.coop.br', :start_date => Date.today) 161 + e = create(Event, :profile => profile, :name => '<p>a paragraph (valid)</p><script type="text/javascript">/* this is invalid */</script>"', :link => 'www.colivre.coop.br', :start_date => DateTime.now)
173 162
174 assert_tag_in_string e.name, :tag => 'p', :content => 'a paragraph (valid)' 163 assert_tag_in_string e.name, :tag => 'p', :content => 'a paragraph (valid)'
175 assert_no_tag_in_string e.name, :tag => 'script' 164 assert_no_tag_in_string e.name, :tag => 'script'
@@ -184,8 +173,8 @@ class EventTest &lt; ActiveSupport::TestCase @@ -184,8 +173,8 @@ class EventTest &lt; ActiveSupport::TestCase
184 173
185 should 'list all events' do 174 should 'list all events' do
186 profile = fast_create(Profile) 175 profile = fast_create(Profile)
187 - event1 = build(Event, :name => 'Ze Birthday', :start_date => Date.today)  
188 - event2 = build(Event, :name => 'Mane Birthday', :start_date => Date.today >> 1) 176 + event1 = build(Event, :name => 'Ze Birthday', :start_date => DateTime.now)
  177 + event2 = build(Event, :name => 'Mane Birthday', :start_date => DateTime.now >> 1)
189 profile.events << [event1, event2] 178 profile.events << [event1, event2]
190 assert_includes profile.events, event1 179 assert_includes profile.events, event1
191 assert_includes profile.events, event2 180 assert_includes profile.events, event2
@@ -194,7 +183,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -194,7 +183,7 @@ class EventTest &lt; ActiveSupport::TestCase
194 should 'list events by day' do 183 should 'list events by day' do
195 profile = fast_create(Profile) 184 profile = fast_create(Profile)
196 185
197 - today = Date.today 186 + today = DateTime.now
198 yesterday_event = build(Event, :name => 'Joao Birthday', :start_date => today - 1.day) 187 yesterday_event = build(Event, :name => 'Joao Birthday', :start_date => today - 1.day)
199 today_event = build(Event, :name => 'Ze Birthday', :start_date => today) 188 today_event = build(Event, :name => 'Ze Birthday', :start_date => today)
200 tomorrow_event = build(Event, :name => 'Mane Birthday', :start_date => today + 1.day) 189 tomorrow_event = build(Event, :name => 'Mane Birthday', :start_date => today + 1.day)
@@ -207,7 +196,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -207,7 +196,7 @@ class EventTest &lt; ActiveSupport::TestCase
207 should 'list events by month' do 196 should 'list events by month' do
208 profile = fast_create(Profile) 197 profile = fast_create(Profile)
209 198
210 - today = Date.new(2013, 10, 6) 199 + today = DateTime.new(2013, 10, 6)
211 200
212 last_month_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.month) 201 last_month_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.month)
213 202
@@ -230,7 +219,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -230,7 +219,7 @@ class EventTest &lt; ActiveSupport::TestCase
230 should 'event by month ordered by start date'do 219 should 'event by month ordered by start date'do
231 profile = fast_create(Profile) 220 profile = fast_create(Profile)
232 221
233 - today = Date.new(2013, 10, 6) 222 + today = DateTime.new(2013, 10, 6)
234 223
235 event_1 = Event.new(:name => 'Maria Birthday', :start_date => today + 1.day) 224 event_1 = Event.new(:name => 'Maria Birthday', :start_date => today + 1.day)
236 event_2 = Event.new(:name => 'Joana Birthday', :start_date => today - 1.day) 225 event_2 = Event.new(:name => 'Joana Birthday', :start_date => today - 1.day)
@@ -248,7 +237,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -248,7 +237,7 @@ class EventTest &lt; ActiveSupport::TestCase
248 should 'list events in a range' do 237 should 'list events in a range' do
249 profile = fast_create(Profile) 238 profile = fast_create(Profile)
250 239
251 - today = Date.today 240 + today = DateTime.now
252 event_in_range = build(Event, :name => 'Noosfero Conference', :start_date => today - 2.day, :end_date => today + 2.day) 241 event_in_range = build(Event, :name => 'Noosfero Conference', :start_date => today - 2.day, :end_date => today + 2.day)
253 event_in_day = build(Event, :name => 'Ze Birthday', :start_date => today) 242 event_in_day = build(Event, :name => 'Ze Birthday', :start_date => today)
254 243
@@ -262,7 +251,7 @@ class EventTest &lt; ActiveSupport::TestCase @@ -262,7 +251,7 @@ class EventTest &lt; ActiveSupport::TestCase
262 should 'not list events out of range' do 251 should 'not list events out of range' do
263 profile = fast_create(Profile) 252 profile = fast_create(Profile)
264 253
265 - today = Date.today 254 + today = DateTime.now
266 event_in_range1 = build(Event, :name => 'Foswiki Conference', :start_date => today - 2.day, :end_date => today + 2.day) 255 event_in_range1 = build(Event, :name => 'Foswiki Conference', :start_date => today - 2.day, :end_date => today + 2.day)
267 event_in_range2 = build(Event, :name => 'Debian Conference', :start_date => today - 2.day, :end_date => today + 3.day) 256 event_in_range2 = build(Event, :name => 'Debian Conference', :start_date => today - 2.day, :end_date => today + 3.day)
268 event_out_of_range = build(Event, :name => 'Ze Birthday', :start_date => today - 5.day, :end_date => today - 3.day) 257 event_out_of_range = build(Event, :name => 'Ze Birthday', :start_date => today - 5.day, :end_date => today - 3.day)
@@ -357,4 +346,9 @@ class EventTest &lt; ActiveSupport::TestCase @@ -357,4 +346,9 @@ class EventTest &lt; ActiveSupport::TestCase
357 assert event.translatable? 346 assert event.translatable?
358 end 347 end
359 348
  349 + should 'have can_display_media_panel with default true' do
  350 + a = Event.new
  351 + assert a.can_display_media_panel?
  352 + end
  353 +
360 end 354 end
test/unit/profile_test.rb
@@ -1563,8 +1563,8 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1563,8 +1563,8 @@ class ProfileTest &lt; ActiveSupport::TestCase
1563 1563
1564 should 'list all events' do 1564 should 'list all events' do
1565 profile = fast_create(Profile) 1565 profile = fast_create(Profile)
1566 - event1 = Event.new(:name => 'Ze Birthday', :start_date => Date.today)  
1567 - event2 = Event.new(:name => 'Mane Birthday', :start_date => Date.today >> 1) 1566 + event1 = Event.new(:name => 'Ze Birthday', :start_date => DateTime.now)
  1567 + event2 = Event.new(:name => 'Mane Birthday', :start_date => DateTime.now >> 1)
1568 profile.events << [event1, event2] 1568 profile.events << [event1, event2]
1569 assert_includes profile.events, event1 1569 assert_includes profile.events, event1
1570 assert_includes profile.events, event2 1570 assert_includes profile.events, event2
@@ -1573,7 +1573,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1573,7 +1573,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1573 should 'list events by day' do 1573 should 'list events by day' do
1574 profile = fast_create(Profile) 1574 profile = fast_create(Profile)
1575 1575
1576 - today = Date.today 1576 + today = DateTime.now
1577 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day) 1577 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day)
1578 today_event = Event.new(:name => 'Ze Birthday', :start_date => today) 1578 today_event = Event.new(:name => 'Ze Birthday', :start_date => today)
1579 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day) 1579 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day)
@@ -1586,7 +1586,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1586,7 +1586,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1586 should 'list events by month' do 1586 should 'list events by month' do
1587 profile = fast_create(Profile) 1587 profile = fast_create(Profile)
1588 1588
1589 - today = Date.new(2014, 03, 2) 1589 + today = DateTime.new(2014, 03, 2)
1590 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day) 1590 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day)
1591 today_event = Event.new(:name => 'Ze Birthday', :start_date => today) 1591 today_event = Event.new(:name => 'Ze Birthday', :start_date => today)
1592 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day) 1592 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day)
@@ -1599,7 +1599,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1599,7 +1599,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1599 should 'list events in a range' do 1599 should 'list events in a range' do
1600 profile = fast_create(Profile) 1600 profile = fast_create(Profile)
1601 1601
1602 - today = Date.today 1602 + today = DateTime.now
1603 event_in_range = Event.new(:name => 'Noosfero Conference', :start_date => today - 2.day, :end_date => today + 2.day) 1603 event_in_range = Event.new(:name => 'Noosfero Conference', :start_date => today - 2.day, :end_date => today + 2.day)
1604 event_in_day = Event.new(:name => 'Ze Birthday', :start_date => today) 1604 event_in_day = Event.new(:name => 'Ze Birthday', :start_date => today)
1605 1605
@@ -1613,7 +1613,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1613,7 +1613,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1613 should 'not list events out of range' do 1613 should 'not list events out of range' do
1614 profile = fast_create(Profile) 1614 profile = fast_create(Profile)
1615 1615
1616 - today = Date.today 1616 + today = DateTime.now
1617 event_in_range1 = Event.new(:name => 'Foswiki Conference', :start_date => today - 2.day, :end_date => today + 2.day) 1617 event_in_range1 = Event.new(:name => 'Foswiki Conference', :start_date => today - 2.day, :end_date => today + 2.day)
1618 event_in_range2 = Event.new(:name => 'Debian Conference', :start_date => today - 2.day, :end_date => today + 3.day) 1618 event_in_range2 = Event.new(:name => 'Debian Conference', :start_date => today - 2.day, :end_date => today + 3.day)
1619 event_out_of_range = Event.new(:name => 'Ze Birthday', :start_date => today - 5.day, :end_date => today - 3.day) 1619 event_out_of_range = Event.new(:name => 'Ze Birthday', :start_date => today - 5.day, :end_date => today - 3.day)
@@ -1627,9 +1627,9 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1627,9 +1627,9 @@ class ProfileTest &lt; ActiveSupport::TestCase
1627 1627
1628 should 'sort events by date' do 1628 should 'sort events by date' do
1629 profile = fast_create(Profile) 1629 profile = fast_create(Profile)
1630 - event1 = Event.new(:name => 'Noosfero Hackaton', :start_date => Date.today)  
1631 - event2 = Event.new(:name => 'Debian Day', :start_date => Date.today - 1)  
1632 - event3 = Event.new(:name => 'Fisl 10', :start_date => Date.today + 1) 1630 + event1 = Event.new(:name => 'Noosfero Hackaton', :start_date => DateTime.now)
  1631 + event2 = Event.new(:name => 'Debian Day', :start_date => DateTime.now - 1)
  1632 + event3 = Event.new(:name => 'Fisl 10', :start_date => DateTime.now + 1)
1633 profile.events << [event1, event2, event3] 1633 profile.events << [event1, event2, event3]
1634 assert_equal [event2, event1, event3], profile.events 1634 assert_equal [event2, event1, event3], profile.events
1635 end 1635 end
test/unit/textile_article_test.rb
@@ -174,6 +174,11 @@ class TextileArticleTest &lt; ActiveSupport::TestCase @@ -174,6 +174,11 @@ class TextileArticleTest &lt; ActiveSupport::TestCase
174 assert_equal "<p>one\nparagraph</p>", build_article("one\nparagraph").to_html 174 assert_equal "<p>one\nparagraph</p>", build_article("one\nparagraph").to_html
175 end 175 end
176 176
  177 + should 'have can_display_media_panel with default true' do
  178 + a = TextileArticle.new
  179 + assert a.can_display_media_panel?
  180 + end
  181 +
177 protected 182 protected
178 183
179 def build_article(input = nil, options = {}) 184 def build_article(input = nil, options = {})
test/unit/tiny_mce_article_test.rb
@@ -235,4 +235,9 @@ end @@ -235,4 +235,9 @@ end
235 :attributes => { :colspan => 2, :rowspan => 3 } 235 :attributes => { :colspan => 2, :rowspan => 3 }
236 end 236 end
237 237
  238 + should 'have can_display_media_panel with default true' do
  239 + a = TinyMceArticle.new
  240 + assert a.can_display_media_panel?
  241 + end
  242 +
238 end 243 end