kalindar 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +4 -2
- data/lib/kalindar/app.rb +28 -22
- data/lib/kalindar/event.rb +13 -0
- data/lib/kalindar/event_calendar.rb +36 -30
- data/lib/kalindar/public/kalindar.css +27 -37
- data/lib/kalindar/timespan.rb +5 -0
- data/lib/kalindar/version.rb +1 -1
- data/lib/kalindar/views/event_list.slim +9 -7
- data/spec/kalindar_spec.rb +21 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWY4OWRmOTQ0N2YwYWQzM2U1YjMwYjQ0NGY0Y2FlYjE5MTk4Yjg2NQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MjJhYzQwYTA5MDUxYzU5NGVkM2FkM2NkZjBlMDQ2YzhjNjZiMjk1Yg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ODdiMTExNTk1YzQyOTM3MTQ1ZWNjOTM5MmZlMDg1MDZjMjU3M2Y0ZGY4MWE4
|
10
|
+
ZmE1NTY2OGRkMjNkNWJhOGFiOTQ4NjQ5ZjdlNjJjNjc4NDk3NzYxZWEwNWYz
|
11
|
+
OWNjNjNkYjBjMjdjNjA1YTIwYzJhNTQ2ODY5MDZlZDgzNjMzM2Q=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Zjk0OWE5YjlhNmJjNzU4YzNhOTM0M2E0OTZkMjViMjYxYTUwZDIzNDg1MTAx
|
14
|
+
MTgzZDY5NmU5NTA1NTgzZjNkY2E3OWE1MWM1NDUyMTRiM2E2Nzg3YzliNGE4
|
15
|
+
ZDU4MDRlZmNhY2RkNGYxZmNmM2ViZWQ2NDI2YjQ3ZTU0MmFmNGQ=
|
data/README.md
CHANGED
@@ -6,6 +6,8 @@ It employs the ri_cal, sinatra, i18n ruby gems, the rightjs JavaScript framework
|
|
6
6
|
|
7
7
|
It shows recuring events and reloads on ics file changes.
|
8
8
|
|
9
|
+
Contact me if you need help!
|
10
|
+
|
9
11
|
## Installation
|
10
12
|
|
11
13
|
Add this line to your application's Gemfile:
|
@@ -34,11 +36,11 @@ Be careful. Kalindar might destroy, change or delete your ics file(s)!
|
|
34
36
|
|
35
37
|
Kalindar does not care about timezones!
|
36
38
|
|
37
|
-
Kalindar
|
39
|
+
Kalindar does not let you edit recuring events.
|
38
40
|
|
39
41
|
### Configuration
|
40
42
|
|
41
|
-
Configuration is done in config.json . There one or many calendar (ics) files and the locale can be set.
|
43
|
+
Configuration is done in config.json . There one or many calendar (ics) files and the locale can be set. Note that only the first calendar defined here can be edited.
|
42
44
|
|
43
45
|
## Contributing
|
44
46
|
|
data/lib/kalindar/app.rb
CHANGED
@@ -58,6 +58,15 @@ class KalindarApp < Sinatra::Base
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
# Add empty list for each day in date to date + number_days,
|
62
|
+
# if no value set for given key
|
63
|
+
def register_days hash, date, number_days
|
64
|
+
(date.to_date .. (date.to_date + number_days)).each do |day|
|
65
|
+
hash[day] ||= []
|
66
|
+
end
|
67
|
+
hash
|
68
|
+
end
|
69
|
+
|
61
70
|
get '/' do
|
62
71
|
redirect '/events'
|
63
72
|
end
|
@@ -68,29 +77,23 @@ class KalindarApp < Sinatra::Base
|
|
68
77
|
|
69
78
|
@events = $cal.events_in(date, date + 30)
|
70
79
|
|
71
|
-
|
72
|
-
(date .. date + 30).each do |day|
|
73
|
-
@events[day] ||= []
|
74
|
-
end
|
80
|
+
register_days @events, date, 30
|
75
81
|
|
76
82
|
slim :event_list
|
77
83
|
end
|
78
84
|
|
79
85
|
get '/events' do
|
80
86
|
# Events from today to in 30 days
|
81
|
-
@events = $cal.events_in(
|
87
|
+
@events = $cal.events_in(Date.today, Date.today + 30)
|
82
88
|
|
83
|
-
|
84
|
-
(DateTime.now .. DateTime.now + 30).each do |day|
|
85
|
-
@events[day] ||= []
|
86
|
-
end
|
89
|
+
register_days @events, Date.today, 30
|
87
90
|
|
88
91
|
slim :event_list
|
89
92
|
end
|
90
93
|
|
91
94
|
get '/events/twoday' do
|
92
95
|
# events from today to in 30 days
|
93
|
-
@events[day] = $cal.events_in
|
96
|
+
@events[day] = $cal.events_in Date.today, Date.today + 2
|
94
97
|
|
95
98
|
#@events = @events.values.flatten.sort_by {|e| e.start_time}
|
96
99
|
@today = Date.today
|
@@ -106,7 +109,7 @@ class KalindarApp < Sinatra::Base
|
|
106
109
|
slim :new_event, :locals => {'start_date' => Date.parse(params[:start_day])}
|
107
110
|
end
|
108
111
|
begin
|
109
|
-
event = Event.create_from_params params
|
112
|
+
event = Kalindar::Event.create_from_params params
|
110
113
|
rescue Exception => e
|
111
114
|
puts e.inspect
|
112
115
|
puts e.backtrace
|
@@ -117,11 +120,12 @@ class KalindarApp < Sinatra::Base
|
|
117
120
|
$cal.calendars.first.write_back!
|
118
121
|
|
119
122
|
if request.xhr?
|
120
|
-
@events = {}
|
121
123
|
# Events from today to in 30 days
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
date = Date.today
|
125
|
+
@events = $cal.events_in date, date + 30
|
126
|
+
|
127
|
+
register_days @events, date, 30
|
128
|
+
|
125
129
|
slim :event_list, :layout => false
|
126
130
|
else
|
127
131
|
redirect '/'
|
@@ -132,7 +136,7 @@ class KalindarApp < Sinatra::Base
|
|
132
136
|
get '/event/new/:day' do
|
133
137
|
# Aim is to get a new event in every case
|
134
138
|
#@event = Event.create_from_params params
|
135
|
-
@event = Event.new(RiCal::Component::Event.new($cal.calendars.first))
|
139
|
+
@event = Kalindar::Event.new(RiCal::Component::Event.new($cal.calendars.first))
|
136
140
|
@event.dtstart = Date.parse(params[:day])
|
137
141
|
slim :new_event, :locals => {'start_date' => Date.parse(params[:day])}
|
138
142
|
end
|
@@ -154,6 +158,9 @@ class KalindarApp < Sinatra::Base
|
|
154
158
|
|
155
159
|
# Edit/save an event.
|
156
160
|
put '/event/edit/:uuid' do
|
161
|
+
|
162
|
+
# TODO: Make sure this is not an recuring event or in a not modifiable calendar.
|
163
|
+
|
157
164
|
# validate_params
|
158
165
|
if params[:submitbutton] == 'cancel'
|
159
166
|
redirect '/'
|
@@ -167,13 +174,12 @@ class KalindarApp < Sinatra::Base
|
|
167
174
|
|
168
175
|
post '/events/full' do
|
169
176
|
params[:calendars]
|
170
|
-
@events = {}
|
171
177
|
# events from today to in 30 days
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
178
|
+
date = Date.today
|
179
|
+
@events = $cal.events_in date .. date + 30
|
180
|
+
|
181
|
+
register_days @events, date, 30
|
182
|
+
|
177
183
|
slim :event_list
|
178
184
|
end
|
179
185
|
end
|
data/lib/kalindar/event.rb
CHANGED
@@ -3,6 +3,19 @@ require 'delegate'
|
|
3
3
|
module Kalindar
|
4
4
|
# Delegator with some handy shortcuts
|
5
5
|
class Event < SimpleDelegator
|
6
|
+
|
7
|
+
attr_accessor :calendar
|
8
|
+
attr_accessor :modifiable
|
9
|
+
|
10
|
+
def recurs?
|
11
|
+
!recurrence_id.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
# is modifiable? if recuring event, its not
|
15
|
+
def modifiable?
|
16
|
+
@modifiable == true && !recurs?
|
17
|
+
end
|
18
|
+
|
6
19
|
# Time it starts at day, or '...'
|
7
20
|
def start_time_f day
|
8
21
|
#puts "start #{start_time} : #{start_time.class} #{start_time.to_date} #{day}"
|
@@ -34,48 +34,37 @@ class EventCalendar
|
|
34
34
|
@calendars.flatten!
|
35
35
|
end
|
36
36
|
|
37
|
-
#
|
38
|
-
def singular_events_for_month year, month
|
39
|
-
@calendar.map do |calendar|
|
40
|
-
calendar.events.select { |event|
|
41
|
-
event_between? event, dtmonth_start(year, month), dtmonth_end(year, month)
|
42
|
-
}
|
43
|
-
end.flatten
|
44
|
-
end
|
45
|
-
|
37
|
+
# Find events during date(s)/timespan.
|
46
38
|
# start_date and end_date are inclusive,
|
47
39
|
# start_date can be Timespan, too
|
48
40
|
def events_in start_date, end_date=nil
|
49
41
|
if end_date.nil? && !start_date.is_a?(Timespan)
|
50
42
|
timespan = Timespan.day_end start_date
|
51
|
-
end_date = timespan.finish
|
52
|
-
start_date = timespan.start
|
53
43
|
end
|
54
44
|
if start_date.is_a? Timespan
|
55
45
|
timespan = start_date
|
56
|
-
end_date = start_date.finish
|
57
|
-
start_date = start_date.start
|
58
46
|
end
|
59
|
-
|
60
|
-
|
61
|
-
occurrences = events.map do |e|
|
62
|
-
e.occurrences(:overlapping => [start_date, end_date])
|
47
|
+
if start_date && end_date
|
48
|
+
timespan = Timespan.new start_date, end_date
|
63
49
|
end
|
64
50
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
event
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
51
|
+
events_in_time = @calendars.map.with_index do |calendar, idx|
|
52
|
+
# Collect Kalindar::Events in that time
|
53
|
+
events = calendar.events.map do |event|
|
54
|
+
occurrences_in(event, timespan).map {|e| Kalindar::Event.new e }
|
55
|
+
end.flatten
|
56
|
+
|
57
|
+
# Set modification and calendar field.
|
58
|
+
is_first = idx == 0
|
59
|
+
events.each do |e|
|
60
|
+
e.modifiable = is_first
|
61
|
+
e.calendar = calendar
|
75
62
|
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
63
|
+
events
|
64
|
+
end.flatten
|
65
|
+
|
66
|
+
# Collect occurences by date.
|
67
|
+
unfold_dates events_in_time, timespan
|
79
68
|
end
|
80
69
|
|
81
70
|
def find_by_uid uuid
|
@@ -115,4 +104,21 @@ class EventCalendar
|
|
115
104
|
incl = event.dtstart.class == event.dtend.class && event.dtstart.class == Icalendar::Values::DateTime && (date_between?(date, event.dtstart, event.dtend))
|
116
105
|
incl
|
117
106
|
end
|
107
|
+
|
108
|
+
# List occurrences in timespan
|
109
|
+
def occurrences_in event, timespan
|
110
|
+
event.occurrences(:overlapping => [timespan.start, timespan.finish])
|
111
|
+
end
|
112
|
+
|
113
|
+
# Make hash with one entry per day and event that lies in timespan
|
114
|
+
def unfold_dates events, timespan
|
115
|
+
events.inject({}) do |hash, event|
|
116
|
+
(event.dtstart.to_date .. event.dtend.to_date).each do |day|
|
117
|
+
if timespan.spans?(day) && !(event.dtstart != event.dtend && event.dtend.class == Date && event.dtend == day)
|
118
|
+
(hash[day] ||= []) << event
|
119
|
+
end
|
120
|
+
end
|
121
|
+
hash
|
122
|
+
end
|
123
|
+
end
|
118
124
|
end
|
@@ -1,22 +1,18 @@
|
|
1
1
|
#main a{
|
2
2
|
font-size: smaller;
|
3
|
+
width: 100%;
|
3
4
|
}
|
4
5
|
.dayname {
|
5
6
|
font-size: larger;
|
6
7
|
margin: 0 0 0 0;
|
7
8
|
padding: 0 0 0 0;
|
8
9
|
border-bottom: solid 1px black;
|
9
|
-
background-image: -moz-linear-gradient(
|
10
|
-
center top,
|
11
|
-
rgb(180,180,180) 0%,
|
12
|
-
rgb(220,220,220) 100%
|
13
|
-
);
|
14
10
|
}
|
15
11
|
ul.day_list {
|
16
12
|
list-style: none;
|
17
13
|
padding-left: 0em;
|
18
14
|
margin-left: 0.3em;
|
19
|
-
width:
|
15
|
+
width: 100%;
|
20
16
|
margin-top: 0.1em;
|
21
17
|
margin-bottom: 0.1em;
|
22
18
|
}
|
@@ -28,27 +24,17 @@ li.day {
|
|
28
24
|
border-right: solid 1px;
|
29
25
|
background-color: #F4F4F4;
|
30
26
|
margin-bottom: 0.5em;
|
31
|
-
background-image: -webkit-gradient(
|
32
|
-
linear,
|
33
|
-
left top,
|
34
|
-
left bottom,
|
35
|
-
color-stop(0.5, rgb(221,221,221)),
|
36
|
-
color-stop(0.5, rgb(255,255,255))
|
37
|
-
);
|
38
|
-
background-image: -moz-linear-gradient(
|
39
|
-
center top,
|
40
|
-
rgb(221,221,221) 50%,
|
41
|
-
rgb(255,255,255) 50%
|
42
|
-
);
|
43
|
-
-moz-box-shadow: inset 0 0 10px #000000;
|
44
|
-
box-shadow: inset 0 0 10px #000000;
|
45
27
|
}
|
46
28
|
|
47
29
|
li.saturday {
|
48
30
|
border-top: solid 1px;
|
49
31
|
border-bottom: solid 1px;
|
50
32
|
background-color: #DADAEE;
|
51
|
-
margin-bottom:
|
33
|
+
margin-bottom: 0.5em;
|
34
|
+
/*
|
35
|
+
margin-left: 0.5em;
|
36
|
+
margin-right: 0.5em;
|
37
|
+
*/
|
52
38
|
}
|
53
39
|
|
54
40
|
li.sunday {
|
@@ -56,6 +42,10 @@ li.sunday {
|
|
56
42
|
border-bottom: solid 1px;
|
57
43
|
background-color: #BBBBEE;
|
58
44
|
margin-bottom: 3em;
|
45
|
+
/*
|
46
|
+
margin-left: 0.5em;
|
47
|
+
margin-right: 0.5em;
|
48
|
+
*/
|
59
49
|
}
|
60
50
|
|
61
51
|
ul.event_list {
|
@@ -72,35 +62,29 @@ ul.event_list {
|
|
72
62
|
ul.event_list li {
|
73
63
|
margin-left: 0.1em;
|
74
64
|
clear: both;
|
75
|
-
background-image: -webkit-gradient(
|
76
|
-
linear,
|
77
|
-
left top,
|
78
|
-
left bottom,
|
79
|
-
color-stop(0.5, rgb(000,221,221)),
|
80
|
-
color-stop(0.5, rgb(255,255,255))
|
81
|
-
);
|
82
|
-
background-image: -moz-linear-gradient(
|
83
|
-
center top,
|
84
|
-
rgb(180,180,180) 0%,
|
85
|
-
rgb(220,220,220) 100%
|
86
|
-
);
|
87
65
|
}
|
88
66
|
|
89
67
|
#event {
|
90
|
-
margin-left: 0.
|
68
|
+
margin-left: 0.2em;
|
91
69
|
}
|
92
70
|
|
93
71
|
#time {
|
94
72
|
float: left;
|
95
73
|
font-size: smaller;
|
96
|
-
|
97
|
-
width: 6.8em;
|
98
|
-
*/
|
74
|
+
margin-right: 0.2em;
|
99
75
|
}
|
100
76
|
|
101
77
|
#summary {
|
78
|
+
margin-left: 0.2em;
|
102
79
|
font-weight: bold;
|
80
|
+
font-size: 90%;
|
81
|
+
/*
|
103
82
|
text-align: center;
|
83
|
+
*/
|
84
|
+
}
|
85
|
+
|
86
|
+
.new_event_mask {
|
87
|
+
margin-left: 1.5em;
|
104
88
|
}
|
105
89
|
|
106
90
|
.hidden_new_event_mask {
|
@@ -114,6 +98,12 @@ ul.event_list li {
|
|
114
98
|
font-size: 80%;
|
115
99
|
}
|
116
100
|
|
101
|
+
#show_new_event_link {
|
102
|
+
text-align: left;
|
103
|
+
width: 80%;
|
104
|
+
margin-left: 0.2em;
|
105
|
+
}
|
106
|
+
|
117
107
|
#edit_event_link {
|
118
108
|
margin-left: 1em;
|
119
109
|
}
|
data/lib/kalindar/timespan.rb
CHANGED
@@ -3,11 +3,16 @@ require 'time'
|
|
3
3
|
class Timespan
|
4
4
|
attr_accessor :start
|
5
5
|
attr_accessor :finish
|
6
|
+
|
6
7
|
def initialize start, finish
|
7
8
|
@start = start
|
8
9
|
@finish = finish
|
9
10
|
end
|
10
11
|
|
12
|
+
def spans? date
|
13
|
+
@start <= date && @finish >= date
|
14
|
+
end
|
15
|
+
|
11
16
|
def self.from_day date
|
12
17
|
start = DateTime.new date.year, date.month, date.day, 0, 0
|
13
18
|
finish = DateTime.new date.year, date.month, date.day, 23, 59
|
data/lib/kalindar/version.rb
CHANGED
@@ -1,29 +1,31 @@
|
|
1
1
|
ul.day_list
|
2
|
-
- @events.each do |day
|
2
|
+
- @events.keys.sort.each do |day|
|
3
|
+
- evs = @events[day]
|
3
4
|
li class=li_day_class(day)
|
4
5
|
.dayname
|
5
6
|
| #{t(:"date.day.day_names")[day.wday-1]} #{l day, :format => :short}
|
7
|
+
small
|
8
|
+
a#show_new_event_link href="/event/new/#{day.strftime('%Y%m%d')}" #{t 'create_event'}
|
6
9
|
input#day_hidden_input type="hidden" name="day" value="#{day.strftime('%Y%m%d')}"
|
7
|
-
a#show_new_event_link href="/event/new/#{day.strftime('%Y%m%d')}" #{t 'create_event'}
|
8
10
|
.new_event_mask style="display: none;"
|
9
11
|
.hidden_new_event_mask
|
10
12
|
== slim :new_event, :layout => false, :locals => {'start_date' => day.strftime("%Y%m%d")}
|
11
13
|
ul.event_list
|
12
|
-
- evs.each do |ev|
|
14
|
+
- evs.sort_by{|e|e.start_time}.each do |ev|
|
13
15
|
li#event_day
|
14
16
|
#event
|
15
17
|
#time
|
16
18
|
| #{ev.time_f day}
|
17
19
|
- if ev.location && !ev.location.empty?
|
18
20
|
| [#{ev.location}]
|
19
|
-
br
|
20
21
|
#summary
|
21
|
-
|
22
|
-
|
22
|
+
| #{ev.summary}
|
23
|
+
- if ev.modifiable?
|
24
|
+
a#edit_event_link href="/event/edit/#{ev.uid}" = t 'edit'
|
23
25
|
#hidden_description
|
24
26
|
| (#{ev.from_to_f})
|
25
27
|
br
|
26
28
|
| #{ev.description}
|
27
|
-
hr(width="20%")
|
29
|
+
/hr(width="20%")
|
28
30
|
#nav
|
29
31
|
|
data/spec/kalindar_spec.rb
CHANGED
@@ -69,6 +69,8 @@ describe EventCalendar do
|
|
69
69
|
it 'wraps in Event Delegate' do
|
70
70
|
events = subject.events_in endjuly
|
71
71
|
expect(events.values.flatten.collect{|e| e.is_a? Kalindar::Event}.length).to eq events.values.flatten.length
|
72
|
+
expect(events.values.flatten[0].modifiable?).to eql true
|
73
|
+
expect(events.values.flatten[0].calendar.class).to eql Calendar
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
@@ -99,6 +101,10 @@ describe "Event" do
|
|
99
101
|
cal = EventCalendar.new 'spec/testcal.ics'
|
100
102
|
cal.find_by_uid("4a129461-cd74-4b3a-a307-faa1e8846cc2")
|
101
103
|
}
|
104
|
+
subject(:daily_event) {
|
105
|
+
cal = EventCalendar.new 'spec/testcal.ics'
|
106
|
+
cal.find_by_uid("d7844d09-75d9-4a8b-a1de-453fe63d6415")
|
107
|
+
}
|
102
108
|
|
103
109
|
describe "#start_time_f" do
|
104
110
|
it "returns the time if given day is start day" do
|
@@ -107,6 +113,12 @@ describe "Event" do
|
|
107
113
|
end
|
108
114
|
end
|
109
115
|
|
116
|
+
describe "#modifiable?" do
|
117
|
+
it 'makes non-recuring events modifiable' do
|
118
|
+
expect(multiday_event.modifiable?).to eql false
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
110
122
|
describe "#finish_time_f" do
|
111
123
|
it "returns the time if given day is end day" do
|
112
124
|
expect(events[0].finish_time_f Date.new(2014, 8, 27)).to eq "..."
|
@@ -147,3 +159,12 @@ describe "Event" do
|
|
147
159
|
end
|
148
160
|
end
|
149
161
|
end
|
162
|
+
|
163
|
+
describe Timespan do
|
164
|
+
describe "#spans?" do
|
165
|
+
it 'works with dates' do
|
166
|
+
today = Date.today
|
167
|
+
expect(Timespan.new(today, today + 4).spans? today + 3).to eql true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kalindar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Wolfsteller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ri_cal
|