event_calendar 0.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,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