elevation_event_calendar 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+ class <%= view_name.classify %>Controller < ApplicationController
2
+
3
+ def index
4
+ @month = params[:month].to_i
5
+ @year = params[:year].to_i
6
+
7
+ @shown_month = Date.civil(@year, @month)
8
+
9
+ @event_strips = <%= class_name.classify %>.event_strips_for_month(@shown_month)
10
+ end
11
+
12
+ end
@@ -0,0 +1,35 @@
1
+ module <%= view_name.classify %>Helper
2
+ def month_link(month_date)
3
+ link_to(I18n.localize(month_date, :format => "%B"), {:month => month_date.month, :year => month_date.year})
4
+ end
5
+
6
+ # custom options for this calendar
7
+ def event_calendar_opts
8
+ {
9
+ :year => @year,
10
+ :month => @month,
11
+ :event_strips => @event_strips,
12
+ :month_name_text => I18n.localize(@shown_month, :format => "%B %Y"),
13
+ :previous_month_text => "<< " + month_link(@shown_month.last_month),
14
+ :next_month_text => month_link(@shown_month.next_month) + " >>"<%- if options[:use_all_day] -%>,
15
+ :use_all_day => true
16
+ <%- end -%>
17
+ }
18
+ end
19
+
20
+ def event_calendar
21
+ # args is an argument hash containing :event, :day, and :options
22
+ calendar event_calendar_opts do |args|
23
+ <%- if options[:use_all_day] -%>
24
+ event, day = args[:event], args[:day]
25
+ html = %(<a href="/events/#{event.id}" title="#{h(event.name)}">)
26
+ html << display_event_time(event, day)
27
+ html << %(#{h(event.name)}</a>)
28
+ html
29
+ <%- else -%>
30
+ event = args[:event]
31
+ %(<a href="/events/#{event.id}" title="#{h(event.name)}">#{h(event.name)}</a>)
32
+ <%- end -%>
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Smart event highlighting
3
+ * Handles for when events span rows, or don't have a background color
4
+ */
5
+ Event.observe(window, "load", function() {
6
+ var highlight_color = "#2EAC6A";
7
+
8
+ // highlight events that have a background color
9
+ $$(".ec-event-bg").each(function(ele) {
10
+ ele.observe("mouseover", function(evt) {
11
+ event_id = ele.readAttribute("data-event-id");
12
+ $$(".ec-event-"+event_id).each(function(el) {
13
+ el.setStyle({ backgroundColor: highlight_color });
14
+ });
15
+ });
16
+ ele.observe("mouseout", function(evt) {
17
+ event_color = ele.readAttribute("data-color");
18
+ event_id = ele.readAttribute("data-event-id");
19
+ $$(".ec-event-"+event_id).each(function(el) {
20
+ el.setStyle({ backgroundColor: event_color });
21
+ });
22
+ });
23
+ });
24
+
25
+ // highlight events that don't have a background color
26
+ $$(".ec-event-no-bg").each(function(ele) {
27
+ ele.observe("mouseover", function(evt) {
28
+ ele.setStyle({ color: "white" });
29
+ ele.select("a").each(function(link) {
30
+ link.setStyle({ color: "white" });
31
+ });
32
+ ele.select(".ec-bullet").each(function(bullet) {
33
+ bullet.setStyle({ backgroundColor: "white" });
34
+ });
35
+ ele.setStyle({ backgroundColor: highlight_color });
36
+ });
37
+ ele.observe("mouseout", function(evt) {
38
+ event_color = ele.readAttribute("data-color");
39
+ ele.setStyle({ color: event_color });
40
+ ele.select("a").each(function(link) {
41
+ link.setStyle({ color: event_color });
42
+ });
43
+ ele.select(".ec-bullet").each(function(bullet) {
44
+ bullet.setStyle({ backgroundColor: event_color });
45
+ });
46
+ ele.setStyle({ backgroundColor: "transparent" });
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,35 @@
1
+ /*
2
+ * Smart event highlighting
3
+ * Handles when events span rows, or don't have a background color
4
+ */
5
+ $(document).ready(function() {
6
+ var highlight_color = "#2EAC6A";
7
+
8
+ // highlight events that have a background color
9
+ $(".ec-event-bg").live("mouseover", function() {
10
+ event_id = $(this).attr("data-event-id");
11
+ $(".ec-event-"+event_id).css("background-color", highlight_color);
12
+ });
13
+ $(".ec-event-bg").live("mouseout", function() {
14
+ event_id = $(this).attr("data-event-id");
15
+ event_color = $(this).attr("data-color");
16
+ $(".ec-event-"+event_id).css("background-color", event_color);
17
+ });
18
+
19
+ // highlight events that don't have a background color
20
+ $(".ec-event-no-bg").live("mouseover", function() {
21
+ ele = $(this);
22
+ ele.css("color", "white");
23
+ ele.find("a").css("color", "white");
24
+ ele.find(".ec-bullet").css("background-color", "white");
25
+ ele.css("background-color", highlight_color);
26
+ });
27
+ $(".ec-event-no-bg").live("mouseout", function() {
28
+ ele = $(this);
29
+ event_color = $(this).attr("data-color");
30
+ ele.css("color", event_color);
31
+ ele.find("a").css("color", event_color);
32
+ ele.find(".ec-bullet").css("background-color", event_color);
33
+ ele.css("background-color", "transparent");
34
+ });
35
+ });
@@ -0,0 +1,18 @@
1
+ class Create<%= class_name.classify.pluralize %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= class_name.pluralize %> do |t|
4
+ t.string :name
5
+ t.datetime :start_at
6
+ t.datetime :end_at
7
+ <%- if options[:use_all_day] -%>
8
+ t.boolean :all_day
9
+ <%- end -%>
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+
15
+ def self.down
16
+ drop_table :<%= class_name.pluralize %>
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ class <%= class_name.classify %> < ActiveRecord::Base
2
+ has_event_calendar
3
+
4
+ end
@@ -0,0 +1,233 @@
1
+ /*
2
+ Event Calendar stylesheet
3
+
4
+ Colors:
5
+ #d5d5d5 - border (gray)
6
+ #303030 - day names bg (gray)
7
+ #444 - number (gray)
8
+ #ecede2 - day header bg (light tan)
9
+ ##d7d7ba - today header bg (tan)
10
+ #ffffdd - today bg light (yellow)
11
+ #777 - other month number (gray)
12
+ #efefef - other month day header (gray)
13
+ #2eac6a - hover (green)
14
+ */
15
+
16
+ /* Outer most container */
17
+ .ec-calendar {
18
+ font-family: verdana, arial, helvetica, sans-serif;
19
+ font-size: 11px;
20
+ line-height: 14px;
21
+ margin: 0;
22
+ padding: 0;
23
+ border-bottom: 1px solid #d5d5d5;
24
+ }
25
+
26
+ /* Month name header & links */
27
+ .ec-calendar-header {
28
+ padding: 5px 0;
29
+ width: 100%;
30
+ table-layout: fixed;
31
+ }
32
+
33
+ .ec-month-name {
34
+ font-size: 16px;
35
+ font-weight: bold;
36
+ }
37
+
38
+ .ec-month-nav {
39
+
40
+ }
41
+
42
+ /* Containers */
43
+ .ec-body {
44
+ position: relative;
45
+ border-right: 1px solid #303030;
46
+ white-space: nowrap;
47
+ }
48
+
49
+ /* Day names */
50
+ .ec-day-names {
51
+ position: absolute;
52
+ top: 0;
53
+ left: 0;
54
+ width: 100%;
55
+ table-layout: fixed;
56
+ padding: 2px 0;
57
+ background: #303030;
58
+ color: white;
59
+ }
60
+
61
+ .ec-day-name {
62
+ font-weight: normal;
63
+ }
64
+
65
+ /* Rows container and Row */
66
+ .ec-rows {
67
+ position: absolute;
68
+ left: 0;
69
+ bottom: 0;
70
+ width: 100%;
71
+ background: white;
72
+ overflow: hidden;
73
+ border-right: 1px solid #d5d5d5;
74
+ }
75
+
76
+ .ec-row {
77
+ position: absolute;
78
+ left: 0;
79
+ width: 100%;
80
+ overflow: hidden;
81
+ }
82
+
83
+ /* Background */
84
+ .ec-row-bg {
85
+ position: absolute;
86
+ top: 0;
87
+ left: 0;
88
+ height: 100%;
89
+ width: 100%;
90
+ table-layout: fixed;
91
+ }
92
+
93
+ .ec-day-bg {
94
+ border-left: 1px solid #d5d5d5;
95
+ }
96
+
97
+ .ec-today-bg {
98
+ background-color: #ffffdd;
99
+ }
100
+
101
+ .ec-row-table {
102
+ position: relative;
103
+ width: 100%;
104
+ table-layout: fixed;
105
+ }
106
+
107
+ /* Day header */
108
+ .ec-day-header {
109
+ color: #444;
110
+ text-align: right;
111
+ padding: 0 5px;
112
+ line-height: 16px;
113
+ border-top: 1px solid #d5d5d5;
114
+ border-left: 1px solid #d5d5d5;
115
+ border-bottom: 1px dotted #bbbbbb;
116
+ background-color: #ecede2;
117
+ overflow: hidden;
118
+ }
119
+
120
+ a.ec-day-link {
121
+ color: #444;
122
+ }
123
+
124
+ .ec-today-header {
125
+ background-color: #d7d7ba;
126
+ }
127
+
128
+ .ec-weekend-day-header {
129
+
130
+ }
131
+
132
+ .ec-other-month-header {
133
+ background-color: #efefef;
134
+ color: #777;
135
+ }
136
+
137
+
138
+ /* Event cell and container */
139
+ .ec-event-cell {
140
+ cursor: pointer;
141
+ vertical-align: top;
142
+ padding-right: 1px;
143
+ padding-left: 2px;
144
+ }
145
+
146
+ .ec-event-cell a {
147
+ text-decoration: none;
148
+ display: block;
149
+ width: 100%;
150
+ height: 100%;
151
+ }
152
+
153
+ .ec-no-event-cell {
154
+ cursor: default;
155
+ }
156
+
157
+ .ec-event {
158
+ color: white;
159
+ padding-right: 1px;
160
+ padding-left: 11px;
161
+ -webkit-border-radius: 3px;
162
+ -khtml-border-radius: 3px;
163
+ -moz-border-radius: 3px;
164
+ overflow: hidden;
165
+ white-space: nowrap;
166
+ }
167
+
168
+ .ec-event :hover {
169
+ /* doesn't look as good as js highlighting */
170
+ /* background-color: #2eac6a; */
171
+ }
172
+
173
+ .ec-event-bg a {
174
+ color: white;
175
+ }
176
+
177
+ /* used to distinguish non-all_day events */
178
+ .ec-event-no-bg {
179
+ position: relative;
180
+ /* padding-left: 5px; */
181
+ }
182
+
183
+ .ec-event-no-bg a {
184
+ /* isn't implemented in all browsers */
185
+ color: inherit;
186
+ }
187
+
188
+ .ec-event-time {
189
+ font-size: 85%;
190
+ font-weight: bold;
191
+ padding-right: 3px;
192
+ }
193
+
194
+
195
+ /* Left and right arrows */
196
+ /* Doesn't work in IE6, use bg images instead */
197
+ .ec-left-arrow, .ec-right-arrow {
198
+ position: relative;
199
+ top: 3px;
200
+ width: 0;
201
+ height: 0;
202
+ font-size: 0;
203
+ line-height: 0;
204
+ margin-bottom: -8px;
205
+ border-top: 4px solid transparent;
206
+ border-bottom: 4px solid transparent;
207
+ }
208
+
209
+ .ec-left-arrow {
210
+ margin-left: -7px;
211
+ margin-right: auto;
212
+ border-right: 4px solid white;
213
+ }
214
+
215
+ .ec-right-arrow {
216
+ margin-left: auto;
217
+ margin-right: 3px;
218
+ border-left: 4px solid white;
219
+ }
220
+
221
+ /* remove this to not have a bullet */
222
+ /* don't look as good in ie */
223
+ .ec-bullet {
224
+ position: absolute;
225
+ top: 7px;
226
+ width: 4px;
227
+ height: 4px;
228
+ margin-left: -7px;
229
+ margin-right: auto;
230
+ -webkit-border-radius: 2px;
231
+ -khtml-border-radius: 2px;
232
+ -moz-border-radius: 2px;
233
+ }
@@ -0,0 +1,6 @@
1
+ <!-- Probably move the stylesheet to you layout. Also make sure you include the javascript. -->
2
+ <%%= stylesheet_link_tag "event_calendar" %>
3
+
4
+ <h1>Calendar</h1>
5
+
6
+ <%%= event_calendar %>
@@ -0,0 +1,172 @@
1
+ module EventCalendar
2
+
3
+ module PluginMethods
4
+ def has_event_calendar
5
+ ClassMethods.setup_event_calendar_on self
6
+ end
7
+ end
8
+
9
+ # class Methods
10
+ module ClassMethods
11
+
12
+ def self.setup_event_calendar_on(recipient)
13
+ recipient.extend ClassMethods
14
+ recipient.class_eval do
15
+ include InstanceMethods
16
+ end
17
+ end
18
+
19
+ # For the given month, find the start and end dates
20
+ # Find all the events within this range, and create event strips for them
21
+ def event_strips_for_month(shown_date, first_day_of_week=0)
22
+ strip_start, strip_end = get_start_and_end_dates(shown_date, first_day_of_week)
23
+ events = events_for_date_range(strip_start, strip_end)
24
+ event_strips = create_event_strips(strip_start, strip_end, events)
25
+ event_strips
26
+ end
27
+
28
+ # Expand start and end dates to show the previous month and next month's days,
29
+ # that overlap with the shown months display
30
+ def get_start_and_end_dates(shown_date, first_day_of_week=0)
31
+ # start with the first day of the given month
32
+ start_of_month = Date.civil(shown_date.year, shown_date.month, 1)
33
+ # the end of last month
34
+ strip_start = beginning_of_week(start_of_month, first_day_of_week)
35
+ # the beginning of next month, unless this month ended evenly on the last day of the week
36
+ if start_of_month.next_month == beginning_of_week(start_of_month.next_month, first_day_of_week)
37
+ # last day of the month is also the last day of the week
38
+ strip_end = start_of_month.next_month
39
+ else
40
+ # add the extra days from next month
41
+ strip_end = beginning_of_week(start_of_month.next_month + 7, first_day_of_week)
42
+ end
43
+ [strip_start, strip_end]
44
+ end
45
+
46
+ # Get the events overlapping the given start and end dates
47
+ def events_for_date_range(start_d, end_d)
48
+ self.find(
49
+ :all,
50
+ :conditions => [ '(? <= end_at) AND (start_at < ?)', start_d.to_time.utc, end_d.to_time.utc ],
51
+ :order => 'start_at ASC'
52
+ )
53
+ end
54
+
55
+ # Create the various strips that show evetns
56
+ def create_event_strips(strip_start, strip_end, events)
57
+ # create an inital event strip, with a nil entry for every day of the displayed days
58
+ event_strips = [[nil] * (strip_end - strip_start + 1)]
59
+
60
+ events.each do |event|
61
+ cur_date = event.start_at.to_date
62
+ end_date = event.end_at.to_date
63
+ cur_date, end_date = event.clip_range(strip_start, strip_end)
64
+ start_range = (cur_date - strip_start).to_i
65
+ end_range = (end_date - strip_start).to_i
66
+
67
+ # make sure the event is within our viewing range
68
+ if (start_range <= end_range) and (end_range >= 0)
69
+ range = start_range..end_range
70
+
71
+ open_strip = space_in_current_strips?(event_strips, range)
72
+
73
+ if open_strip.nil?
74
+ # no strips open, make a new one
75
+ new_strip = [nil] * (strip_end - strip_start + 1)
76
+ range.each {|r| new_strip[r] = event}
77
+ event_strips << new_strip
78
+ else
79
+ # found an open strip, add this event to it
80
+ range.each {|r| open_strip[r] = event}
81
+ end
82
+ end
83
+ end
84
+ event_strips
85
+ end
86
+
87
+ def space_in_current_strips?(event_strips, range)
88
+ open_strip = nil
89
+ for strip in event_strips
90
+ strip_is_open = true
91
+ range.each do |r|
92
+ # overlapping events on this strip
93
+ if !strip[r].nil?
94
+ strip_is_open = false
95
+ break
96
+ end
97
+ end
98
+
99
+ if strip_is_open
100
+ open_strip = strip
101
+ break
102
+ end
103
+ end
104
+ open_strip
105
+ end
106
+
107
+ def days_between(first, second)
108
+ if first > second
109
+ second + (7 - first)
110
+ else
111
+ second - first
112
+ end
113
+ end
114
+
115
+ def beginning_of_week(date, start = 0)
116
+ days_to_beg = days_between(start, date.wday)
117
+ date - days_to_beg
118
+ end
119
+
120
+ end
121
+
122
+ # Instance Methods
123
+ # Override in your model as needed
124
+ module InstanceMethods
125
+ def year
126
+ date.year
127
+ end
128
+
129
+ def month
130
+ date.month
131
+ end
132
+
133
+ def day
134
+ date.day
135
+ end
136
+
137
+ def all_day
138
+ self[:all_day]
139
+ end
140
+
141
+ def color
142
+ self[:color] || '#9aa4ad'
143
+ end
144
+
145
+ def days
146
+ end_at.to_date - start_at.to_date
147
+ end
148
+
149
+ # start_d - start of the month, or start of the week
150
+ # end_d - end of the month, or end of the week
151
+ def clip_range(start_d, end_d)
152
+ # make sure we are comparing date objects to date objects,
153
+ # otherwise timezones can cause problems
154
+ start_at_d = start_at.to_date
155
+ end_at_d = end_at.to_date
156
+ # Clip start date, make sure it also ends on or after the start range
157
+ if (start_at_d < start_d and end_at_d >= start_d)
158
+ clipped_start = start_d
159
+ else
160
+ clipped_start = start_at_d
161
+ end
162
+
163
+ # Clip end date
164
+ if (end_at_d > end_d)
165
+ clipped_end = end_d
166
+ else
167
+ clipped_end = end_at_d
168
+ end
169
+ [clipped_start, clipped_end]
170
+ end
171
+ end
172
+ end