event_calendar 0.0.0 → 0.0.1

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/README.rdoc CHANGED
@@ -1,17 +1,43 @@
1
1
  = event_calendar
2
2
 
3
- Generates HTML event calendars with ruby
3
+ Generates HTML event calendars
4
4
 
5
- INCOMPLETE
6
5
 
7
6
  == Installation
8
7
 
9
- gem install event_calendar --source http://gemcutter.org
8
+ gem install event_calendar
9
+
10
10
 
11
11
  == Usage
12
12
 
13
- @calendar = Calendar.new(2009, 10, :events => Event.all)
14
- puts @calendar.to_html
13
+ === Basic
14
+
15
+ @event_calendar = EventCalendar.new(2009, 10, :events => Event.all)
16
+ puts @event_calendar.to_html
17
+
18
+ === Options
19
+
20
+ The <tt>EventCalendar.new</tt> method accepts a hash or block of options, for example:
21
+
22
+ @event_calendar = EventCalendar.new(2009, 10, :id => 'calendar', :events => Event.all)
23
+
24
+ @event_calendar = EventCalendar.new(2009, 10) do |c|
25
+ c.id = 'calendar'
26
+ c.events = Event.all
27
+ end
28
+
29
+ See the documentation for the <tt>EventCalendar</tt> class at http://rdoc.info/projects/shuber/event_calendar for a list of available options.
30
+
31
+ === Assets
32
+
33
+ rake event_calendar:generate:css # Generates css for the event calendar
34
+ rake event_calendar:generate:js # Generates js for the event calendar
35
+ rake event_calendar:generate:sandbox # Creates a sandbox in the current working directory for testing
36
+
37
+ ==== Note
38
+
39
+ The default css was built on YUI (See http://developer.yahoo.com/yui) and javascript on Prototype (See http://www.prototypejs.org).
40
+
15
41
 
16
42
  == Note on Patches/Pull Requests
17
43
 
@@ -24,6 +50,14 @@ INCOMPLETE
24
50
  bump version in a commit by itself I can ignore when I pull)
25
51
  * Send me a pull request. Bonus points for topic branches.
26
52
 
53
+
54
+ == TODO
55
+
56
+ * Break Markaby template down into sections so that it's easier to overwrite certain parts
57
+ * Dynamic height calculations for calendar days in JavaScript
58
+ * jQuery support
59
+
60
+
27
61
  == Copyright
28
62
 
29
63
  Copyright (c) 2009 Sean Huber. See MIT-LICENSE for details.
data/Rakefile CHANGED
@@ -1,26 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
3
 
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = 'event_calendar'
8
- gem.summary = 'Generates HTML event calendars'
9
- gem.description = 'Generates HTML event calendars'
10
- gem.email = 'shuber@huberry.com'
11
- gem.homepage = 'http://github.com/shuber/event_calendar'
12
- gem.authors = ['Sean Huber']
13
- gem.add_dependency 'activesupport'
14
- gem.add_dependency 'markaby'
15
- gem.add_dependency 'haml'
16
- gem.add_development_dependency 'shoulda'
17
- gem.add_development_dependency 'timecop'
18
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
- end
20
- rescue LoadError
21
- puts 'Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler'
22
- end
23
-
24
4
  require 'rake/testtask'
25
5
  Rake::TestTask.new(:test) do |test|
26
6
  test.libs << 'lib' << 'test'
@@ -41,20 +21,12 @@ rescue LoadError
41
21
  end
42
22
  end
43
23
 
44
- task :test => :check_dependencies
45
-
46
24
  task :default => :test
47
25
 
48
26
  require 'rake/rdoctask'
49
27
  Rake::RDocTask.new do |rdoc|
50
- if File.exist?('VERSION')
51
- version = File.read('VERSION')
52
- else
53
- version = ""
54
- end
55
-
56
28
  rdoc.rdoc_dir = 'rdoc'
57
- rdoc.title = "event_calendar #{version}"
29
+ rdoc.title = "event_calendar"
58
30
  rdoc.rdoc_files.include('README*')
59
31
  rdoc.rdoc_files.include('lib/**/*.rb')
60
32
  end
