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 92  
93 93 def events
94 94 if params[:year].blank? && params[:year].blank? && params[:day].blank?
95   - @date = Date.today
  95 + @date = DateTime.now
96 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 99 day = (params[:day] ? params[:day].to_i : 1)
100 100 @date = build_date(year, month, day)
101 101 end
... ... @@ -106,9 +106,7 @@ class SearchController < PublicController
106 106 @events = @category ?
107 107 environment.events.by_day(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
108 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 110 @events = @category ?
113 111 environment.events.by_month(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
114 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 51 elsif date_format == 'past_time'
52 52 left_time = true
53 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 55 end
56 56  
57 57 def link_to_comments(article, args = {})
... ...
app/helpers/dates_helper.rb
... ... @@ -43,9 +43,14 @@ module DatesHelper
43 43 end
44 44  
45 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 54 else
50 55 ''
51 56 end
... ... @@ -53,7 +58,7 @@ module DatesHelper
53 58  
54 59 def show_period(date1, date2 = nil, use_numbers = false)
55 60 if (date1 == date2) || (date2.nil?)
56   - show_date(date1, use_numbers)
  61 + show_time(date1, use_numbers)
57 62 else
58 63 if date1.year == date2.year
59 64 if date1.month == date2.month
... ... @@ -72,8 +77,8 @@ module DatesHelper
72 77 end
73 78 else
74 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 83 end
79 84 end
... ... @@ -106,18 +111,18 @@ module DatesHelper
106 111  
107 112 def build_date(year, month, day = 1)
108 113 if year.blank? and month.blank? and day.blank?
109   - Date.today
  114 + DateTime.now
110 115 else
111 116 if year.blank?
112   - year = Date.today.year
  117 + year = DateTime.now.year
113 118 end
114 119 if month.blank?
115   - month = Date.today.month
  120 + month = DateTime.now.month
116 121 end
117 122 if day.blank?
118 123 day = 1
119 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 126 end
122 127 end
123 128  
... ...
app/helpers/events_helper.rb
... ... @@ -16,7 +16,7 @@ module EventsHelper
16 16  
17 17 content_tag( 'tr',
18 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 20 content_tag('div',link_to(article.name,article.url),:class => 'event-title') +
21 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 30 # the day itself
31 31 date,
32 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 34 # is this date in the current month?
35 35 true
36 36 ]
... ...
app/helpers/forms_helper.rb
... ... @@ -151,7 +151,7 @@ module FormsHelper
151 151 datepicker_options[:close_text] ||= _('Done')
152 152 datepicker_options[:constrain_input] ||= true
153 153 datepicker_options[:current_text] ||= _('Today')
154   - datepicker_options[:date_format] ||= 'mm/dd/yy'
  154 + datepicker_options[:date_format] ||= 'yy/mm/dd'
155 155 datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')]
156 156 datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')]
157 157 datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')]
... ... @@ -236,7 +236,7 @@ module FormsHelper
236 236 weekHeader: #{datepicker_options[:week_header].to_json},
237 237 yearRange: #{datepicker_options[:year_range].to_json},
238 238 yearSuffix: #{datepicker_options[:year_suffix].to_json}
239   - })
  239 + }).datepicker('setDate', new Date('#{value}'))
240 240 </script>
241 241 ".html_safe
242 242 result
... ...
app/models/article.rb
... ... @@ -635,6 +635,14 @@ class Article &lt; ActiveRecord::Base
635 635 can_display_hits? && display_hits
636 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 646 def image?
639 647 false
640 648 end
... ... @@ -743,9 +751,10 @@ class Article &lt; ActiveRecord::Base
743 751 end
744 752  
745 753 def body_images_paths
746   - require 'uri'
747 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 758 end
750 759 end
751 760  
... ...
app/models/category.rb
... ... @@ -81,7 +81,7 @@ class Category &lt; ActiveRecord::Base
81 81 end
82 82  
83 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 85 end
86 86  
87 87 def display_in_menu?
... ...
app/models/enterprise_homepage.rb
... ... @@ -35,4 +35,8 @@ class EnterpriseHomepage &lt; Article
35 35 false
36 36 end
37 37  
  38 + def can_display_media_panel?
  39 + true
  40 + end
  41 +
38 42 end
... ...
app/models/event.rb
... ... @@ -23,7 +23,7 @@ class Event &lt; Article
23 23  
24 24 def initialize(*args)
25 25 super(*args)
26   - self.start_date ||= Date.today
  26 + self.start_date ||= DateTime.now
27 27 end
28 28  
29 29 validates_presence_of :title, :start_date
... ... @@ -35,7 +35,7 @@ class Event &lt; Article
35 35 end
36 36  
37 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 39 :order => 'start_date ASC'
40 40 }
41 41 }
... ... @@ -80,7 +80,7 @@ class Event &lt; Article
80 80  
81 81 def self.date_range(year, month)
82 82 if year.nil? || month.nil?
83   - today = Date.today
  83 + today = DateTime.now
