refinerycms-calendar 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/admin/event_categories_controller.rb +9 -0
- data/app/controllers/admin/events_controller.rb +26 -0
- data/app/controllers/event_categories_controller.rb +10 -0
- data/app/controllers/events_controller.rb +64 -0
- data/app/helpers/event_categories_helper.rb +3 -0
- data/app/helpers/events_helper.rb +38 -0
- data/app/models/event.rb +72 -0
- data/app/models/event_categorization.rb +4 -0
- data/app/models/event_category.rb +10 -0
- data/app/views/admin/event_categories/_event_categories.html.erb +1 -0
- data/app/views/admin/event_categories/_event_category.html.erb +18 -0
- data/app/views/admin/event_categories/_form.html.erb +26 -0
- data/app/views/admin/event_categories/_sortable_list.html.erb +3 -0
- data/app/views/admin/event_categories/edit.html.erb +1 -0
- data/app/views/admin/event_categories/index.html.erb +40 -0
- data/app/views/admin/event_categories/new.html.erb +1 -0
- data/app/views/admin/events/_event.html.erb +18 -0
- data/app/views/admin/events/_events.html.erb +1 -0
- data/app/views/admin/events/_form.html.erb +126 -0
- data/app/views/admin/events/_sortable_list.html.erb +20 -0
- data/app/views/admin/events/edit.html.erb +1 -0
- data/app/views/admin/events/index.html.erb +41 -0
- data/app/views/admin/events/new.html.erb +1 -0
- data/app/views/event_categories/show.html.erb +15 -0
- data/app/views/events/_event.html.erb +103 -0
- data/app/views/events/_sidebar.html.erb +38 -0
- data/app/views/events/archive.html.erb +17 -0
- data/app/views/events/index.html.erb +17 -0
- data/app/views/events/index.rss.builder +24 -0
- data/app/views/events/show.html.erb +15 -0
- data/changelog.md +22 -0
- data/config/locales/en.yml +39 -0
- data/config/locales/lolcat.yml +24 -0
- data/config/locales/nb.yml +20 -0
- data/config/locales/nl.yml +20 -0
- data/config/routes.rb +11 -0
- data/db/migrate/01_create_events.rb +33 -0
- data/db/migrate/02_create_event_categories.rb +13 -0
- data/db/migrate/03_create_event_categorizations.rb +17 -0
- data/db/seeds/events.rb +17 -0
- data/features/manage_events.feature +64 -0
- data/features/step_definitions/event_steps.rb +14 -0
- data/features/support/factories/event_categories.rb +3 -0
- data/features/support/factories/events.rb +6 -0
- data/features/support/paths.rb +17 -0
- data/lib/generators/refinerycms_events_generator.rb +6 -0
- data/lib/refinerycms-events.rb +23 -0
- data/lib/tasks/events.rake +13 -0
- data/public/stylesheets/refinerycms-events.css +73 -0
- data/readme.md +49 -0
- data/refinerycms-calendar.gemspec +17 -0
- data/spec/controllers/events_controller_spec.rb +14 -0
- data/spec/helpers/events_helper_spec.rb +16 -0
- data/spec/models/event_category_spec.rb +29 -0
- data/spec/models/event_spec.rb +82 -0
- metadata +133 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module Admin
|
2
|
+
class EventsController < Admin::BaseController
|
3
|
+
before_filter :find_categories, :except => :index
|
4
|
+
|
5
|
+
crudify :event, :xhr_paging => true
|
6
|
+
|
7
|
+
def index
|
8
|
+
search_all_events if searching?
|
9
|
+
|
10
|
+
@archived = Event.archive
|
11
|
+
@upcoming = Event.upcoming
|
12
|
+
@current = Event.current
|
13
|
+
|
14
|
+
@events = (@archived | @upcoming | @current)
|
15
|
+
|
16
|
+
render :partial => 'events' if request.xhr?
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def find_categories
|
22
|
+
@event_categories = EventCategory.all
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class EventsController < ApplicationController
|
2
|
+
|
3
|
+
before_filter :find_all_events
|
4
|
+
before_filter :find_page
|
5
|
+
before_filter :find_categories
|
6
|
+
|
7
|
+
helper [:events, :event_categories]
|
8
|
+
|
9
|
+
def index
|
10
|
+
# you can use meta fields from your model instead (e.g. browser_title)
|
11
|
+
# by swapping @page for @event in the line below:
|
12
|
+
present(@page)
|
13
|
+
end
|
14
|
+
|
15
|
+
def show
|
16
|
+
@event = Event.find(params[:id])
|
17
|
+
# you can use meta fields from your model instead (e.g. browser_title)
|
18
|
+
# by swapping @page for @event in the line below:
|
19
|
+
present(@page)
|
20
|
+
end
|
21
|
+
|
22
|
+
def archive
|
23
|
+
if params[:month].present?
|
24
|
+
date = "#{params[:month]}/#{params[:year]}"
|
25
|
+
@archive_date = Time.parse(date)
|
26
|
+
@date_title = @archive_date.strftime('%B %Y')
|
27
|
+
@events = Event.by_archive(@archive_date).paginate({
|
28
|
+
:page => params[:page],
|
29
|
+
:per_page => RefinerySetting.find_or_set(:events_per_page, 10)
|
30
|
+
})
|
31
|
+
else
|
32
|
+
date = "01/#{params[:year]}"
|
33
|
+
@archive_date = Time.parse(date)
|
34
|
+
@date_title = @archive_date.strftime('%Y')
|
35
|
+
@events = Event.by_year(@archive_date).paginate({
|
36
|
+
:page => params[:page],
|
37
|
+
:per_page => RefinerySetting.find_or_set(:events_per_page, 10)
|
38
|
+
})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def find_all_events
|
45
|
+
upcoming = Event.upcoming.not_featured
|
46
|
+
current = Event.current.not_featured
|
47
|
+
@events = (upcoming | current).sort { |a,b| a.start_at <=> b.start_at }
|
48
|
+
|
49
|
+
featured_upcoming = Event.upcoming.featured
|
50
|
+
featured_current = Event.current.featured
|
51
|
+
@featured_events = (featured_upcoming | featured_current).sort { |a,b| a.start_at <=> b.start_at }
|
52
|
+
|
53
|
+
@other_events = Event.live.limit(5)
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_page
|
57
|
+
@page = Page.find_by_link_url("/events")
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_categories
|
61
|
+
@event_categories = EventCategory.all
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module EventsHelper
|
2
|
+
def events_archive_list
|
3
|
+
events = Event.select('start_at').for_archive_list
|
4
|
+
return nil if events.blank?
|
5
|
+
html = '<ul>'
|
6
|
+
links = []
|
7
|
+
super_old_links = []
|
8
|
+
|
9
|
+
events.each do |e|
|
10
|
+
if e.start_at >= Time.now.end_of_year.advance(:years => -3)
|
11
|
+
links << e.start_at.strftime('%m/%Y')
|
12
|
+
else
|
13
|
+
super_old_links << e.start_at.strftime('01/%Y')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
links.uniq!
|
17
|
+
super_old_links.uniq!
|
18
|
+
links.each do |l|
|
19
|
+
year = l.split('/')[1]
|
20
|
+
month = l.split('/')[0]
|
21
|
+
count = Event.by_archive(Time.parse(l)).size
|
22
|
+
text = t("date.month_names")[month.to_i] + " #{year} (#{count})"
|
23
|
+
html << "<li>"
|
24
|
+
html << link_to(text, archive_events_path(:year => year, :month => month))
|
25
|
+
html << "</li>"
|
26
|
+
end
|
27
|
+
super_old_links.each do |l|
|
28
|
+
year = l.split('/')[1]
|
29
|
+
count = Event.by_year(Time.parse(l)).size
|
30
|
+
text = "#{year} (#{count})"
|
31
|
+
html << "<li>"
|
32
|
+
html << link_to(text, archive_events_path(:year => year))
|
33
|
+
html << "</li>"
|
34
|
+
end
|
35
|
+
html << '</ul>'
|
36
|
+
html.html_safe
|
37
|
+
end
|
38
|
+
end
|
data/app/models/event.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
class Event < ActiveRecord::Base
|
2
|
+
has_many :event_categorizations
|
3
|
+
has_many :categories, :through => :event_categorizations, :source => :event_category
|
4
|
+
|
5
|
+
default_scope order('start_at ASC')
|
6
|
+
|
7
|
+
scope :current, where(['start_at < ? and end_at >= ?', Time.now, Time.now])
|
8
|
+
scope :upcoming, where(['start_at >= ?', Time.now])
|
9
|
+
scope :featured, where(['featured IS NOT NULL and featured = ?', true])
|
10
|
+
scope :not_featured, where(['featured IS NULL or featured = ?', false])
|
11
|
+
scope :live, where(['end_at > ?', Time.now])
|
12
|
+
scope :archive, where(['end_at < ?', Time.now])
|
13
|
+
scope :for_archive_list, where(['end_at < ?', Time.now.beginning_of_month])
|
14
|
+
|
15
|
+
scope :by_archive, lambda { |archive_date|
|
16
|
+
where(['start_at between ? and ?', archive_date.beginning_of_month, archive_date.end_of_month])
|
17
|
+
}
|
18
|
+
|
19
|
+
scope :by_year, lambda { |archive_year|
|
20
|
+
where(['start_at between ? and ?', archive_year.beginning_of_year, archive_year.end_of_year])
|
21
|
+
}
|
22
|
+
|
23
|
+
acts_as_indexed :fields => [:title, :venue_name, :venue_address, :ticket_link, :description]
|
24
|
+
|
25
|
+
validates :title, :presence => true, :uniqueness => true
|
26
|
+
validates :ticket_price, :numericality => true, :allow_blank => true
|
27
|
+
validates :ticket_link, :format => /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix, :allow_blank => true
|
28
|
+
validate :ends_after_start
|
29
|
+
|
30
|
+
has_friendly_id :title, :use_slug => true
|
31
|
+
|
32
|
+
belongs_to :image
|
33
|
+
|
34
|
+
def current?
|
35
|
+
end_at >= Time.now
|
36
|
+
end
|
37
|
+
|
38
|
+
def upcoming?
|
39
|
+
start_at >= Time.now
|
40
|
+
end
|
41
|
+
|
42
|
+
def archived?
|
43
|
+
end_at < Time.now
|
44
|
+
end
|
45
|
+
|
46
|
+
def featured?
|
47
|
+
featured == true
|
48
|
+
end
|
49
|
+
|
50
|
+
def status
|
51
|
+
"current" if current?
|
52
|
+
"coming up" if upcoming?
|
53
|
+
"archived" if archived?
|
54
|
+
end
|
55
|
+
|
56
|
+
def next
|
57
|
+
Event.where(['end_at >= ? AND start_at > ?', Time.now, self.start_at]).first
|
58
|
+
end
|
59
|
+
|
60
|
+
def prev
|
61
|
+
Event.where(['end_at >= ? AND start_at < ?', Time.now, self.start_at]).reverse.first
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def ends_after_start
|
67
|
+
start_at ||= Time.now
|
68
|
+
end_at ||= start_at.advance(:hours => 1)
|
69
|
+
errors.add(:base, "End at date must be after the start at date") if end_at < start_at
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render :partial => "sortable_list" %>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<li class='clearfix record <%= cycle("on", "on-hover") %>' id="<%= dom_id(event_category) -%>">
|
2
|
+
<span class='title'>
|
3
|
+
<%= event_category.name %>
|
4
|
+
<span class="preview"></span>
|
5
|
+
</span>
|
6
|
+
<span class='actions'>
|
7
|
+
<%= link_to refinery_icon_tag("application_go.png"), category_events_url(event_category),
|
8
|
+
:title => t('.view_live_html'),
|
9
|
+
:target => "_blank" %>
|
10
|
+
<%= link_to refinery_icon_tag("application_edit.png"), edit_admin_event_category_path(event_category),
|
11
|
+
:title => t('.edit') %>
|
12
|
+
<%= link_to refinery_icon_tag("delete.png"), admin_event_category_path(event_category),
|
13
|
+
:class => "cancel confirm-delete",
|
14
|
+
:title => t('.delete'),
|
15
|
+
:confirm => t('message', :scope => 'shared.admin.delete', :title => event_category.name),
|
16
|
+
:method => :delete %>
|
17
|
+
</span>
|
18
|
+
</li>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%= form_for [:admin, @event_category] do |f| -%>
|
2
|
+
<%= render :partial => "/shared/admin/error_messages", :locals => {
|
3
|
+
:object => @event_category,
|
4
|
+
:include_object_name => true
|
5
|
+
} %>
|
6
|
+
|
7
|
+
<div class='field'>
|
8
|
+
<%= f.label :name -%>
|
9
|
+
<%= f.text_field :name, :class => 'larger widest' -%>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<%= render :partial => "/shared/admin/form_actions",
|
13
|
+
:locals => {
|
14
|
+
:f => f,
|
15
|
+
:continue_editing => false,
|
16
|
+
:delete_title => t('delete', :scope => 'admin.event_categories.event_category'),
|
17
|
+
:delete_confirmation => t('message', :scope => 'shared.admin.delete', :title => @event_category.name)
|
18
|
+
} %>
|
19
|
+
<% end -%>
|
20
|
+
<% content_for :javascripts do %>
|
21
|
+
<script>
|
22
|
+
$(document).ready(function(){
|
23
|
+
page_options.init(false, '', '');
|
24
|
+
});
|
25
|
+
</script>
|
26
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render :partial => "form" %>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<div id='records'>
|
2
|
+
<% if searching? %>
|
3
|
+
<h2><%= t('results_for', :scope => 'shared.admin.search', :query => params[:search]) %></h2>
|
4
|
+
<% end %>
|
5
|
+
<% if @event_categories.any? %>
|
6
|
+
<div class='pagination_container'>
|
7
|
+
<%= render :partial => 'event_categories' %>
|
8
|
+
</div>
|
9
|
+
<% else %>
|
10
|
+
<p>
|
11
|
+
<% unless searching? %>
|
12
|
+
<strong>
|
13
|
+
<%= t('.no_items_yet') %>
|
14
|
+
</strong>
|
15
|
+
<% else %>
|
16
|
+
<%= t('no_results', :scope => 'shared.admin.search') %>
|
17
|
+
<% end %>
|
18
|
+
</p>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
21
|
+
<div id='actions'>
|
22
|
+
<ul>
|
23
|
+
<% if Admin::EventCategoriesController.searchable? %>
|
24
|
+
<li>
|
25
|
+
<%= render :partial => "/shared/admin/search",
|
26
|
+
:locals => {
|
27
|
+
:url => admin_event_categories_url
|
28
|
+
} %>
|
29
|
+
</li>
|
30
|
+
<% end %>
|
31
|
+
<li>
|
32
|
+
<%= link_to t('.create_new'), new_admin_event_category_url,
|
33
|
+
:class => "add_icon" %>
|
34
|
+
</li>
|
35
|
+
<li>
|
36
|
+
<%= link_to "Manage Events", admin_events_url,
|
37
|
+
:class => "edit_icon" %>
|
38
|
+
</li>
|
39
|
+
</ul>
|
40
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render :partial => "form" %>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<li class='clearfix record <%= cycle("on", "on-hover") %>' id="<%= dom_id(event) -%>">
|
2
|
+
<span class='title'>
|
3
|
+
<%= event.title %>
|
4
|
+
<span class="preview">(<%= event.start_at.strftime('%b %d, %Y') %>) <%= '***Featured***' if event.featured? %></span>
|
5
|
+
</span>
|
6
|
+
<span class='actions'>
|
7
|
+
<%= link_to refinery_icon_tag("application_go.png"), event_url(event),
|
8
|
+
:title => t('.view_live_html'),
|
9
|
+
:target => "_blank" %>
|
10
|
+
<%= link_to refinery_icon_tag("application_edit.png"), edit_admin_event_path(event),
|
11
|
+
:title => t('.edit') %>
|
12
|
+
<%= link_to refinery_icon_tag("delete.png"), admin_event_path(event),
|
13
|
+
:class => "cancel confirm-delete",
|
14
|
+
:title => t('.delete'),
|
15
|
+
:confirm => t('message', :scope => 'shared.admin.delete', :title => event.title),
|
16
|
+
:method => :delete %>
|
17
|
+
</span>
|
18
|
+
</li>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render :partial => "sortable_list" %>
|
@@ -0,0 +1,126 @@
|
|
1
|
+
<%= form_for [:admin, @event] do |f| -%>
|
2
|
+
<%= render :partial => "/shared/admin/error_messages", :locals => {
|
3
|
+
:object => @event,
|
4
|
+
:include_object_name => true
|
5
|
+
} %>
|
6
|
+
|
7
|
+
<div class='field'>
|
8
|
+
<%= f.label :title -%>
|
9
|
+
<%= f.text_field :title, :class => 'larger widest' -%>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<% if @event_categories.any? -%>
|
13
|
+
<div class='field'>
|
14
|
+
<h2>Categories</h2>
|
15
|
+
<ul class="check_box_list">
|
16
|
+
<% @event_categories.each do |category| -%>
|
17
|
+
<li>
|
18
|
+
<%= check_box_tag 'event[category_ids][]', category.id,
|
19
|
+
@event.categories.include?(category),
|
20
|
+
:id => (id="event_category_ids_#{category.id}") %>
|
21
|
+
<%= label_tag 'event[category_ids][]', category.name,
|
22
|
+
:class => 'stripped',
|
23
|
+
:for => id %>
|
24
|
+
</li>
|
25
|
+
<% end -%>
|
26
|
+
</ul>
|
27
|
+
</div>
|
28
|
+
<% end -%>
|
29
|
+
|
30
|
+
<div class='field'>
|
31
|
+
<%= f.label :start_at -%>
|
32
|
+
<%= f.datetime_select :start_at, :default => Time.now.change(:hour => 12, :minute => 0) -%>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div class='field'>
|
36
|
+
<%= f.label :end_at -%>
|
37
|
+
<%= f.datetime_select :end_at, :default => Time.now.change(:hour => 13, :minute => 0) -%>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div class='field'>
|
41
|
+
<div id='page-tabs' class='clearfix ui-tabs ui-widget ui-widget-content ui-corner-all'>
|
42
|
+
<ul id='page_parts'>
|
43
|
+
<% [:description].each_with_index do |part, part_index| %>
|
44
|
+
<li class='ui-state-default<%= ' ui-state-active' if part_index == 0 %>'>
|
45
|
+
<%= link_to part.to_s.titleize, "##{part}" %>
|
46
|
+
</li>
|
47
|
+
<% end %>
|
48
|
+
</ul>
|
49
|
+
|
50
|
+
<div id='page_part_editors'>
|
51
|
+
<% [:description].each do |part| %>
|
52
|
+
<div class='page_part' id='<%= part %>'>
|
53
|
+
<%= f.text_area part, :rows => 20, :class => 'wymeditor widest' -%>
|
54
|
+
</div>
|
55
|
+
<% end %>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
<div class='field'>
|
61
|
+
<%= f.label :image -%>
|
62
|
+
<%= render :partial => "/shared/admin/image_picker", :locals => {
|
63
|
+
:f => f,
|
64
|
+
:field => :image_id,
|
65
|
+
:image => @event.image,
|
66
|
+
:toggle_image_display => false
|
67
|
+
} %>
|
68
|
+
</div>
|
69
|
+
|
70
|
+
<div class='field'>
|
71
|
+
<%= f.label :venue_name -%>
|
72
|
+
<%= f.text_field :venue_name -%>
|
73
|
+
</div>
|
74
|
+
|
75
|
+
<div class='field'>
|
76
|
+
<%= f.label :venue_address -%>
|
77
|
+
<%= f.text_field :venue_address, :class => 'larger wide' -%>
|
78
|
+
</div>
|
79
|
+
|
80
|
+
<div class='field'>
|
81
|
+
<%= f.label :ticket_price -%>
|
82
|
+
$<%= f.text_field :ticket_price, :size => 3 -%>
|
83
|
+
</div>
|
84
|
+
|
85
|
+
<div class='field'>
|
86
|
+
<%= f.label :ticket_link -%>
|
87
|
+
<%= f.text_field :ticket_link, :class => 'larger wide' -%>
|
88
|
+
</div>
|
89
|
+
|
90
|
+
<div class='field'>
|
91
|
+
<p><%= f.check_box :featured -%> <%= f.label :featured, "Featured event", :class => 'stripped' -%></p>
|
92
|
+
</div>
|
93
|
+
|
94
|
+
<%= render :partial => "/shared/admin/form_actions",
|
95
|
+
:locals => {
|
96
|
+
:f => f,
|
97
|
+
:continue_editing => false,
|
98
|
+
:delete_title => t('delete', :scope => 'admin.events.event'),
|
99
|
+
:delete_confirmation => t('message', :scope => 'shared.admin.delete', :title => @event.title)
|
100
|
+
} %>
|
101
|
+
<% end -%>
|
102
|
+
<% content_for :javascripts do %>
|
103
|
+
<script>
|
104
|
+
$(document).ready(function(){
|
105
|
+
page_options.init(false, '', '');
|
106
|
+
});
|
107
|
+
</script>
|
108
|
+
<% end %>
|
109
|
+
|
110
|
+
<% content_for :stylesheets do -%>
|
111
|
+
<style>
|
112
|
+
ul.check_box_list{
|
113
|
+
list-style:none;
|
114
|
+
margin:10px 0;
|
115
|
+
padding:5px;
|
116
|
+
border:1px solid #333;
|
117
|
+
overflow:auto;
|
118
|
+
height:200px;
|
119
|
+
width:300px;
|
120
|
+
}
|
121
|
+
ul.check_box_list li{
|
122
|
+
list-style:none;
|
123
|
+
margin:5px 0;
|
124
|
+
}
|
125
|
+
</style>
|
126
|
+
<% end -%>
|