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,360 @@
1
+ module EventCalendar
2
+ module CalendarHelper
3
+
4
+ # Returns an HTML calendar which can show multiple, overlapping events across calendar days and rows.
5
+ # Customize using CSS, the below options, and by passing in a code block.
6
+ #
7
+ # The following are optional, available for customizing the default behaviour:
8
+ # :month => Time.now.month # The month to show the calendar for. Defaults to current month.
9
+ # :year => Time.now.year # The year to show the calendar for. Defaults to current year.
10
+ # :abbrev => true # Abbreviate day names. Reads from the abbr_day_names key in the localization file.
11
+ # :first_day_of_week => 0 # Renders calendar starting on Sunday. Use 1 for Monday, and so on.
12
+ # :show_today => true # Highlights today on the calendar using CSS class.
13
+ # :month_name_text => nil # Displayed center in header row.
14
+ # Defaults to current month name from Date::MONTHNAMES hash.
15
+ # :previous_month_text => nil # Displayed left of the month name if set
16
+ # :next_month_text => nil # Displayed right of the month name if set
17
+ # :event_strips => [] # An array of arrays, encapsulating the event rows on the calendar
18
+ #
19
+ # :width => nil # Width of the calendar, if none is set then it will stretch the container's width
20
+ # :height => 500 # Approx minimum total height of the calendar (excluding the header).
21
+ # Height could get added if a day has too many event's to fit.
22
+ # :day_names_height => 18 # Height of the day names table (included in the above 'height' option)
23
+ # :day_nums_height => 18 # Height of the day numbers tables (included in the 'height' option)
24
+ # :event_height => 18 # Height of an individual event row
25
+ # :event_margin => 1 # Spacing of the event rows
26
+ # :event_padding_top => 1 # Padding on the top of the event rows (increase to move text down)
27
+ #
28
+ # :use_all_day => false # If set to true, will check for an 'all_day' boolean field when displaying an event.
29
+ # If it is an all day event, or the event is multiple days, then it will display as usual.
30
+ # Otherwise it will display without a background color bar.
31
+ # :use_javascript => true # Outputs HTML with inline javascript so events spanning multiple days will be highlighted.
32
+ # If this option is false, cleaner HTML will be output, but events spanning multiple days will
33
+ # not be highlighted correctly on hover, so it is only really useful if you know your calendar
34
+ # will only have single-day events. Defaults to true.
35
+ # :link_to_day_action => false # If controller action is passed,
36
+ # the day number will be a link. Override the day_link method for greater customization.
37
+ #
38
+ # For more customization, you can pass a code block to this method
39
+ # The varibles you have to work with in this block are passed in an agruments hash:
40
+ # :event => The event to be displayed.
41
+ # :day => The day the event is displayed on. Usually the first day of the event, or the first day of the week,
42
+ # if the event spans a calendar row.
43
+ # :options => All the calendar options in use. (User defined and defaults merged.)
44
+ #
45
+ # For example usage, see README.
46
+ #
47
+ def calendar(options = {}, &block)
48
+ block ||= Proc.new {|d| nil}
49
+
50
+ defaults = {
51
+ :year => Time.now.year,
52
+ :month => Time.now.month,
53
+ :abbrev => true,
54
+ :first_day_of_week => 0,
55
+ :show_today => true,
56
+ :month_name_text => Time.now.strftime("%B %Y"),
57
+ :previous_month_text => nil,
58
+ :next_month_text => nil,
59
+ :event_strips => [],
60
+
61
+ # it would be nice to have these in the CSS file
62
+ # but they are needed to perform height calculations
63
+ :width => nil,
64
+ :height => 500,
65
+ :day_names_height => 18,
66
+ :day_nums_height => 18,
67
+ :event_height => 18,
68
+ :event_margin => 1,
69
+ :event_padding_top => 2,
70
+
71
+ :use_all_day => false,
72
+ :use_javascript => true,
73
+ :link_to_day_action => false
74
+ }
75
+ options = defaults.merge options
76
+
77
+ # default month name for the given number
78
+ options[:month_name_text] ||= I18n.translate(:'date.month_names')[options[:month]]
79
+
80
+ # make the height calculations
81
+ # tricky since multiple events in a day could force an increase in the set height
82
+ height = options[:day_names_height]
83
+ row_heights = cal_row_heights(options)
84
+ row_heights.each do |row_height|
85
+ height += row_height
86
+ end
87
+
88
+ # the first and last days of this calendar month
89
+ first = Date.civil(options[:year], options[:month], 1)
90
+ last = Date.civil(options[:year], options[:month], -1)
91
+
92
+ # create the day names array [Sunday, Monday, etc...]
93
+ day_names = []
94
+ if options[:abbrev]
95
+ day_names.concat(I18n.translate(:'date.abbr_day_names'))
96
+ else
97
+ day_names.concat(I18n.translate(:'date.day_names'))
98
+ end
99
+ options[:first_day_of_week].times do
100
+ day_names.push(day_names.shift)
101
+ end
102
+
103
+ # Build the HTML string
104
+ cal = ""
105
+
106
+ # outer calendar container
107
+ cal << %(<div class="ec-calendar")
108
+ cal << %(style="width: #{options[:width]}px;") if options[:width]
109
+ cal << %(>)
110
+
111
+ # table header, including the monthname and links to prev & next month
112
+ cal << %(<table class="ec-calendar-header" cellpadding="0" cellspacing="0">)
113
+ cal << %(<thead><tr>)
114
+ if options[:previous_month_text] or options[:next_month_text]
115
+ cal << %(<th colspan="2" class="ec-month-nav">#{options[:previous_month_text]}</th>)
116
+ colspan = 3
117
+ else
118
+ colspan = 7
119
+ end
120
+ cal << %(<th colspan="#{colspan}" class="ec-month-name">#{options[:month_name_text]}</th>)
121
+ if options[:next_month_text]
122
+ cal << %(<th colspan="2" class="ec-month-nav">#{options[:next_month_text]}</th>)
123
+ end
124
+ cal << %(</tr></thead></table>)
125
+
126
+ # body container (holds day names and the calendar rows)
127
+ cal << %(<div class="ec-body" style="height: #{height}px;">)
128
+
129
+ # day names
130
+ cal << %(<table class="ec-day-names" style="height: #{options[:day_names_height]}px;" cellpadding="0" cellspacing="0">)
131
+ cal << %(<tbody><tr>)
132
+ day_names.each do |day_name|
133
+ cal << %(<th class="ec-day-name" title="#{day_name}">#{day_name}</th>)
134
+ end
135
+ cal << %(</tr></tbody></table>)
136
+
137
+ # container for all the calendar rows
138
+ cal << %(<div class="ec-rows" style="top: #{options[:day_names_height]}px; )
139
+ cal << %(height: #{height - options[:day_names_height]}px;">)
140
+
141
+ # initialize loop variables
142
+ first_day_of_week = beginning_of_week(first, options[:first_day_of_week])
143
+ last_day_of_week = end_of_week(first, options[:first_day_of_week])
144
+ last_day_of_cal = end_of_week(last, options[:first_day_of_week])
145
+ row_num = 0
146
+ top = 0
147
+
148
+ # go through a week at a time, until we reach the end of the month
149
+ while(last_day_of_week <= last_day_of_cal)
150
+ cal << %(<div class="ec-row" style="top: #{top}px; height: #{row_heights[row_num]}px;">)
151
+ top += row_heights[row_num]
152
+
153
+ # this weeks background table
154
+ cal << %(<table class="ec-row-bg" cellpadding="0" cellspacing="0">)
155
+ cal << %(<tbody><tr>)
156
+ first_day_of_week.upto(first_day_of_week+6) do |day|
157
+ today_class = (day == Date.today) ? "ec-today-bg" : ""
158
+ cal << %(<td class="ec-day-bg #{today_class}">&nbsp;</td>)
159
+ end
160
+ cal << %(</tr></tbody></table>)
161
+
162
+ # calendar row
163
+ cal << %(<table class="ec-row-table" cellpadding="0" cellspacing="0">)
164
+ cal << %(<tbody>)
165
+
166
+ # day numbers row
167
+ cal << %(<tr>)
168
+ first_day_of_week.upto(last_day_of_week) do |day|
169
+ cal << %(<td class="ec-day-header )
170
+ cal << %(ec-today-header ) if options[:show_today] and (day == Date.today)
171
+ cal << %(ec-other-month-header ) if (day < first) || (day > last)
172
+ cal << %(ec-weekend-day-header) if weekend?(day)
173
+ cal << %(" style="height: #{options[:day_nums_height]}px;">)
174
+ if options[:link_to_day_action]
175
+ cal << day_link(day.day, day, options[:link_to_day_action])
176
+ else
177
+ cal << %(#{day.day})
178
+ end
179
+ cal << %(</td>)
180
+ end
181
+ cal << %(</tr>)
182
+
183
+ # event rows for this day
184
+ # for each event strip, create a new table row
185
+ options[:event_strips].each do |strip|
186
+ cal << %(<tr>)
187
+ # go through through the strip, for the entries that correspond to the days of this week
188
+ strip[row_num*7, 7].each_with_index do |event, index|
189
+ day = first_day_of_week + index
190
+
191
+ if event
192
+ # get the dates of this event that fit into this week
193
+ dates = event.clip_range(first_day_of_week, last_day_of_week)
194
+ # if the event (after it has been clipped) starts on this date,
195
+ # then create a new cell that spans the number of days
196
+ if dates[0] == day.to_date
197
+ # check if we should display the bg color or not
198
+ no_bg = no_event_bg?(event, options)
199
+
200
+ cal << %(<td class="ec-event-cell" colspan="#{(dates[1]-dates[0]).to_i + 1}" )
201
+ cal << %(style="padding-top: #{options[:event_margin]}px;">)
202
+ cal << %(<div class="ec-event ec-event-#{event.id} )
203
+ if no_bg
204
+ cal << %(ec-event-no-bg" )
205
+ cal << %(style="color: #{event.color}; )
206
+ else
207
+ cal << %(ec-event-bg" )
208
+ cal << %(style="background-color: #{event.color}; )
209
+ end
210
+ cal << %(padding-top: #{options[:event_padding_top]}px; )
211
+ cal << %(height: #{options[:event_height] - options[:event_padding_top]}px;" )
212
+ if options[:use_javascript]
213
+ # custom attributes needed for javascript event highlighting
214
+ cal << %(data-event-id="#{event.id}" data-color="#{event.color}" )
215
+ end
216
+ cal << %(>)
217
+
218
+ # add a left arrow if event is clipped at the beginning
219
+ if event.start_at.to_date < dates[0]
220
+ cal << %(<div class="ec-left-arrow"></div>)
221
+ end
222
+ # add a right arrow if event is clipped at the end
223
+ if event.end_at.to_date > dates[1]
224
+ cal << %(<div class="ec-right-arrow"></div>)
225
+ end
226
+
227
+ if no_bg
228
+ cal << %(<div class="ec-bullet" style="background-color: #{event.color};"></div>)
229
+ # make sure anchor text is the event color
230
+ # here b/c CSS 'inherit' color doesn't work in all browsers
231
+ cal << %(<style type="text/css">.ec-event-#{event.id} a { color: #{event.color}; }</style>)
232
+ end
233
+
234
+ if block_given?
235
+ # add the additional html that was passed as a block to this helper
236
+ cal << block.call({:event => event, :day => day.to_date, :options => options})
237
+ else
238
+ # default content in case nothing is passed in
239
+ cal << %(<a href="/events/#{event.id}" title="#{h(event.name)}">#{h(event.name)}</a>)
240
+ end
241
+
242
+ cal << %(</div></td>)
243
+ end
244
+
245
+ else
246
+ # there wasn't an event, so create an empty cell and container
247
+ cal << %(<td class="ec-event-cell ec-no-event-cell" )
248
+ cal << %(style="padding-top: #{options[:event_margin]}px;">)
249
+ cal << %(<div class="ec-event" )
250
+ cal << %(style="padding-top: #{options[:event_padding_top]}px; )
251
+ cal << %(height: #{options[:event_height] - options[:event_padding_top]}px;" )
252
+ cal << %(>)
253
+ cal << %(&nbsp;</div></td>)
254
+ end
255
+ end
256
+ cal << %(</tr>)
257
+ end
258
+
259
+ cal << %(</tbody></table>)
260
+ cal << %(</div>)
261
+
262
+ # increment the calendar row we are on, and the week
263
+ row_num += 1
264
+ first_day_of_week += 7
265
+ last_day_of_week += 7
266
+ end
267
+
268
+ cal << %(</div>)
269
+ cal << %(</div>)
270
+ cal << %(</div>)
271
+ end
272
+
273
+ # override this in your own helper for greater control
274
+ def day_link(text, date, day_action)
275
+ link_to(text, params.merge(:action => day_action, :year => date.year, :month => date.month, :day => date.day), :class => 'ec-day-link')
276
+ end
277
+
278
+ # check if we should display without a background color
279
+ def no_event_bg?(event, options)
280
+ options[:use_all_day] && !event.all_day && event.days == 0
281
+ end
282
+
283
+ # default html for displaying an event's time
284
+ # to customize: override, or do something similar, in your helper
285
+ def display_event_time(event, day)
286
+ time = event.start_at
287
+ if !event.all_day and time.to_date == day
288
+ # try to make it display as short as possible
289
+ fmt = (time.min == 0) ? "%l" : "%l:%M"
290
+ t = time.strftime(fmt)
291
+ am_pm = time.strftime("%p") == "PM" ? "p" : ""
292
+ t += am_pm
293
+ %(<span class="ec-event-time">#{t}</span>)
294
+ else
295
+ ""
296
+ end
297
+ end
298
+
299
+ private
300
+
301
+ # calculate the height of each row
302
+ # by default, it will be the height option minus the day names height,
303
+ # divided by the total number of calendar rows
304
+ # this gets tricky, however, if there are too many event rows to fit into the row's height
305
+ # then we need to add additional height
306
+ def cal_row_heights(options)
307
+ # number of rows is the number of days in the event strips divided by 7
308
+ num_cal_rows = options[:event_strips].first.size / 7
309
+ # the row will be at least this big
310
+ min_height = (options[:height] - options[:day_names_height]) / num_cal_rows
311
+ row_heights = []
312
+ num_event_rows = 0
313
+ # for every day in the event strip...
314
+ 1.upto(options[:event_strips].first.size+1) do |index|
315
+ num_events = 0
316
+ # get the largest event strip that has an event on this day
317
+ options[:event_strips].each_with_index do |strip, strip_num|
318
+ num_events = strip_num + 1 unless strip[index-1].blank?
319
+ end
320
+ # get the most event rows for this week
321
+ num_event_rows = [num_event_rows, num_events].max
322
+ # if we reached the end of the week, calculate this row's height
323
+ if index % 7 == 0
324
+ total_event_height = options[:event_height] + options[:event_margin]
325
+ calc_row_height = (num_event_rows * total_event_height) + options[:day_nums_height] + options[:event_margin]
326
+ row_height = [min_height, calc_row_height].max
327
+ row_heights << row_height
328
+ num_event_rows = 0
329
+ end
330
+ end
331
+ row_heights
332
+ end
333
+
334
+ #
335
+ # helper methods for working with a calendar week
336
+ #
337
+
338
+ def days_between(first, second)
339
+ if first > second
340
+ second + (7 - first)
341
+ else
342
+ second - first
343
+ end
344
+ end
345
+
346
+ def beginning_of_week(date, start = 0)
347
+ days_to_beg = days_between(start, date.wday)
348
+ date - days_to_beg
349
+ end
350
+
351
+ def end_of_week(date, start = 0)
352
+ beg = beginning_of_week(date, start)
353
+ beg + 6
354
+ end
355
+
356
+ def weekend?(date)
357
+ [0, 6].include?(date.wday)
358
+ end
359
+ end
360
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ ActiveRecord::Base.extend EventCalendar::PluginMethods
2
+ ActionView::Base.send :include, EventCalendar::CalendarHelper
data/rails/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :event_calendar do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class EventCalendarTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elevation_event_calendar
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - elevation
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-05-08 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Easily show multiple, overlapping events across calendar days and rows.
17
+ email: info@semanticgap.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - ./CHANGELOG.rdoc
26
+ - ./generators/event_calendar/event_calendar_generator.rb
27
+ - ./generators/event_calendar/lib/insert_routes.rb
28
+ - ./generators/event_calendar/templates/controller.rb.erb
29
+ - ./generators/event_calendar/templates/helper.rb.erb
30
+ - ./generators/event_calendar/templates/javascript.js
31
+ - ./generators/event_calendar/templates/jq_javascript.js
32
+ - ./generators/event_calendar/templates/migration.rb.erb
33
+ - ./generators/event_calendar/templates/model.rb.erb
34
+ - ./generators/event_calendar/templates/stylesheet.css
35
+ - ./generators/event_calendar/templates/view.html.erb
36
+ - ./generators/event_calendar/USAGE
37
+ - ./rails/init.rb
38
+ - ./rails/install.rb
39
+ - ./lib/event_calendar/calendar_helper.rb
40
+ - ./lib/event_calendar.rb
41
+ - ./MIT-LICENSE
42
+ - ./Rakefile
43
+ - ./README.rdoc
44
+ - ./tasks/event_calendar_tasks.rake
45
+ - ./test/event_calendar_test.rb
46
+ - ./test/test_helper.rb
47
+ - ./rails/uninstall.rb
48
+ has_rdoc: true
49
+ homepage: http://github.com/semanticgap/event_calendar
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.3.5
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Calendar helper for Rails
76
+ test_files: []
77
+