84 84 year = today.year
85 85 month = today.month
86 86 else
... ... @@ -88,7 +88,7 @@ class Event &lt; Article
88 88 month = month.to_i
89 89 end
90 90  
91   - first_day = Date.new(year, month, 1)
  91 + first_day = DateTime.new(year, month, 1)
92 92 last_day = first_day + 1.month - 1.day
93 93  
94 94 first_day..last_day
... ... @@ -114,7 +114,7 @@ class Event &lt; Article
114 114 end
115 115  
116 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 118 end
119 119  
120 120 alias_method :article_lead, :lead
... ... @@ -134,6 +134,10 @@ class Event &lt; Article
134 134 true
135 135 end
136 136  
  137 + def can_display_media_panel?
  138 + true
  139 + end
  140 +
137 141 include Noosfero::TranslatableContent
138 142 include MaybeAddHttp
139 143  
... ...
app/models/textile_article.rb
... ... @@ -24,6 +24,10 @@ class TextileArticle &lt; TextArticle
24 24 true
25 25 end
26 26  
  27 + def can_display_media_panel?
  28 + true
  29 + end
  30 +
27 31 protected
28 32  
29 33 def convert_to_html(textile)
... ...
app/models/tiny_mce_article.rb
... ... @@ -28,4 +28,8 @@ class TinyMceArticle &lt; TextArticle
28 28 true
29 29 end
30 30  
  31 + def can_display_media_panel?
  32 + true
  33 + end
  34 +
31 35 end
... ...
app/views/cms/_event.html.erb
... ... @@ -8,9 +8,8 @@
8 8 <%= render :partial => 'general_fields' %>
9 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 14 <%= labelled_form_field(_('Event website:'), text_field(:article, :link)) %>
16 15  
... ...
app/views/cms/edit.html.erb
1 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 4 <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %>
7 5  
8 6 <%= hidden_field_tag("type", @type) if @type %>
... ... @@ -68,7 +66,7 @@
68 66 <% end %>
69 67 </div>
70 68  
71   -<% if show_media_panel %>
  69 +<% if @article.display_media_panel? %>
72 70 <%= render :partial => 'text_editor_sidebar' %>
73 71 <% end %>
74 72  
... ...
app/views/content_viewer/_publishing_info.html.erb
1 1 <span class="publishing-info">
2 2 <span class="date">
3   - <%= show_date(@page.published_at) %>
  3 + <%= show_time(@page.published_at) %>
4 4 </span>
5 5 <span class="author">
6 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 @@
  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
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20150712130827) do
  14 +ActiveRecord::Schema.define(:version => 20150722042714) do
15 15  
16 16 create_table "abuse_reports", :force => true do |t|
17 17 t.integer "reporter_id"
... ... @@ -75,8 +75,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150712130827) do
75 75 t.integer "comments_count"
76 76 t.boolean "advertise", :default => true
77 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 80 t.integer "children_count", :default => 0
81 81 t.boolean "accept_comments", :default => true
82 82 t.integer "reference_article_id"
... ... @@ -127,8 +127,8 @@ ActiveRecord::Schema.define(:version =&gt; 20150712130827) do
127 127 t.integer "comments_count", :default => 0
128 128 t.boolean "advertise", :default => true
129 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 132 t.integer "children_count", :default => 0
133 133 t.boolean "accept_comments", :default => true
134 134 t.integer "reference_article_id"
... ...
features/events.feature
... ... @@ -223,7 +223,7 @@ Feature: events
223 223 | owner | name | start_date | end_date |
224 224 | josesilva | WikiSym 2009 | 2009-10-25 | 2009-10-27 |
225 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 228 Scenario: show place of the event
229 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 29  
30 30 def initialize(*args)
31 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 34 end
35 35  
36 36 def set_hidden_position
... ... @@ -72,20 +72,20 @@ class CommunityTrackPlugin::Step &lt; Folder
72 72 end
73 73  
74 74 def active?
75   - (start_date..end_date).include?(Date.today)
  75 + (start_date..end_date).cover?(DateTime.now)
76 76 end
77 77  
78 78 def finished?
79   - Date.today > end_date
  79 + DateTime.now > end_date
80 80 end
81 81  
82 82 def waiting?
83   - Date.today < start_date
  83 + DateTime.now < start_date
