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 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