refinerycms-calendar 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 -%>
|