84 84 end
85 85  
86 86 def schedule_activation
87 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 89 schedule_date = !accept_comments ? start_date : end_date + 1.day
90 90 CommunityTrackPlugin::ActivationJob.find(id).destroy_all
91 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 6 def setup
7 7 @profile = Community.create!(:name => 'Sample community', :identifier => 'sample-community')
8 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 11 user = create_user('testinguser')
12 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 9 @track.add_category(@category)
10 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 13 Delayed::Job.destroy_all
14 14 end
15 15  
... ... @@ -22,39 +22,39 @@ class StepTest &lt; ActiveSupport::TestCase
22 22 end
23 23  
24 24 should 'set accept_comments to false on create' do
25   - today = Date.today
  25 + today = DateTime.now
26 26 step = CommunityTrackPlugin::Step.create(:name => 'Step', :body => 'body', :profile => @profile, :parent => @track, :start_date => today, :end_date => today, :published => true)
27 27 refute step.accept_comments
28 28 end
29 29  
30 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 32 blog = fast_create(Blog)
33 33 step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => blog, :start_date => today, :end_date => today, :published => true)
34 34 refute step.save
35 35 end
36 36  
37 37 should 'do not allow step creation without a parent' do
38   - today = Date.today
  38 + today = DateTime.now
39 39 step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => nil, :start_date => today, :end_date => today, :published => true)
40 40 refute step.save
41 41 end
42 42  
43 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 46 assert @step.save
47 47 end
48 48  
49 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 52 assert @step.save
53 53 end
54 54  
55 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 58 refute @step.save
59 59 end
60 60  
... ... @@ -71,20 +71,20 @@ class StepTest &lt; ActiveSupport::TestCase
71 71 end
72 72  
73 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 76 assert @step.active?
77 77 end
78 78  
79 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 82 assert @step.finished?
83 83 end
84 84  
85 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 88 assert @step.waiting?
89 89 end
90 90  
... ... @@ -95,17 +95,17 @@ class StepTest &lt; ActiveSupport::TestCase
95 95 end
96 96  
97 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 100 @step.accept_comments = false
101 101 @step.schedule_activation
102 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 104 end
105 105  
106 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 109 @step.schedule_activation
110 110 assert_equal 1, Delayed::Job.count
111 111 @step.schedule_activation
... ... @@ -113,30 +113,30 @@ class StepTest &lt; ActiveSupport::TestCase
113 113 end
114 114  
115 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 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 120 end
121 121  
122 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 125 @step.accept_comments = false
126 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 128 end
129 129  
130 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 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 135 end
136 136  
137 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 140 @step.save!
141 141 assert_equal 1, Delayed::Job.count
142 142 Delayed::Job.destroy_all
... ... @@ -149,13 +149,13 @@ class StepTest &lt; ActiveSupport::TestCase
149 149 refute @step.position
150 150 @step.save!
151 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 153 step2.save!
154 154 assert_equal 2, step2.position
155 155 end
156 156  
157 157 should 'accept comments if step is active' do
158   - @step.start_date = Date.today
  158 + @step.start_date = DateTime.now
159 159 @step.save!
160 160 refute @step.accept_comments
161 161 @step.toggle_activation
... ... @@ -164,8 +164,8 @@ class StepTest &lt; ActiveSupport::TestCase
164 164 end
165 165  
166 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 169 @step.save!
170 170 refute @step.published
171 171 @step.toggle_activation
... ... @@ -174,14 +174,14 @@ class StepTest &lt; ActiveSupport::TestCase
174 174 end
175 175  
176 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 178 @step.save!
179 179 @step.toggle_activation
180 180 @step.reload
181 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 185 @step.save!
186 186 @step.toggle_activation
187 187 @step.reload
... ... @@ -203,7 +203,7 @@ class StepTest &lt; ActiveSupport::TestCase
203 203 end
204 204  
205 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 207 step1.save!
208 208 @step.hidden = true
209 209 @step.save!
... ... @@ -215,7 +215,7 @@ class StepTest &lt; ActiveSupport::TestCase
215 215  
216 216 should 'decrement lower items positions if a step becomes hidden' do
217 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 219 step1.save!
220 220 assert_equal 2, step1.position
221 221 @step.hidden = true
... ... @@ -225,7 +225,7 @@ class StepTest &lt; ActiveSupport::TestCase
225 225 end
226 226  
227 227 should 'do not publish a hidden step' do
228   - @step.start_date = Date.today
  228 + @step.start_date = DateTime.now
229 229 @step.hidden = true
230 230 @step.save!
231 231 refute @step.published
... ... @@ -266,7 +266,7 @@ class StepTest &lt; ActiveSupport::TestCase
266 266 end
267 267  
268 268 should 'enable comments on children when step is activated' do
269   - @step.start_date = Date.today
  269 + @step.start_date = DateTime.now
270 270 @step.save!
271 271 refute @step.accept_comments
272 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 276 end
277 277  
278 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 280 @step.save!
282 281 refute @step.accept_comments
283 282 @step.toggle_activation
... ...
plugins/environment_notification/controllers/environment_notification_plugin_admin_controller.rb 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  1 +class EnvironmentNotificationPlugin::DangerNotification < EnvironmentNotificationPlugin::EnvironmentNotification
  2 +end
