elevation_event_calendar 1.0.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.
@@ -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