kalindar 0.2.1 → 0.3.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.
- 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
|