... ...
plugins/environment_notification/models/environment_notification_plugin/environment_notification.rb 0 → 100644
... ... @@ -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 @@
  1 +class EnvironmentNotificationPlugin::InformationNotification < EnvironmentNotificationPlugin::EnvironmentNotification
  2 +end
... ...
plugins/environment_notification/models/environment_notification_plugin/success_notification.rb 0 → 100644
... ... @@ -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 @@
  1 +class EnvironmentNotificationPlugin::WarningNotification < EnvironmentNotificationPlugin::EnvironmentNotification
  2 +end
... ...
plugins/environment_notification/public/environment_notification_plugin.js 0 → 100644
... ... @@ -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 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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  1 +<%= render :partial => "form" %>
... ...
plugins/environment_notification/views/environment_notification_plugin_admin/index.html.erb 0 → 100644
... ... @@ -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 @@
  1 +<%= render :partial => "form" %>
... ...
plugins/environment_notification/views/environment_notification_plugin_admin/show_notification.html.erb 0 → 100644
... ... @@ -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 30 events = user.nil? ? events.public : events.display_filter(user,nil)
31 31  
32 32 if future_only
33   - events = events.where('start_date >= ?', Date.today)
  33 + events = events.where('start_date >= ?', DateTime.now.beginning_of_day)
34 34 end
35 35  
36 36 if date_distance_limit > 0
37 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 41 end
42 42  
... ...
plugins/event/test/functional/event_block_test.rb
1 1 require File.dirname(__FILE__) + '/../../../../test/test_helper'
2 2  
  3 +
3 4 # Re-raise errors caught by the controller.
4 5 class HomeController
5   - #append_view_path File.join(File.dirname(__FILE__) + '/../../views')
  6 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
6 7 def rescue_action(e)
7 8 raise e
8 9 end
... ... @@ -15,7 +16,7 @@ class HomeControllerTest &lt; ActionController::TestCase
15 16 @env.enable_plugin('EventPlugin')
16 17  
17 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 21 box = Box.create!(:owner => @env)
21 22 @block = EventPlugin::EventBlock.create!(:box => box)
... ... @@ -27,6 +28,7 @@ class HomeControllerTest &lt; ActionController::TestCase
27 28  
28 29 should 'see events microdata sturcture' do
29 30 get :index
  31 +#raise response.body.inspect
