event_calendar 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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