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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZWU3MDYxNDY1NDhmMjQ1MTcxZDgxNDgwNGY4NDcxNDJiYTk3NGM1MQ==
4
+ YWY4OWRmOTQ0N2YwYWQzM2U1YjMwYjQ0NGY0Y2FlYjE5MTk4Yjg2NQ==
5
5
  data.tar.gz: !binary |-
6
- ZmMzMzNkNmMyOGMyYmEyYWU1MzQyY2EwYmQyZDQyMGQ5MmM1N2UzOA==
6
+ MjJhYzQwYTA5MDUxYzU5NGVkM2FkM2NkZjBlMDQ2YzhjNjZiMjk1Yg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MzQ3M2Q5ZTFhZGNhMmExYTkzOTNjZmQ0NWVhMzkxZGY1OTdjZjNkYmNjYTY4
10
- NDA1ZmM1YjkwZmVmNDY4ZmYxMzRmN2Y2MTk3NmFlYzVlMmQ1Nzk4NzliOWRj
11
- ZjMzMjA3ZDFmNTkzZGM0M2VlZDI4ZjlhMTdkN2IxYTQ2NjZlZTg=
9
+ ODdiMTExNTk1YzQyOTM3MTQ1ZWNjOTM5MmZlMDg1MDZjMjU3M2Y0ZGY4MWE4
10
+ ZmE1NTY2OGRkMjNkNWJhOGFiOTQ4NjQ5ZjdlNjJjNjc4NDk3NzYxZWEwNWYz
11
+ OWNjNjNkYjBjMjdjNjA1YTIwYzJhNTQ2ODY5MDZlZDgzNjMzM2Q=
12
12
  data.tar.gz: !binary |-
13
- ZWI4OWM2NTZkNDY4YWQyZjk0OWU5ZGJkYjFkOGVjNTc0NTUzYjM5ODVkNzli
14
- MzlkMjZlMzM0OGM2NDNhYzZjMDNiYjA5MmJjYmY4MjA3OWM1MDM1NjNkODVl
15
- NTI3ZGI3MjQwMzgzMzQxZjIzOGU0NjZmZjY1MzRlYjJkNjQ0YWY=
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 gets confused by re-occuring events, they are shown, but better do not modify.
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
 
@@ -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
- # Pre-fill hash
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(DateTime.now, DateTime.now + 30)
87
+ @events = $cal.events_in(Date.today, Date.today + 30)
82
88
 
83
- # Pre-fill hash
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 DateTime.now, DateTime.now + 2
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
- (DateTime.now .. DateTime.now + 30).each do |day|
123
- @events[day] = $cal.find_events day.to_date
124
- end
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
- (DateTime.now .. DateTime.now + 30).each do |day|
173
- #@events[d] = $cal.events_for(d)
174
- # bring chosen calendars into equation
175
- @events[day] = $cal.find_events day.to_date
176
- end
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
@@ -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
- # Catches only certain events
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
- # All overlapping occurences.
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
- # Collect occurences by date.
66
- hash = occurrences.inject({}) do |hsh, o|
67
- o.each do |oc|
68
- event = Kalindar::Event.new(oc)
69
- (oc.dtstart.to_date .. oc.dtend.to_date).each do |day|
70
- # Strip timerange and exclude one-and-whole-day events (they "end" next day).
71
- if day >= start_date && day <= end_date && !(oc.dtstart != oc.dtend && oc.dtend.class == Date && oc.dtend == day)
72
- (hsh[day] ||= []) << event
73
- end
74
- end
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
- hsh
77
- end
78
- hash
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: 18em;
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: 1em;
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.4em;
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
  }
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Kalindar
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -1,29 +1,31 @@
1
1
  ul.day_list
2
- - @events.each do |day, evs|
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
- | #{ev.summary}
22
- a#edit_event_link href="/event/edit/#{ev.uid}" = t 'edit'
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
 
@@ -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.2.1
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-27 00:00:00.000000000 Z
11
+ date: 2014-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ri_cal