30 32 assert_select '.event-plugin_event-block ul.events'
31 33 assert_select ev
32 34 assert_select ev + 'a[itemprop="url"]'
... ... @@ -41,15 +43,15 @@ class HomeControllerTest &lt; ActionController::TestCase
41 43  
42 44 should 'see event duration' do
43 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 48 @e1a.save!
47 49 get :index
48 50 assert_select ev + 'time.duration[itemprop="endDate"]', /1 day/
49 51  
50 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 55 @e1a.save!
54 56 get :index
55 57 assert_select ev + 'time.duration[itemprop="endDate"]', /2 days/
... ... @@ -60,8 +62,8 @@ class HomeControllerTest &lt; ActionController::TestCase
60 62 assert_select ev + 'time.duration[itemprop="endDate"]', false
61 63  
62 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 67 @e1a.save!
66 68 get :index
67 69 assert_select ev + 'time.duration[itemprop="endDate"]', false
... ...
plugins/event/views/blocks/event.html.erb
... ... @@ -2,7 +2,7 @@
2 2  
3 3 <ul class="events">
4 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 6 <li itemscope="itemscope" itemtype="http://data-vocabulary.org/Event" class="event">
7 7 <%= render(
8 8 :file => 'event_plugin/event_block_item',
... ...
plugins/metadata/lib/ext/article.rb
... ... @@ -12,9 +12,9 @@ class Article
12 12 end,
13 13 title: proc{ |a, plugin| "#{a.title} - #{a.profile.name}" },
14 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 18 img
19 19 end,
20 20 see_also: [],
... ... @@ -31,10 +31,10 @@ class Article
31 31 card: 'summary',
32 32 description: proc do |a, plugin|
33 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 35 end,
36 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 40 metadata_spec namespace: :article, key_attr: :property, tags: {
... ...
plugins/metadata/lib/ext/product.rb
... ... @@ -14,8 +14,8 @@ class Product
14 14 description: proc{ |p, plugin| ActionView::Base.full_sanitizer.sanitize p.description },
15 15  
16 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 19 img ||= MetadataPlugin.config[:open_graph][:environment_logo] rescue nil if img.blank?
20 20 img
21 21 end,
... ...
plugins/metadata/lib/ext/profile.rb
... ... @@ -5,8 +5,8 @@ class Profile
5 5 metadata_spec namespace: :og, tags: {
6 6 type: proc{ |p, plugin| plugin.context.params[:og_type] || MetadataPlugin.og_types[:profile] || :profile },
7 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 10 img
11 11 end,
12 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 13 plugin.og_url_for url
14 14 end,
15 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 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 50 Array(values).each do |value|
51 51 value = value.call(object, plugin) if value.is_a? Proc rescue nil
52 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 55 end
55 56 end
56 57 end
... ...
plugins/metadata/lib/metadata_plugin/url_helper.rb
... ... @@ -7,7 +7,8 @@ module MetadataPlugin::UrlHelper
7 7 def og_url_for options
8 8 options.delete :port
9 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 12 end
12 13  
13 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 48 assert_tag tag: 'meta', attributes: { property: 'og:image', content: /\/images\/x.png/ }
49 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 59 should 'render not_found page properly' do
52 60 assert_equal false, Article.exists?(:slug => 'non-existing-page')
53 61 assert_nothing_raised do
... ...
plugins/site_tour/controllers/public/site_tour_plugin_public_controller.rb 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 2 \ No newline at end of file
... ...
plugins/site_tour/public/main.js 0 → 100644
... ... @@ -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 @@
  1 +introjs.min.css
0 2 \ No newline at end of file
... ...
plugins/site_tour/public/tour/en/tour.js.dist 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
... ...
plugins/site_tour/test/unit/site_tour_helper_test.rb 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  1 +../box_organizer/site_tour_plugin
0 2 \ No newline at end of file
... ...
plugins/site_tour/views/profile_design/site_tour_plugin 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../box_organizer/site_tour_plugin
0 2 \ No newline at end of file
... ...
plugins/site_tour/views/site_tour_plugin_admin/index.html.erb 0 → 100644
... ... @@ -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 @@
  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 7 msgstr ""
8 8 "Project-Id-Version: PACKAGE VERSION\n"
9 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 12 "Language-Team: German "
13 13 "<https://hosted.weblate.org/projects/noosfero/documentation/de/>\n"
14 14 "Language: de\n"
... ... @@ -16,7 +16,7 @@ msgstr &quot;&quot;
16 16 "Content-Type: text/plain; charset=UTF-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 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 21 # type: Content of: <h1>
22 22 #. type: Content of: <h1>
... ... @@ -28,7 +28,7 @@ msgstr &quot;&quot;
28 28 #. type: Content of: <p>
29 29 #: doc/noosfero/plugins/send_email.en.xhtml:2
30 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 33 # type: Content of: <h2>
34 34 #. type: Content of: <h2>
... ... @@ -36,7 +36,7 @@ msgstr &quot;&quot;
36 36 #: doc/noosfero/plugins/google_cse.en.xhtml:3
37 37 #: doc/noosfero/plugins/google_analytics.en.xhtml:3
38 38 msgid "Usage"
39   -msgstr ""
  39 +msgstr "Verwendung"
40 40  
41 41 # type: Content of: <ul><li>
42 42 #. type: Content of: <ul><li>
... ... @@ -52,6 +52,7 @@ msgstr &quot;&quot;
52 52 msgid ""
53 53 "Add a &#8220;to&#8221; and &#8220;message&#8221; field and a submit button"
54 54 msgstr ""
  55 +"Fügt ein ``to``- und ein ``message``-Feld, mit einem ``submit`` Knopf hinzu"
55 56  
56 57 # type: Content of: <ul><li>
57 58 #. type: Content of: <ul><li>
... ...
public/designs/templates/lefttopright/javascripts/template.js
... ... @@ -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 1 #boxes {
2   - display: table;
3 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 19 position: relative;
15 20 float: left;
16   - width: 20%;
17 21 }
18 22  
19   -.box-3 {
  23 +.box-2 {
20 24 position: relative;
21 25 float: right;
22   - width: 20%;
  26 + width: 20.5%;
23 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 36 \ No newline at end of file
... ...
public/designs/themes/base/style.scss
... ... @@ -1505,7 +1505,8 @@ table#recaptcha_table tr:hover td {
1505 1505  
1506 1506 .event-date {
1507 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 1512 .event-link {
... ...
test/functional/events_controller_test.rb
... ... @@ -8,12 +8,12 @@ class EventsControllerTest &lt; ActionController::TestCase
8 8 attr_reader :profile
9 9  
10 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 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 17 assert_tag :tag => 'div', :attributes => {:id => "agenda-items"},
18 18 :descendant => {:tag => 'h3', :content => "Events for #{today}"},
19 19 :descendant => {:tag => 'tr', :content => "Joao Birthday"},
... ... @@ -23,15 +23,15 @@ class EventsControllerTest &lt; ActionController::TestCase
23 23 should 'display calendar of current month' do
24 24 get :events, :profile => profile.identifier
25 25  
26   - month = Date.today.strftime("%B %Y")
  26 + month = DateTime.now.strftime("%B %Y")
27 27 assert_tag :tag => 'table', :attributes => {:class => /current-month/}, :descendant => {:tag => 'caption', :content => /#{month}/}
28 28 end
29 29  
30 30 should 'display links to previous and next month' do
31 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 35 prev_month_name = prev_month.strftime("%B")
36 36 next_month_name = next_month.strftime("%B")
37 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 40  
41 41 should 'see the events paginated' do
42 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 44 end
45 45 get :events, :profile => profile.identifier
46 46 assert_equal 20, assigns(:events).size
47 47 end
48 48  
49 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 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 305  
306 306 should 'search for events' do
307 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 310 get :events, :query => 'event to be found'
311 311  
... ... @@ -314,10 +314,10 @@ class SearchControllerTest &lt; ActionController::TestCase
314 314  
315 315 should 'return events of the day' do
316 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 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 322 get :events, :day => ten_days_ago.day, :month => ten_days_ago.month, :year => ten_days_ago.year
323 323 assert_equal [ev1], assigns(:events)
... ... @@ -325,9 +325,11 @@ class SearchControllerTest &lt; ActionController::TestCase
325 325  
326 326 should 'return events of the day with category' do
327 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 333 ev2 = create_event(person, :name => 'event 2', :start_date => ten_days_ago)
332 334  
333 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 339  
338 340 should 'return events of today when no date specified' do
339 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 345 get :events
344 346  
... ... @@ -349,9 +351,9 @@ class SearchControllerTest &lt; ActionController::TestCase
349 351 person = create_user('someone').person
350 352  
351 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 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 358 get :events
357 359  
... ... @@ -362,8 +364,8 @@ class SearchControllerTest &lt; ActionController::TestCase
362 364 should 'list events for a given month' do
363 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 370 get :events, :year => '2008', :month => '1'
369 371  
... ... @@ -373,7 +375,7 @@ class SearchControllerTest &lt; ActionController::TestCase
373 375 should 'see the events paginated' do
374 376 person = create_user('testuser').person
375 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 379 end
378 380 get :events
379 381 assert_equal 20, assigns(:events).size
... ... @@ -416,7 +418,7 @@ class SearchControllerTest &lt; ActionController::TestCase
416 418 end
417 419  
418 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 423 get :events
422 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 477  
476 478 should 'show events of specific day' do
477 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 482 get :events_by_day, :year => 2009, :month => 10, :day => 28
481 483  
... ... @@ -484,8 +486,8 @@ class SearchControllerTest &lt; ActionController::TestCase
484 486  
485 487 should 'ignore filter of events if category not exists' do
486 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 492 id_of_unexistent_category = Category.last.id + 10
491 493  
... ... @@ -772,7 +774,7 @@ class SearchControllerTest &lt; ActionController::TestCase
772 774 protected
773 775  
774 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 778 ev.profile = profile
777 779 ev.save!
778 780 ev
... ...
test/unit/article_test.rb
... ... @@ -1497,6 +1497,17 @@ class ArticleTest &lt; ActiveSupport::TestCase
1497 1497 assert_includes a.body_images_paths, 'http://test.com/noosfero.png'
1498 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 1511 should 'get absolute images paths in article body' do
1501 1512 Environment.any_instance.stubs(:default_hostname).returns('noosfero.org')
1502 1513 a = build TinyMceArticle, :profile => @profile
... ... @@ -2180,4 +2191,27 @@ class ArticleTest &lt; ActiveSupport::TestCase
2180 2191 article.destroy
2181 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 2217 end
... ...
test/unit/content_viewer_helper_test.rb
... ... @@ -16,14 +16,14 @@ class ContentViewerHelperTest &lt; ActionView::TestCase
16 16 blog = fast_create(Blog, :name => 'Blog test', :profile_id => profile.id)
17 17 post = create(TextileArticle, :name => 'post test', :profile => profile, :parent => blog)
18 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 20 end
21 21  
22 22 should 'display published-at for forum posts' do
23 23 forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id)
24 24 post = TextileArticle.create!(:name => 'post test', :profile => profile, :parent => forum)
25 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 27 end
28 28  
29 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 21 should 'generate period with two dates' do
22 22 date1 = mock
23 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 25 date2 = mock
26 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 28 expects(:_).with('from %{date1} to %{date2}').returns('from %{date1} to %{date2}')
29 29 assert_equal 'from XXX to YYY', show_period(date1, date2)
30 30 end
31 31  
32 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 36 end
37 37  
38 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 41 assert_equal 'from February 1 to March 1, 2013', show_period(date1, date2)
42 42 end
43 43  
... ... @@ -49,13 +49,13 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
49 49  
50 50 should 'generate period with two equal dates' do
51 51 date1 = mock
52   - expects(:show_date).with(date1, anything).returns('XXX')
  52 + expects(:show_time).with(date1, anything).returns('XXX')
53 53 assert_equal 'XXX', show_period(date1, date1)
54 54 end
55 55  
56 56 should 'generate period with one date only' do
57 57 date1 = mock
58   - expects(:show_date).with(date1, anything).returns('XXX')
  58 + expects(:show_time).with(date1, anything).returns('XXX')
59 59 assert_equal 'XXX', show_period(date1)
60 60 end
61 61  
... ... @@ -84,7 +84,7 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
84 84 end
85 85  
86 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 88 assert_equal 'November 2008', show_month(nil, nil)
89 89 assert_equal 'November 2008', show_month('', '')
90 90 end
... ... @@ -118,16 +118,16 @@ class DatesHelperTest &lt; ActiveSupport::TestCase
118 118 end
119 119  
120 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 122 end
123 123  
124 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 126 end
127 127  
128 128 should 'translate time' do
129 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 131 end
132 132  
133 133 should 'handle nil time' do
... ...
test/unit/enterprise_homepage_test.rb
... ... @@ -26,4 +26,9 @@ class EnterpriseHomepageTest &lt; ActiveSupport::TestCase
26 26 assert_equal false, a.can_display_hits?
27 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 34 end
... ...
test/unit/event_test.rb
... ... @@ -29,15 +29,9 @@ class EventTest &lt; ActiveSupport::TestCase
29 29 assert_equal 'South Noosfero street, 88', e.address
30 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 32 should 'set start date default value as today' do
39 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 35 end
42 36  
43 37 should 'require start date' do
... ... @@ -45,38 +39,32 @@ class EventTest &lt; ActiveSupport::TestCase
45 39 e.start_date = nil
46 40 e.valid?
47 41 assert e.errors[:start_date.to_s].present?
48   - e.start_date = Date.today
  42 + e.start_date = DateTime.now
49 43 e.valid?
50 44 refute e.errors[:start_date.to_s].present?
51 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 47 should 'use its own icon' do
60 48 assert_equal 'event', Event.icon_name
61 49 end
62 50  
63 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 53 e.valid?
66 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 57 e.valid?
70 58 refute e.errors[:start_date.to_s].present?
71 59 end
72 60  
73 61 should 'find by range of dates' do
74 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 68 assert_includes found, e1
81 69 assert_includes found, e2
82 70 assert_not_includes found, e3
... ... @@ -84,32 +72,33 @@ class EventTest &lt; ActiveSupport::TestCase
84 72  
85 73 should 'filter events by range' do
86 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 77 end
90 78  
91 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 83 end
96 84  
97 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 87 end
100 88  
101 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 92 end
105 93  
106 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 97 end
110 98  
111 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 102 display = instance_eval(&event.to_html)
114 103  
115 104 assert_tag_in_string display, :content => Regexp.new("January 1, 2008")
... ... @@ -148,7 +137,7 @@ class EventTest &lt; ActiveSupport::TestCase
148 137 profile = create_user('testuser').person
149 138 event = create(Event, :profile => profile, :name => 'test',
150 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 142 assert_match '<p>first paragraph </p>', event.first_paragraph
154 143 end
... ... @@ -161,7 +150,7 @@ class EventTest &lt; ActiveSupport::TestCase
161 150  
162 151 should 'filter HTML in body' do
163 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 155 assert_tag_in_string e.body, :tag => 'p', :content => 'a paragraph (valid)'
167 156 assert_no_tag_in_string e.body, :tag => 'script'
... ... @@ -169,7 +158,7 @@ class EventTest &lt; ActiveSupport::TestCase
169 158  
170 159 should 'filter HTML in name' do
171 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 163 assert_tag_in_string e.name, :tag => 'p', :content => 'a paragraph (valid)'
175 164 assert_no_tag_in_string e.name, :tag => 'script'
... ... @@ -184,8 +173,8 @@ class EventTest &lt; ActiveSupport::TestCase
184 173  
185 174 should 'list all events' do
186 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 178 profile.events << [event1, event2]
190 179 assert_includes profile.events, event1
191 180 assert_includes profile.events, event2
... ... @@ -194,7 +183,7 @@ class EventTest &lt; ActiveSupport::TestCase
194 183 should 'list events by day' do
195 184 profile = fast_create(Profile)
196 185  
197   - today = Date.today
  186 + today = DateTime.now
198 187 yesterday_event = build(Event, :name => 'Joao Birthday', :start_date => today - 1.day)
199 188 today_event = build(Event, :name => 'Ze Birthday', :start_date => today)
200 189 tomorrow_event = build(Event, :name => 'Mane Birthday', :start_date => today + 1.day)
... ... @@ -207,7 +196,7 @@ class EventTest &lt; ActiveSupport::TestCase
207 196 should 'list events by month' do
208 197 profile = fast_create(Profile)
209 198  
210   - today = Date.new(2013, 10, 6)
  199 + today = DateTime.new(2013, 10, 6)
211 200  
212 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 219 should 'event by month ordered by start date'do
231 220 profile = fast_create(Profile)
232 221  
233   - today = Date.new(2013, 10, 6)
  222 + today = DateTime.new(2013, 10, 6)
234 223  
235 224 event_1 = Event.new(:name => 'Maria Birthday', :start_date => today + 1.day)
236 225 event_2 = Event.new(:name => 'Joana Birthday', :start_date => today - 1.day)
... ... @@ -248,7 +237,7 @@ class EventTest &lt; ActiveSupport::TestCase
248 237 should 'list events in a range' do
249 238 profile = fast_create(Profile)
250 239  
251   - today = Date.today
  240 + today = DateTime.now
252 241 event_in_range = build(Event, :name => 'Noosfero Conference', :start_date => today - 2.day, :end_date => today + 2.day)
253 242 event_in_day = build(Event, :name => 'Ze Birthday', :start_date => today)
254 243  
... ... @@ -262,7 +251,7 @@ class EventTest &lt; ActiveSupport::TestCase
262 251 should 'not list events out of range' do
263 252 profile = fast_create(Profile)
264 253  
265   - today = Date.today
  254 + today = DateTime.now
266 255 event_in_range1 = build(Event, :name => 'Foswiki Conference', :start_date => today - 2.day, :end_date => today + 2.day)
267 256 event_in_range2 = build(Event, :name => 'Debian Conference', :start_date => today - 2.day, :end_date => today + 3.day)
268 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 346 assert event.translatable?
358 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 354 end
... ...
test/unit/profile_test.rb
... ... @@ -1563,8 +1563,8 @@ class ProfileTest &lt; ActiveSupport::TestCase
1563 1563  
1564 1564 should 'list all events' do
1565 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 1568 profile.events << [event1, event2]
1569 1569 assert_includes profile.events, event1
1570 1570 assert_includes profile.events, event2
... ... @@ -1573,7 +1573,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1573 1573 should 'list events by day' do
1574 1574 profile = fast_create(Profile)
1575 1575  
1576   - today = Date.today
  1576 + today = DateTime.now
1577 1577 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day)
1578 1578 today_event = Event.new(:name => 'Ze Birthday', :start_date => today)
1579 1579 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day)
... ... @@ -1586,7 +1586,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1586 1586 should 'list events by month' do
1587 1587 profile = fast_create(Profile)
1588 1588  
1589   - today = Date.new(2014, 03, 2)
  1589 + today = DateTime.new(2014, 03, 2)
1590 1590 yesterday_event = Event.new(:name => 'Joao Birthday', :start_date => today - 1.day)
1591 1591 today_event = Event.new(:name => 'Ze Birthday', :start_date => today)
1592 1592 tomorrow_event = Event.new(:name => 'Mane Birthday', :start_date => today + 1.day)
... ... @@ -1599,7 +1599,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1599 1599 should 'list events in a range' do
1600 1600 profile = fast_create(Profile)
1601 1601  
1602   - today = Date.today
  1602 + today = DateTime.now
1603 1603 event_in_range = Event.new(:name => 'Noosfero Conference', :start_date => today - 2.day, :end_date => today + 2.day)
1604 1604 event_in_day = Event.new(:name => 'Ze Birthday', :start_date => today)
1605 1605  
... ... @@ -1613,7 +1613,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1613 1613 should 'not list events out of range' do
1614 1614 profile = fast_create(Profile)
1615 1615  
1616   - today = Date.today
  1616 + today = DateTime.now
1617 1617 event_in_range1 = Event.new(:name => 'Foswiki Conference', :start_date => today - 2.day, :end_date => today + 2.day)
1618 1618 event_in_range2 = Event.new(:name => 'Debian Conference', :start_date => today - 2.day, :end_date => today + 3.day)
1619 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 1627  
1628 1628 should 'sort events by date' do
1629 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 1633 profile.events << [event1, event2, event3]
1634 1634 assert_equal [event2, event1, event3], profile.events
1635 1635 end
... ...
test/unit/textile_article_test.rb
... ... @@ -174,6 +174,11 @@ class TextileArticleTest &lt; ActiveSupport::TestCase
174 174 assert_equal "<p>one\nparagraph</p>", build_article("one\nparagraph").to_html
175 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 182 protected
178 183  
179 184 def build_article(input = nil, options = {})
... ...
test/unit/tiny_mce_article_test.rb
... ... @@ -235,4 +235,9 @@ end
235 235 :attributes => { :colspan => 2, :rowspan => 3 }
236 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 243 end
... ...