event_calendar 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,84 @@
1
+ .calendar table {
2
+ border-collapse: collapse;
3
+ margin: 0;
4
+ width: 100%; }
5
+ .calendar table td {
6
+ border-bottom: 0px solid transparent !important;
7
+ width: 14.285%; }
8
+ .calendar .days {
9
+ position: relative; }
10
+ .calendar .days table.grid {
11
+ z-index: 1; }
12
+ .calendar .days .events {
13
+ left: 0px;
14
+ position: absolute;
15
+ table-layout: fixed;
16
+ text-align: left;
17
+ top: 0px;
18
+ z-index: 2; }
19
+ .calendar .days .events td {
20
+ border-bottom-width: 0px;
21
+ border-left-width: 0px;
22
+ border-color: transparent;
23
+ overflow: hidden;
24
+ padding: 0;
25
+ text-overflow: ellipsis;
26
+ white-space: nowrap; }
27
+ .calendar .days .events td a {
28
+ background-color: transparent;
29
+ cursor: pointer;
30
+ display: block;
31
+ padding: 1px 3px;
32
+ text-decoration: none; }
33
+ .calendar .days .events td .fields {
34
+ display: none; }
35
+ .calendar .days .events tr.grid td {
36
+ border-top-width: 0px;
37
+ height: 0px; }
38
+
39
+ .calendar {
40
+ border-bottom: 1px solid #d4d5d4; }
41
+ .calendar table td {
42
+ border-color: #d4d5d4;
43
+ border-width: 1px; }
44
+ .calendar .navigation td {
45
+ border-color: transparent; }
46
+ .calendar table.grid {
47
+ background-color: #fefffe;
48
+ height: 125px; }
49
+ .calendar .label {
50
+ background-color: #ebede2;
51
+ border-top-width: 1px;
52
+ color: black; }
53
+ .calendar .header .label {
54
+ background-color: #2f302f;
55
+ color: white; }
56
+ .calendar .days .events td {
57
+ border-top-width: 3px; }
58
+ .calendar .days .events td a {
59
+ background-color: #9aac9a;
60
+ color: white;
61
+ -khtml-border-radius: 5px;
62
+ -moz-border-radius: 5px;
63
+ -webkit-border-radius: 5px;
64
+ border-radius: 5px; }
65
+ .calendar .days .events td:hover a, .calendar .days .events td.hover a {
66
+ background-color: #6f7f6f; }
67
+ .calendar .days .events td.continuation a {
68
+ -khtml-border-radius-bottomleft: 0px;
69
+ -moz-border-radius-bottomleft: 0px;
70
+ -webkit-border-bottom-left-radius: 0px;
71
+ border-bottom-left-radius: 0px;
72
+ -khtml-border-radius-topleft: 0px;
73
+ -moz-border-radius-topleft: 0px;
74
+ -webkit-border-top-left-radius: 0px;
75
+ border-top-left-radius: 0px; }
76
+ .calendar .days .events td.continued a {
77
+ -khtml-border-radius-bottomright: 0px;
78
+ -moz-border-radius-bottomright: 0px;
79
+ -webkit-border-bottom-right-radius: 0px;
80
+ border-bottom-right-radius: 0px;
81
+ -khtml-border-radius-topright: 0px;
82
+ -moz-border-radius-topright: 0px;
83
+ -webkit-border-top-right-radius: 0px;
84
+ border-top-right-radius: 0px; }
@@ -0,0 +1,13 @@
1
+ /*
2
+ Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3
+ Code licensed under the BSD License:
4
+ http://developer.yahoo.net/yui/license.txt
5
+ version: 2.7.0
6
+ */
7
+ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}/*
8
+ Copyright (c) 2009, Yahoo! Inc. All rights reserved.
9
+ Code licensed under the BSD License:
10
+ http://developer.yahoo.net/yui/license.txt
11
+ version: 2.7.0
12
+ */
13
+ body{margin:10px;}h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong,dt{font-weight:bold;}optgroup{font-weight:normal;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;}em{font-style:italic;}del{text-decoration:line-through;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ol li{list-style:decimal outside;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{border:1px solid #000;padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}sup{vertical-align:super;}sub{vertical-align:sub;}p,fieldset,table,pre{margin-bottom:1em;}button,input[type="checkbox"],input[type="radio"],input[type="reset"],input[type="submit"]{padding:1px;}
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'event_calendar'
@@ -0,0 +1,46 @@
1
+ class Calendar
2
+ class Event
3
+
4
+ undef_method :id
5
+
6
+ def initialize(event, options)
7
+ @event, @options = event, options
8
+ end
9
+
10
+ def days(week_start = start_date, week_end = end_date)
11
+ (end_date > week_end ? week_end : end_date) - (start_date < week_start ? week_start : start_date) + 1
12
+ end
13
+
14
+ def end_date
15
+ self.end.to_date
16
+ end
17
+
18
+ def start_date
19
+ start.to_date
20
+ end
21
+
22
+ def method_missing(method, *args)
23
+ option = "event_#{method}".to_sym
24
+ if @options.has_key?(option)
25
+ evaluate_option(option)
26
+ else
27
+ @event.send(method, *args)
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ def evaluate_option(option)
34
+ value = @options[option]
35
+ case value
36
+ when Symbol
37
+ @event.send(value)
38
+ when Proc
39
+ proc.call(self)
40
+ else
41
+ value
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,133 @@
1
+ =round(!radius)
2
+ :-khtml-border-radius= !radius
3
+ :-moz-border-radius= !radius
4
+ :-webkit-border-radius= !radius
5
+ :border-radius= !radius
6
+
7
+ =unround_left()
8
+ :-khtml-border-radius-bottomleft= 0px
9
+ :-moz-border-radius-bottomleft= 0px
10
+ :-webkit-border-bottom-left-radius= 0px
11
+ :border-bottom-left-radius= 0px
12
+ :-khtml-border-radius-topleft= 0px
13
+ :-moz-border-radius-topleft= 0px
14
+ :-webkit-border-top-left-radius= 0px
15
+ :border-top-left-radius= 0px
16
+
17
+ =unround_right()
18
+ :-khtml-border-radius-bottomright= 0px
19
+ :-moz-border-radius-bottomright= 0px
20
+ :-webkit-border-bottom-right-radius= 0px
21
+ :border-bottom-right-radius= 0px
22
+ :-khtml-border-radius-topright= 0px
23
+ :-moz-border-radius-topright= 0px
24
+ :-webkit-border-top-right-radius= 0px
25
+ :border-top-right-radius= 0px
26
+
27
+ .calendar
28
+
29
+ table
30
+ border-collapse: collapse
31
+ margin: 0
32
+ width: 100%
33
+
34
+ td
35
+ border-bottom: 0px solid transparent !important
36
+ width: 14.285%
37
+
38
+ .days
39
+ position: relative
40
+
41
+ table.grid
42
+ z-index: 1
43
+
44
+ .events
45
+ left: 0px
46
+ position: absolute
47
+ table-layout: fixed
48
+ text-align: left
49
+ top: 0px
50
+ z-index: 2
51
+
52
+ td
53
+ border-bottom-width: 0px
54
+ border-left-width: 0px
55
+ border-color: transparent
56
+ overflow: hidden
57
+ padding: 0
58
+ text-overflow: ellipsis
59
+ white-space: nowrap
60
+
61
+ a
62
+ background-color: transparent
63
+ cursor: pointer
64
+ display: block
65
+ padding: 1px 3px
66
+ text-decoration: none
67
+
68
+ .fields
69
+ display: none
70
+
71
+ tr.grid td
72
+ border-top-width: 0px
73
+ height: 0px
74
+
75
+
76
+
77
+
78
+ !border_color = #D4D5D4
79
+ !border_width = 1px
80
+
81
+ !event_background_color = #9AAC9A
82
+ !event_hover_background_color = #6F7F6F
83
+ !event_color = #FFF
84
+ !event_spacing = 3px
85
+
86
+ !grid_background_color = #FEFFFE
87
+ !grid_height = 125px
88
+
89
+ !header_label_background_color = #2F302F
90
+ !header_label_color = #FFF
91
+
92
+ !label_background_color = #EBEDE2
93
+ !label_color = #000
94
+
95
+ .calendar
96
+ border-bottom= !border_width "solid" !border_color
97
+
98
+ table td
99
+ border-color= !border_color
100
+ border-width= !border_width
101
+
102
+ .navigation td
103
+ border-color: transparent
104
+
105
+ table.grid
106
+ background-color= !grid_background_color
107
+ height= !grid_height
108
+
109
+ .label
110
+ background-color= !label_background_color
111
+ border-top-width= !border_width
112
+ color= !label_color
113
+
114
+ .header .label
115
+ background-color= !header_label_background_color
116
+ color= !header_label_color
117
+
118
+ .days .events td
119
+ border-top-width= !event_spacing
120
+
121
+ a
122
+ background-color= !event_background_color
123
+ color= !event_color
124
+ +round(5px)
125
+
126
+ &:hover a, &.hover a
127
+ background-color= !event_hover_background_color
128
+
129
+ &.continuation a
130
+ +unround_left()
131
+
132
+ &.continued a
133
+ +unround_right()
@@ -0,0 +1,110 @@
1
+ div.calendar.send(calendar.date.strftime('%B').downcase).send("#{calendar.id}!") do
2
+ div.header do
3
+ table do
4
+ tbody do
5
+ tr.navigation do
6
+ td.previous_month(:colspan => 2) do
7
+ a(:rel => 'previous', :href => calendar.navigation_url.call(calendar.date.last_month)) do
8
+ calendar.evaluate_date_format_option(:navigation_label, calendar.date.last_month, calendar.date)
9
+ end
10
+ end
11
+ td.current_month calendar.evaluate_date_format_option(:header_label, calendar.date), :colspan => 3
12
+ td.next_month(:colspan => 2) do
13
+ a(:rel => 'next', :href => calendar.navigation_url.call(calendar.date.next_month)) do
14
+ calendar.evaluate_date_format_option(:navigation_label, calendar.date.next_month, calendar.date)
15
+ end
16
+ end
17
+ end
18
+ tr.labels do
19
+ calendar.weeks.first.each_with_index do |day, index|
20
+ day_label = td.day
21
+ day_label = day_label.send(day.strftime('%A').downcase)
22
+ day_label = day_label.today if day.cwday == Time.now.to_date.cwday
23
+ day_label.label calendar.evaluate_date_format_option(:header_day_label, day)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ div.body do
30
+ calendar.weeks.each do |week|
31
+ div.week.send("#{calendar.id}_week_#{week.first}_#{week.last}!") do
32
+ table.send("#{calendar.id}_labels_#{week.first}_#{week.last}!") do
33
+ tbody do
34
+ tr.labels do
35
+ week.each do |day|
36
+ day_label = td.day
37
+ day_label = day_label.send(day.month == calendar.date.month ? 'current_month' : day < calendar.date ? 'previous_month' : 'next_month')
38
+ day_label = day_label.send([6, 7].include?(day.cwday) ? 'weekend' : 'weekday')
39
+ day_label = day_label.send(day.strftime('%A').downcase)
40
+ day_label = day_label.send(day.strftime('%B').downcase)
41
+ day_label = day_label.send("day_#{day.strftime('%d').gsub(/^0/, '')}")
42
+ day_label = day_label.today if day == Time.now.to_date
43
+ day_label = day_label.scheduled if calendar.events.any? { |event| event.start_date <= day && event.end_date >= day }
44
+ day_label.label calendar.evaluate_date_format_option(:day_label, day)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ div.days.send("#{calendar.id}_days_#{week.first}_#{week.last}!") do
50
+ table.grid.send("#{calendar.id}_grid_#{week.first}_#{week.last}!") do
51
+ tbody do
52
+ tr do
53
+ week.each do |day|
54
+ day_grid = td.day
55
+ day_grid = day_grid.send(day.month == calendar.date.month ? 'current_month' : day < calendar.date ? 'previous_month' : 'next_month')
56
+ day_grid = day_grid.send([6, 7].include?(day.cwday) ? 'weekend' : 'weekday')
57
+ day_grid = day_grid.send(day.strftime('%A').downcase)
58
+ day_grid = day_grid.send(day.strftime('%B').downcase)
59
+ day_grid = day_grid.send("day_#{day.strftime('%d').gsub(/^0/, '')}")
60
+ day_grid = day_grid.today if day == Time.now.to_date
61
+ day_grid = day_grid.scheduled if calendar.events.any? { |event| event.start_date <= day && event.end_date >= day }
62
+ day_grid.send("#{calendar.id}_day_#{day}!") {}
63
+ end
64
+ end
65
+ end
66
+ end
67
+ unless week.events.empty?
68
+ table.events.send("#{calendar.id}_events_#{week.first}_#{week.last}!") do
69
+ tbody do
70
+ tr.grid do
71
+ week.each { |day| td('') }
72
+ end
73
+ week.events.each do |row|
74
+ tr do
75
+ row.each do |cell|
76
+ if cell.empty?
77
+ td('')
78
+ else
79
+ html_options = { :class => 'event' }
80
+ html_options[:colspan] = cell[:span] unless cell[:span] == 1
81
+ html_options[:class] << " #{calendar.event_class}" unless calendar.event_class.nil?
82
+ if cell[:continued]
83
+ html_options[:class] << ' continuation' if cell[:event].start_date < week.first
84
+ html_options[:class] << ' continued' if cell[:event].end_date > week.last
85
+ end
86
+ event_id = "event_#{cell[:event].id}"
87
+ begin
88
+ td.send("#{event_id}!", html_options) do
89
+ calendar.event_output.call(cell[:event]) + div.fields do
90
+ calendar.event_fields.each do |field|
91
+ span(cell[:event].send(field), :title => field)
92
+ end
93
+ end
94
+ end
95
+ rescue Markaby::InvalidXhtmlError
96
+ event_id = event_id.gsub(/^event_(\d+)(_(\d+))?$/) { |match| "event_#{$1}_#{$3.to_i + 1}" }
97
+ retry
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,34 @@
1
+ class Calendar
2
+ class Week < Array
3
+
4
+ extend ActiveSupport::Memoizable
5
+
6
+ def initialize(days, events)
7
+ super days
8
+ each { |day| day.events = events.select { |event| event.start_date == day || (event.start_date < day && event.end_date >= day && day == first) } }
9
+ end
10
+
11
+ def events
12
+ events = []
13
+ until all? { |day| day.events.empty? }
14
+ row = []
15
+ each_with_index do |day, index|
16
+ cell_count = row.inject(0) { |sum, cell| sum += (cell.empty? ? 1 : cell[:span]) }
17
+ next if cell_count > index || cell_count >= 7
18
+
19
+ cell = {}
20
+ unless day.events.empty?
21
+ cell[:event] = day.events.shift
22
+ cell[:span] = cell[:event].days(first, last)
23
+ cell[:continued] = cell[:event].days != cell[:span]
24
+ end
25
+ row << cell
26
+ end
27
+ events << row
28
+ end
29
+ events
30
+ end
31
+ memoize :events
32
+
33
+ end
34
+ end
@@ -0,0 +1,97 @@
1
+ require 'activesupport'
2
+ require 'markaby'
3
+ require 'haml'
4
+ require 'calendar/event'
5
+ require 'calendar/week'
6
+
7
+ Date.class_eval { attr_accessor :events }
8
+
9
+ class Calendar
10
+
11
+ extend ActiveSupport::Memoizable
12
+
13
+ undef_method :id
14
+
15
+ attr_accessor :events, :month, :options, :year
16
+
17
+ def self.default_options
18
+ @default_options ||= {
19
+ :id => 'calendar',
20
+ :beginning_of_week => 0,
21
+ :day_label => proc { |date| date.strftime('%d').gsub(/^0/, '') },
22
+ :event_class => nil,
23
+ :event_id => :id,
24
+ :event_title => :title,
25
+ :event_start => :starts_at,
26
+ :event_end => :ends_at,
27
+ :event_output => proc { |event| "<a href=\"#\" title=\"#{event.title}\">#{event.title}</a>" },
28
+ :event_fields => [:id, :title, :start, :end],
29
+ :events => [],
30
+ :header_label => '%B %Y',
31
+ :header_day_label => '%a',
32
+ :navigation_label => '%B',
33
+ :navigation_url => proc { |date| '#' },
34
+ :template => File.join(File.dirname(__FILE__), 'calendar', 'template.mab')
35
+ }
36
+ end
37
+
38
+ 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)
41
+ yield self if block_given?
42
+ end
43
+
44
+ def date
45
+ Date.civil(year, month, 1)
46
+ end
47
+ memoize :date
48
+
49
+ def evaluate_date_format_option(option, *args)
50
+ value = self.send(option)
51
+ 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
60
+ end
61
+ end
62
+
63
+ def method_missing(method, *args)
64
+ if method.to_s =~ /^([^=]+)(=?)$/ && options.has_key?($1.to_sym)
65
+ options[$1.to_sym] = args.first unless $2.empty?
66
+ options[$1.to_sym]
67
+ else
68
+ super
69
+ end
70
+ end
71
+
72
+ def to_s
73
+ date(:reload)
74
+ weeks(:reload)
75
+ render
76
+ end
77
+ alias_method :to_html, :to_s
78
+
79
+ def weeks
80
+ days_in_month = Time.days_in_month(month, year)
81
+ starting_day = date.beginning_of_week() -1.day + beginning_of_week.days
82
+ ending_day = (date + days_in_month).end_of_week() -1.day + beginning_of_week.days
83
+ (starting_day..ending_day).to_a.in_groups_of(7).collect { |week| Week.new(week, events) }
84
+ end
85
+ memoize :weeks
86
+
87
+ protected
88
+
89
+ def render
90
+ render_with_markaby
91
+ end
92
+
93
+ def render_with_markaby
94
+ Markaby::Builder.new(:calendar => self, :template => File.read(template)) { eval(template) }.to_s
95
+ end
96
+
97
+ end
@@ -0,0 +1,87 @@
1
+ require 'fileutils'
2
+
3
+ CALENDAR_ROOT = File.join(File.dirname(__FILE__), '..', '..')
4
+ ASSETS_ROOT = File.join(CALENDAR_ROOT, 'assets')
5
+ SANDBOX_ROOT = File.join(CALENDAR_ROOT, 'sandbox')
6
+
7
+ namespace :calendar do
8
+ namespace :generate do
9
+ desc 'Generates css for the calendar'
10
+ task :css => :build_css do
11
+ puts File.read(File.join(ASSETS_ROOT, 'stylesheets', 'calendar.css'))
12
+ end
13
+
14
+ desc 'Generates js for the calendar'
15
+ task :js do
16
+ puts File.read(File.join(ASSETS_ROOT, 'javascripts', 'calendar.js'))
17
+ end
18
+
19
+ desc 'Creates a sandbox in the gem root for testing'
20
+ task :sandbox => [:build_css] do
21
+ $:.unshift(File.join(CALENDAR_ROOT, 'lib'))
22
+ require 'timecop'
23
+ require 'active_support'
24
+ require 'markaby'
25
+ require 'calendar'
26
+
27
+ FileUtils.mkdir(SANDBOX_ROOT) unless File.exists?(SANDBOX_ROOT)
28
+ FileUtils.cp_r(File.join(ASSETS_ROOT, '.'), SANDBOX_ROOT)
29
+
30
+ Event = Struct.new(:title, :starts_at, :ends_at) do
31
+ def id; object_id; end
32
+ end
33
+
34
+ Timecop.freeze(Date.civil(2009, 10, 6)) do
35
+ events = [
36
+ Event.new('Event 1', Time.now, 10.minutes.from_now),
37
+ Event.new('Event 1a', Time.now, 10.minutes.from_now),
38
+ Event.new('Event 1b', Time.now, 10.minutes.from_now),
39
+ Event.new('Event 1c', Time.now, 10.minutes.from_now),
40
+ Event.new('Event 2', 1.day.from_now, 1.5.days.from_now),
41
+ Event.new('Event 3', Time.now, 3.days.from_now),
42
+ Event.new('Event 4 has a longer title', 3.days.from_now, 5.days.from_now),
43
+ Event.new('Event 5 spans across multiple weeks', 4.days.from_now, 12.days.from_now)
44
+ ]
45
+ @calendar = Calendar.new(Time.now.year, Time.now.month, :events => events)
46
+ end
47
+
48
+ File.open(File.join(SANDBOX_ROOT, 'index.html'), 'w+') do |file|
49
+ file.write <<-EOF
50
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
51
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
52
+ <head>
53
+ <title>Calendar</title>
54
+ <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
55
+ <link href="stylesheets/yui-2.7.0.css" media="screen" rel="stylesheet" type="text/css" />
56
+ <link href="stylesheets/calendar.css" media="screen" rel="stylesheet" type="text/css" />
57
+ <script src="javascripts/prototype-1.6.1.js" type="text/javascript"></script>
58
+ <script src="javascripts/calendar.js" type="text/javascript"></script>
59
+ <script type="text/javascript">
60
+ //<![CDATA[
61
+ document.observe('dom:loaded', function() {
62
+ $$('.calendar').each(function(element) {
63
+ new Calendar(element);
64
+ });
65
+ });
66
+ //]]>
67
+ </script>
68
+ </head>
69
+ <body>
70
+ #{@calendar}
71
+ </body>
72
+ </html>
73
+ EOF
74
+ end
75
+ end
76
+
77
+ task :build_css do
78
+ require 'haml'
79
+ require 'sass/engine'
80
+
81
+ sass = File.join(CALENDAR_ROOT, 'lib', 'calendar', 'stylesheet.sass')
82
+ File.open(File.join(ASSETS_ROOT, 'stylesheets', 'calendar.css'), 'w+') do |file|
83
+ file.write Sass::Engine.new(File.read(sass)).to_css
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ Event = Struct.new(:title, :starts_at, :ends_at) do
4
+ def id; object_id; end
5
+ end
6
+
7
+ class CalendarTest < Test::Unit::TestCase
8
+
9
+ should 'test this gem' do
10
+ flunk
11
+ end
12
+
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'timecop'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'event_calendar'
9
+
10
+ class Test::Unit::TestCase
11
+ end