@@ -1,4 +1,4 @@
1
- var Calendar = Class.create({
1
+ var EventCalendar = Class.create({
2
2
 
3
3
  options: $H({
4
4
  events_css_path: '.event',
@@ -16,7 +16,7 @@ var Calendar = Class.create({
16
16
  this.add_hover_behavior_to_event(event);
17
17
  }.bind(this));
18
18
 
19
- Calendar.instances.push(this);
19
+ EventCalendar.instances.push(this);
20
20
  },
21
21
 
22
22
  add_fields_to_event: function(event) {
@@ -52,4 +52,4 @@ var Calendar = Class.create({
52
52
 
53
53
  });
54
54
 
55
- Calendar.instances = [];
55
+ EventCalendar.instances = [];
@@ -1,22 +1,22 @@
1
- .calendar table {
1
+ .event_calendar table {
2
2
  border-collapse: collapse;
3
3
  margin: 0;
4
4
  width: 100%; }
5
- .calendar table td {
5
+ .event_calendar table td {
6
6
  border-bottom: 0px solid transparent !important;
7
7
  width: 14.285%; }
8
- .calendar .days {
8
+ .event_calendar .days {
9
9
  position: relative; }
10
- .calendar .days table.grid {
10
+ .event_calendar .days table.grid {
11
11
  z-index: 1; }
12
- .calendar .days .events {
12
+ .event_calendar .days .events {
13
13
  left: 0px;
14
14
  position: absolute;
15
15
  table-layout: fixed;
16
16
  text-align: left;
17
17
  top: 0px;
18
18
  z-index: 2; }
19
- .calendar .days .events td {
19
+ .event_calendar .days .events td {
20
20
  border-bottom-width: 0px;
21
21
  border-left-width: 0px;
22
22
  border-color: transparent;
@@ -24,47 +24,47 @@
24
24
  padding: 0;
25
25
  text-overflow: ellipsis;
26
26
  white-space: nowrap; }
27
- .calendar .days .events td a {
27
+ .event_calendar .days .events td a {
28
28
  background-color: transparent;
29
29
  cursor: pointer;
30
30
  display: block;
31
31
  padding: 1px 3px;
32
32
  text-decoration: none; }
33
- .calendar .days .events td .fields {
33
+ .event_calendar .days .events td .fields {
34
34
  display: none; }
35
- .calendar .days .events tr.grid td {
35
+ .event_calendar .days .events tr.grid td {
36
36
  border-top-width: 0px;
37
37
  height: 0px; }
38
38
 
39
- .calendar {
39
+ .event_calendar {
40
40
  border-bottom: 1px solid #d4d5d4; }
41
- .calendar table td {
41
+ .event_calendar table td {
42
42
  border-color: #d4d5d4;
43
43
  border-width: 1px; }
44
- .calendar .navigation td {
44
+ .event_calendar .navigation td {
45
45
  border-color: transparent; }
46
- .calendar table.grid {
46
+ .event_calendar table.grid {
47
47
  background-color: #fefffe;
48
48
  height: 125px; }
49
- .calendar .label {
49
+ .event_calendar .label {
50
50
  background-color: #ebede2;
51
51
  border-top-width: 1px;
52
52
  color: black; }
53
- .calendar .header .label {
53
+ .event_calendar .header .label {
54
54
  background-color: #2f302f;
55
55
  color: white; }
56
- .calendar .days .events td {
56
+ .event_calendar .days .events td {
57
57
  border-top-width: 3px; }
58
- .calendar .days .events td a {
58
+ .event_calendar .days .events td a {
59
59
  background-color: #9aac9a;
60
60
  color: white;
61
61
  -khtml-border-radius: 5px;
62
62
  -moz-border-radius: 5px;
63
63
  -webkit-border-radius: 5px;
64
64
  border-radius: 5px; }
65
- .calendar .days .events td:hover a, .calendar .days .events td.hover a {
65
+ .event_calendar .days .events td:hover a, .event_calendar .days .events td.hover a {
66
66
  background-color: #6f7f6f; }
67
- .calendar .days .events td.continuation a {
67
+ .event_calendar .days .events td.continuation a {
68
68
  -khtml-border-radius-bottomleft: 0px;
69
69
  -moz-border-radius-bottomleft: 0px;
70
70
  -webkit-border-bottom-left-radius: 0px;
@@ -73,7 +73,7 @@
73
73
  -moz-border-radius-topleft: 0px;
74
74
  -webkit-border-top-left-radius: 0px;
75
75
  border-top-left-radius: 0px; }
76
- .calendar .days .events td.continued a {
76
+ .event_calendar .days .events td.continued a {
77
77
  -khtml-border-radius-bottomright: 0px;
78
78
  -moz-border-radius-bottomright: 0px;
79
79
  -webkit-border-bottom-right-radius: 0px;
@@ -1,22 +1,52 @@
1
- require 'activesupport'
1
+ require 'active_support'
2
2
  require 'markaby'
3
3
  require 'haml'
4
- require 'calendar/event'
5
- require 'calendar/week'
4
+ require 'event_calendar/event'
5
+ require 'event_calendar/week'
6
6
 
7
+ # Adds an <tt>:events</tt> <tt>attr_accessor</tt> to the <tt>Date</tt> object.
7
8
  Date.class_eval { attr_accessor :events }
8
9
 
9
- class Calendar
10
+ # Generates HTML calendars
11
+ class EventCalendar
10
12
 
11
13
  extend ActiveSupport::Memoizable
12
14
 
13
15
  undef_method :id
14
16
 
15
- attr_accessor :events, :month, :options, :year
17
+ attr_accessor :events, :options
18
+ attr_reader :month, :year
16
19
 
20
+ # The default options used when generating event calendars
21
+ #
22
+ # :id => The HTML id of the generated container div for this event calendar. Defaults to 'event_calendar'.
23
+ # :beginning_of_week => The day number to use as the beginning of the week. For example, 0 is for Sunday, 1 is for Monday, etc.
24
+ # Defaults to 0.
25
+ # :day_label * => The label to use for each day. Defaults to the day number.
26
+ # :event_class ** => The HTML class to add to each event. Defaults to nil.
27
+ # :event_id ** => The id (object_id or database id) of an event. Defaults to :id.
28
+ # :event_title ** => The title of an event. Defaults to :title.
29
+ # :event_start ** => The start date or datetime of an event. Defaults to :starts_at.
30
+ # :event_end ** => The end date or datetime of an event. Defaults to :ends_at.
31
+ # :event_url ** => The url of an event to use as the HTML href attribute. Defaults to '#'.
32
+ # :event_output ** => The HTML to output for an event. Defaults to a link to the :event_url using the :event_title
33
+ # as its label and title attributes.
34
+ # :event_fields ** => The event fields to output as hidden attributes into the calendar so that they can be accessed with
35
+ # javascript. Defaults to [:id, :title, :start, :end].
36
+ # :events => An array of events to display in the calendar. Defaults to [].
37
+ # :header_label * => The label to use as the header of the calendar. Defaults to the month name and year like 'October 2009'.
38
+ # :header_day_label * => The label to use as the header of each day. Defaults to the abbreviated day name like 'Thu'.
39
+ # :navigation_label * => The label to use as the inner HTML for the navigation links. Defaults to the full month name like 'November'.
40
+ # :navigation_url => A proc which returns the url to use as the HTML href attribute for the previous and next month links.
41
+ # This proc is passed a date object representing the first day of the previous or next months. Defaults to '#'.
42
+ # :template => A path to the Markaby template file to use when rendering the calendar. Defaults to the 'event_calendar/template.mab'
43
+ # file found in this directory.
44
+ #
45
+ # * See the EventCalendar.evaluate_date_format_option method for possible values.
46
+ # ** See the Event#evaluate_option method for possible values.
17
47
  def self.default_options
18
48
  @default_options ||= {
19
- :id => 'calendar',
49
+ :id => 'event_calendar',
20
50
  :beginning_of_week => 0,
21
51
  :day_label => proc { |date| date.strftime('%d').gsub(/^0/, '') },
22
52
  :event_class => nil,
@@ -24,42 +54,81 @@ class Calendar
24
54
  :event_title => :title,
25
55
  :event_start => :starts_at,
26
56
  :event_end => :ends_at,
27
- :event_output => proc { |event| "<a href=\"#\" title=\"#{event.title}\">#{event.title}</a>" },
57
+ :event_url => '#',
58
+ :event_output => proc { |event| "<a href=\"#{event.url}\" title=\"#{event.title}\">#{event.title}</a>" },
28
59
  :event_fields => [:id, :title, :start, :end],
29
60
  :events => [],
30
61
  :header_label => '%B %Y',
31
62
  :header_day_label => '%a',
32
63
  :navigation_label => '%B',
33
64
  :navigation_url => proc { |date| '#' },
34
- :template => File.join(File.dirname(__FILE__), 'calendar', 'template.mab')
65
+ :template => File.join(File.dirname(__FILE__), 'event_calendar', 'template.mab')
35
66
  }
36
67
  end
37
68
 
69
+ # Optionally accepts a <tt>year</tt> as the first argument, a <tt>month</tt> (integer) as the second argument, and a
70
+ # hash of options as the third argument. It also accepts a block which it passes itself to.
71
+ #
72
+ # For example:
73
+ #
74
+ # @event_calendar = EventCalendar.new
75
+ #
76
+ # @event_calendar = EventCalendar.new(2009, 10, :id => 'calendar', :events => Event.all)
77
+ #
78
+ # @event_calendar = EventCalendar.new(2009, 10) do |c|
79
+ # c.id = 'calendar'
80
+ # c.events = Event.all
81
+ # end
38
82
  def initialize(year = Time.now.year, month = Time.now.month, options = {})
39
- self.year, self.month, self.options = year, month, self.class.default_options.merge(options)
40
- self.events = self.options.delete(:events).collect { |event| Event.new(event, self.options) }.sort_by(&:start)
83
+ @year, @month, self.options = year, month, self.class.default_options.merge(options)
84
+ @events = self.options.delete(:events).collect { |event| Event.new(event, self.options) }.sort_by(&:start)
41
85
  yield self if block_given?
42
86
  end
43
87
 
88
+ # Returns a date object representing the first day of this <tt>EventCalendar</tt> instance's specified <tt>year</tt> and <tt>month</tt>.
44
89
  def date
45
90
  Date.civil(year, month, 1)
46
91
  end
47
92
  memoize :date
48
93
 
94
+ # Looks up the specified option representing a date format and returns the evaluated the result.
95
+ #
96
+ # This is used inside the <tt>Markaby</tt> template. For example, we have an option <tt>:header_label</tt> which
97
+ # represents the content at the top of the calendar that outputs the month name and year by default, like
98
+ # "October 2009".
99
+ #
100
+ # Inside the template, we call <tt>event_calendar.evaluate_date_format_option(:header_label, event_calendar.date)</tt>.
101
+ #
102
+ # If <tt>options[:header_label]</tt> is a string, it takes <tt>event_calendar.date</tt> and calls <tt>strftime(options[:header_label])</tt>
103
+ # on it.
104
+ #
105
+ # If it's a symbol, it takes <tt>event_calendar.date</tt> and calls <tt>send(options[:header_label])</tt> on it.
106
+ #
107
+ # If it's a proc, it calls the proc and passes <tt>event_calendar.date</tt> to it. You can pass any number of args to this method
108
+ # and they'll passed to the proc.
109
+ #
110
+ # Any other value for <tt>options[:header_label]</tt> is simply returned.
49
111
  def evaluate_date_format_option(option, *args)
50
112
  value = self.send(option)
51
113
  case value
52
- when String
53
- args.first.strftime(value)
54
- when Symbol
55
- args.first.send(value)
56
- when Proc
57
- value.call(*args)
58
- else
59
- value
114
+ when String
115
+ args.first.strftime(value)
116
+ when Symbol
117
+ args.first.send(value)
118
+ when Proc
119
+ value.call(*args)
120
+ else
121
+ value
60
122
  end
61
123
  end
62
124
 
125
+ # Allows you to read and write options using method notation.
126
+ #
127
+ # For example:
128
+ #
129
+ # @event_calendar = EventCalendar.new(2009, 10)
130
+ # @event_calendar.template = '/path/to/some/other/template.mab'
131
+ # puts @event_calendar.beginning_of_week
63
132
  def method_missing(method, *args)
64
133
  if method.to_s =~ /^([^=]+)(=?)$/ && options.has_key?($1.to_sym)
65
134
  options[$1.to_sym] = args.first unless $2.empty?
@@ -69,13 +138,30 @@ class Calendar
69
138
  end
70
139
  end
71
140
 
141
+ # Returns the HTML representation of this <tt>EventCalendar</tt>.
142
+ #
143
+ # aliased as <tt>to_html</tt>
72
144
  def to_s
73
- date(:reload)
74
- weeks(:reload)
75
145
  render
76
146
  end
77
147
  alias_method :to_html, :to_s
78
148
 
149
+ # Returns an array of week objects which contain date objects for every day that this calendar displays.
150
+ # It may contain a few days from the previous and next months.
151
+ #
152
+ # The <tt>EventCalendar::Week</tt> class inherits from <tt>Array</tt>.
153
+ #
154
+ # For example:
155
+ #
156
+ # puts EventCalendar.new(2009, 10).weeks.inspect
157
+ #
158
+ # # [
159
+ # # [Sun, 27 Sep 2009, Mon, 28 Sep 2009, Tue, 29 Sep 2009, Wed, 30 Sep 2009, Thu, 01 Oct 2009, Fri, 02 Oct 2009, Sat, 03 Oct 2009],
160
+ # # [Sun, 04 Oct 2009, Mon, 05 Oct 2009, Tue, 06 Oct 2009, Wed, 07 Oct 2009, Thu, 08 Oct 2009, Fri, 09 Oct 2009, Sat, 10 Oct 2009],
161
+ # # [Sun, 11 Oct 2009, Mon, 12 Oct 2009, Tue, 13 Oct 2009, Wed, 14 Oct 2009, Thu, 15 Oct 2009, Fri, 16 Oct 2009, Sat, 17 Oct 2009],
162
+ # # [Sun, 18 Oct 2009, Mon, 19 Oct 2009, Tue, 20 Oct 2009, Wed, 21 Oct 2009, Thu, 22 Oct 2009, Fri, 23 Oct 2009, Sat, 24 Oct 2009],
163
+ # # [Sun, 25 Oct 2009, Mon, 26 Oct 2009, Tue, 27 Oct 2009, Wed, 28 Oct 2009, Thu, 29 Oct 2009, Fri, 30 Oct 2009, Sat, 31 Oct 2009]
164
+ # # ]
79
165
  def weeks
80
166
  days_in_month = Time.days_in_month(month, year)
81
167
  starting_day = date.beginning_of_week() -1.day + beginning_of_week.days
@@ -86,12 +172,17 @@ class Calendar
86
172
 
87
173
  protected
88
174
 
175
+ # Generates the HTML representation of this <tt>EventCalendar</tt>. The default implementation calls
176
+ # <tt>render_with_markaby</tt>.
89
177
  def render
90
178
  render_with_markaby
91
179
  end
180
+ memoize :render
92
181
 
182
+ # Reads the template file specified in <tt>options[:template]</tt> and evaluates it with <tt>Markaby</tt>,
183
+ # passing this <tt>EventCalendar</tt> instance as the <tt>event_calendar</tt> local variable.
93
184
  def render_with_markaby
94
- Markaby::Builder.new(:calendar => self, :template => File.read(template)) { eval(template) }.to_s
185
+ Markaby::Builder.new(:event_calendar => self, :template => File.exists?(template) ? File.read(template) : template) { eval(template) }.to_s
95
186
  end
96
187
 
97
188
  end
@@ -0,0 +1,74 @@
1
+ class EventCalendar
2
+
3
+ # Provides conveniece methods for calculating dates and spans for an event. Stores the real event object for
4
+ # proxying all other method calls to it.
5
+ class Event
6
+
7
+ undef_method :id
8
+
9
+ attr_accessor :options
10
+ attr_reader :event
11
+
12
+ # Accepts a real event object which it stores to proxy method calls to, and a hash of options obtained from the
13
+ # <tt>EventCalendar</tt> instance.
14
+ def initialize(event, options)
15
+ @event, @options = event, options
16
+ end
17
+
18
+ # Calculates the number of days this day takes up on a calendar (rounding up).
19
+ # Optionally accepts <tt>week_start</tt> and <tt>week_end</tt> dates to calculate how many days an event takes
20
+ # up in a single week. For example, if an event started on a Friday and ended the following Wednesday, calling
21
+ # <tt>@event.days(the_sunday_after_the_event_starts)</tt> would return 4.
22
+ def days(week_start = start_date, week_end = end_date)
23
+ (end_date > week_end ? week_end : end_date) - (start_date < week_start ? week_start : start_date) + 1
24
+ end
25
+
26
+ # Returns the end date of the event. If the event stores its end as a datetime then it is converted to a date.
27
+ def end_date
28
+ self.end.to_date
29
+ end
30
+
31
+ # Returns the start date of the event. If the event stores its start as a datetime then it is converted to a date.
32
+ def start_date
33
+ start.to_date
34
+ end
35
+
36
+ # Allows you to read options starting with <tt>:event_</tt> using method notation.
37
+ #
38
+ # For example: calling <tt>@event.title</tt> will return the value of <tt>@event.options[:event_title]</tt> if
39
+ # that option exists.
40
+ #
41
+ # All other calls are delegated to the real <tt>:event</tt> object.
42
+ def method_missing(method, *args)
43
+ option = "event_#{method}".to_sym
44
+ if @options.has_key?(option)
45
+ evaluate_option(option)
46
+ else
47
+ @event.send(method, *args)
48
+ end
49
+ end
50
+
51
+ protected
52
+
53
+ # Looks up the specified option returns the evaluated the result.
54
+ #
55
+ # If the value of the option is a symbol, then it calls <tt>@event.send(value)</tt>
56
+ #
57
+ # If the value of the option is a proc, then it calls the proc and passes the current <tt>Event</tt>
58
+ # instance as an argument.
59
+ #
60
+ # Any other value is simply returned.
61
+ def evaluate_option(option)
62
+ value = @options[option]
63
+ case value
64
+ when Symbol
65
+ @event.send(value)
66
+ when Proc
67
+ value.call(self)
68
+ else
69
+ value
70
+ end
71
+ end
72
+
73
+ end
74
+ end