kalindar 0.0.1 → 0.1.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
- YjgyYTE3M2NkOTJiODk5NTcxNTkyZjFkODA4NTMyNDlkZmQ3NGFmMw==
4
+ NDY4ODFlYzA2NjAxZjdjZGU1YzdjM2Q1ZDA0OTZkNTA1NTRmMTFlYw==
5
5
  data.tar.gz: !binary |-
6
- YzMyYzI1NTVmNWMyODUxZjljMWRmZjU0NmM5MWFlZTg3ZjM1NzVlMQ==
6
+ NzkxNTk3ODk1ZjI4NDQ2ODJiMzJiNTI3OTE5YTA5NGQ5NDZhMzUwNQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MzNjNDFkNzYzM2EyOTgyODIwMTk5MTkzNDEyNzBhNDc2NWYxODQzZWQ4YTE1
10
- ZjgxNjQ2YTk2OTRkN2M3MjZmNjFiNzI0NGMxNDhjYzM3YjY1Zjk4ZjNmYzY0
11
- YTQwNjQxYTU3YjIzNDA5MzMzZjRhNmJkOTkxZDNmYWM4NTY2M2U=
9
+ ZGZjMTJkYTZjMzY2ZWMzMjlkZjU2ZGQyMmQ1NGU3NGZlZDQ1ZDI4YmQ2MGVl
10
+ ZDVlZmE4YmY2ZTgyODgwNmE0NDczODgzOGNkNDlkY2M4ZDIzMTc1MTdmNjNj
11
+ YmE5NDgyMzc1MWNhNGJmMDlmNjQ4NjM4ZDlmNWExYzE5YzJiZGY=
12
12
  data.tar.gz: !binary |-
13
- OTI4MjAyYzYwOWQ3ZTgzMGZkZGZjNzBjMzQzNzk2MzY4ZTM1OWFiNTNjNzA0
14
- ZDc4Y2E4N2ZhZTc0OWMzMDcyOWUzYWYzYTMxMzkwZWM0OTJkNTZmNDBiNzlj
15
- MTVlNGVkZmVkZDhhYTA2Zjg5NWQ5YTNiYzFmMDdkMjFlOTBhMWU=
13
+ Njk3YzdhMmFhYjNiYjNjNTc3OWU0ZjU2NDcwYTJlOGUzZTU3ODM3MTY0MWE3
14
+ MzdkOTMyY2RmYTk2OWY3NDQxNjViNjYzZjQyOWI3MGYyMGQzOTRmYWJlZDQ0
15
+ YzkyNjI1ZjExMjg4MjIyMTFjZTRlZDI5OTFiMWI0YmM2NTBiNTI=
data/Procfile ADDED
@@ -0,0 +1 @@
1
+ web: bundle exec rackup config.ru -p $PORT
data/kalindar.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["felix.wolfsteller@gmail.com"]
11
11
  spec.summary = %q{Web-Interface to ics files}
12
12
  spec.description = %q{Web-Interface to ics files with sinatra}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/fwolfst/kalindar"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
data/lib/kalindar.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  require "kalindar/version"
2
+ require 'kalindar/event'
3
+ require 'kalindar/calendar'
2
4
  require 'kalindar/event_calendar'
3
5
  require 'kalindar/app'
4
- require 'kalindar/event'
5
6
 
6
7
  module Kalindar
7
8
  # Your code goes here...
data/lib/kalindar/app.rb CHANGED
@@ -1,10 +1,12 @@
1
- require 'sinatra/base'
2
- require 'slim'
3
1
  require 'time'
4
2
  require 'json'
3
+ require 'securerandom'
4
+ require 'sinatra/base'
5
+ require 'slim'
5
6
  require 'i18n'
6
7
  require 'i18n/backend/fallbacks'
7
8
 
9
+ # Sinatra App for Kalindar, show ics files.
8
10
  class KalindarApp < Sinatra::Base
9
11
  $conf = JSON.load(File.new('config.json'))
10
12
  $cal = EventCalendar.new($conf['calendar_files'])
@@ -22,6 +24,9 @@ class KalindarApp < Sinatra::Base
22
24
  # We like pretty html indentation
23
25
  set :slim, :pretty => true
24
26
 
27
+ # Allow inclusion in iframe.
28
+ set :protection, :except => :frame_options
29
+
25
30
  helpers do
26
31
  def li_day_class day
27
32
  return "sunday" if day.sunday?
@@ -40,6 +45,17 @@ class KalindarApp < Sinatra::Base
40
45
  redirect '/events'
41
46
  end
42
47
 
48
+ get '/events/:year/:month' do
49
+ @events = {}
50
+ # Events from start time to 31 days later
51
+ date = Date.new(params[:year].to_i, params[:month].to_i, 1)
52
+ (date .. date + 30).each do |day|
53
+ #@events[d] = $cal.events_for(d)
54
+ @events[day] = $cal.find_events day.to_date
55
+ end
56
+ slim :event_list
57
+ end
58
+
43
59
  get '/events' do
44
60
  @events = {}
45
61
  # events from today to in 30 days
@@ -50,51 +66,75 @@ class KalindarApp < Sinatra::Base
50
66
  slim :event_list
51
67
  end
52
68
 
53
- # Create DateTime from yyyymmdd + h + m .
54
- def start_time_from_params params
55
- hour = params['start_time'][/\d\d/].to_i
56
- minute = params['start_time'][/:\d\d/][1,2].to_i
57
- start_day = Date.parse(params['start_day'])
58
- start_time = DateTime.new(start_day.year,
59
- start_day.month, start_day.day, hour, minute)
60
- end
61
-
62
- # Adds minutes to start_time.
63
- def end_time_from_params params, start_time
64
- minutes = case params['duration']
65
- when '15m' then 15
66
- when '30m' then 30
67
- when '60m' then 60
68
- when '90m' then 90
69
- when '120m' then 120
70
- when '1d' then 24 * 60
71
- when '2d' then 24 * 2 * 60
72
- when '5d' then 24 * 5 * 60
73
- when '1w' then 24 * 7 * 60
74
- end
75
- start_time + Rational(minutes, 1440)
69
+ get '/events/twoday' do
70
+ @events = {}
71
+ # events from today to in 30 days
72
+ (DateTime.now .. DateTime.now + 30).each do |day|
73
+ #@events[d] = $cal.events_for(d)
74
+ @events[day] = $cal.find_events day.to_date
75
+ end
76
+ @events = @events.values.flatten.sort_by {|e| e.start_time}
77
+ slim :twoday_list
76
78
  end
77
79
 
78
- # Add event, save ics file.
80
+ # Add new event, save ics file.
79
81
  put '/event' do
80
- event = RiCal::Component::Event.new($cal.calendars.first)
81
- start_time = start_time_from_params params
82
- event.dtstart = start_time
83
- event.dtend = end_time_from_params params, start_time
84
- event.summary = params['summary']
85
- event.description = params['description']
86
- event.location = params['location']
87
-
88
- # Motivate Calendar Delegate
82
+ errors = EventParamHelper.check_params params
83
+ if !errors.empty?
84
+ slim :new_event, :locals => {'start_date' => Date.parse(params[:start_day])}
85
+ end
86
+ begin
87
+ event = Event.create_from_params params
88
+ rescue
89
+ return 502, "Eingabefehler"
90
+ end
91
+
89
92
  $cal.calendars.first.events << event
90
- io = File.open($cal.filename_of($cal.calendars.first), 'w')
91
- $cal.calendars.first.export_to io
92
- io.close
93
+ $cal.calendars.first.write_back!
93
94
 
94
- redirect back
95
+ if request.xhr?
96
+ @events = {}
97
+ # Events from today to in 30 days
98
+ (DateTime.now .. DateTime.now + 30).each do |day|
99
+ @events[day] = $cal.find_events day.to_date
100
+ end
101
+ slim :event_list, :layout => false
102
+ else
103
+ redirect '/'
104
+ end
95
105
  end
96
106
 
107
+ # Show new event template.
97
108
  get '/event/new/:day' do
98
- slim :new_event, :locals => {'start_date' => nil}
109
+ # Aim is to get a new event in every case
110
+ #@event = Event.create_from_params params
111
+ @event = Event.new(RiCal::Component::Event.new($cal.calendars.first))
112
+ @event.dtstart = Date.parse(params[:day])
113
+ slim :new_event, :locals => {'start_date' => Date.parse(params[:day])}
114
+ end
115
+
116
+ # Yet empty route.
117
+ get '/event/delete/:uuid' do
118
+ redirect back
119
+ end
120
+
121
+ # Show edit view.
122
+ get '/event/edit/:uuid' do
123
+ event = $cal.find_by_uid params[:uuid]
124
+ if event.nil?
125
+ redirect back
126
+ else
127
+ slim :edit_event, :locals => {'event' => event}
128
+ end
129
+ end
130
+
131
+ # Edit/save an event.
132
+ put '/event/edit/:uuid' do
133
+ # validate_params
134
+ puts params
135
+ event = $cal.find_by_uid(params[:uuid])
136
+ event.update params
137
+ $cal.calendars.first.write_back!
138
+ redirect '/'
99
139
  end
100
140
  end
@@ -0,0 +1,12 @@
1
+ require 'delegate'
2
+
3
+ # Delegator with some handy shortcuts
4
+ class Calendar < SimpleDelegator
5
+ attr_accessor :filename
6
+ # Write 'back' to file.
7
+ def write_back!
8
+ File.open(@filename, 'w') do |file|
9
+ export_to file
10
+ end
11
+ end
12
+ end
@@ -1,24 +1,139 @@
1
+ require 'delegate'
2
+
1
3
  # Delegator with some handy shortcuts
2
4
  class Event < SimpleDelegator
5
+ # Time it starts at day, or '...'
3
6
  def start_time_f day
4
- puts "start #{start_time} : #{start_time.class} #{start_time.to_date} #{day}"
5
- return start_time.strftime('%H:%M') if start_time.to_date == day.to_date
6
- return "..."
7
+ #puts "start #{start_time} : #{start_time.class} #{start_time.to_date} #{day}"
8
+ if dtstart.class == Date
9
+ # whole day
10
+ ""
11
+ elsif start_time.to_date == day.to_date
12
+ start_time.strftime('%H:%M')
13
+ else
14
+ "..."
15
+ end
7
16
  end
17
+
18
+ # Time it finishes at day, or '...'
8
19
  def finish_time_f day
9
- return finish_time.strftime('%H:%M') if finish_time.to_date == day.to_date
10
- return "..."
20
+ if dtend.class == Date
21
+ # whole day
22
+ ""
23
+ elsif finish_time.to_date == day.to_date
24
+ finish_time.strftime('%H:%M')
25
+ else
26
+ return "..."
27
+ end
11
28
  end
29
+
30
+ # Time it finishes and or starts at day, or '...'
12
31
  def time_f day
13
32
  start = start_time_f day
14
33
  finish = finish_time_f day
15
- if start == finish && start == "..."
34
+ if start == finish && start == ""
35
+ # whole day
36
+ ""
37
+ elsif start == finish && start == "..."
16
38
  "..."
17
39
  else
18
40
  "#{start_time_f day} - #{finish_time_f day}"
19
41
  end
20
42
  end
43
+
44
+ # Date and time from and to
21
45
  def from_to_f
22
46
  return "#{dtstart.to_datetime.strftime("%d.%m. %H:%M")} - #{dtend.to_datetime.strftime("%d.%m. %H:%M")}"
23
47
  end
48
+
49
+ # Create DateTime from yyyymmdd + h + m .
50
+ def self.start_time_from_params params
51
+ start_day = Date.parse(params['start_day'])
52
+ if !params[:start_time]
53
+ return start_day
54
+ end
55
+
56
+ hour, minute = params[:start_time].match(/(\d\d):(\d\d)/)[1,2]
57
+ start_time = DateTime.new(start_day.year,
58
+ start_day.month, start_day.day, hour.to_i, minute.to_i)
59
+ end
60
+
61
+ def self.start_date_from params
62
+ Date.parse(params['start_day'])
63
+ end
64
+
65
+
66
+ def update params
67
+ begin
68
+ hour, minute = params['start_time'].match(/(\d\d):(\d\d)/)[1,2]
69
+ start_day = Date.parse(params['start_day'])
70
+ start_time = DateTime.new(start_day.year,
71
+ start_day.month, start_day.day, hour.to_i, minute.to_i)
72
+ self.dtstart = start_time
73
+ minutes = EventParamHelper.duration params['duration']
74
+ self.dtend = start_time + Rational(minutes, 1440)
75
+ rescue => e
76
+ STDERR.puts "event#update params: problems with (up)date #{e.message}"
77
+ end
78
+
79
+ self.summary = params['summary'] if params['summary']
80
+ self.description = params['description'] if params['description']
81
+ self.location = params['location'] if params['location']
82
+ end
83
+
84
+ # Create a new event from params as given by new_event form of kalindar.
85
+ # this should eventually go somewhere else, but its better here than in app already.
86
+ def self.create_from_params params
87
+ event = RiCal::Component::Event.new($cal.calendars.first)
88
+ event.uid = SecureRandom.uuid
89
+ if params['summary']
90
+ event.summary = params['summary']
91
+ end
92
+ if params['description']
93
+ event.description = params['description']
94
+ end
95
+ if params['location']
96
+ event.location = params['location']
97
+ end
98
+
99
+ # Access should be made failsafe.
100
+ start_time = start_time_from_params(params)
101
+ event.dtstart = start_time
102
+ minutes = EventParamHelper.duration params['duration']
103
+ event.dtend = start_time + Rational(minutes, 1440)
104
+ Event.new event
105
+ end
106
+
107
+ private
108
+ end
109
+
110
+ module EventParamHelper
111
+
112
+ # minutes for abbrevations
113
+ @@duration_param = {
114
+ '15m' => 15,
115
+ '30m' => 30,
116
+ '60m' => 60,
117
+ '90m' => 90,
118
+ '120m' => 120,
119
+ '1d' => 24 * 60,
120
+ '2d' => 24 * 2 * 60,
121
+ '5d' => 24 * 5 * 60,
122
+ '1w' => 24 * 7 * 60
123
+ }
124
+ def self.duration duration_p
125
+ # throw
126
+ @@duration_param[duration_p]
127
+ end
128
+
129
+ def self.check_params params
130
+ errors = {}
131
+ if not(params[:start_time] =~ /\d\d:\d\d/)
132
+ errors[:start_time] = ''
133
+ end
134
+ if not(duration params[:duration])
135
+ errors[:duration] = ''
136
+ end
137
+ errors
138
+ end
24
139
  end
@@ -1,26 +1,36 @@
1
1
  require 'ri_cal'
2
+ require 'kalindar/calendar'
2
3
 
4
+ # Public facing methods should return Event Decorators,
5
+ # private methods can return "raw" RiCal::Component::Event s.
3
6
  class EventCalendar
4
7
  attr_accessor :calendars
5
- attr_accessor :filenames # decorator?
6
- # also decoreate event for access to calendar?
7
8
 
9
+ # Given filename or array of filenames, initialize the calendar.
8
10
  def initialize filename
9
11
  @calendars = []
10
- @filenames = []
11
12
  if filename.class == Array
12
- filename.each {|file| read_file file}
13
+ filename.each {|file| read_file file, true}
13
14
  else
14
- read_file filename
15
+ read_file filename, true
15
16
  end
16
17
  end
17
18
 
18
- def read_file filename
19
+ # Opens calendar
20
+ # param: create if true, create empty calendar file if not existant.
21
+ def read_file filename, create
22
+ if create && !File.exist?(filename)
23
+ File.open(filename, 'w') do |file|
24
+ (RiCal::Component::Calendar.new).export_to file
25
+ end
26
+ end
19
27
  @calendars << File.open(filename, 'r') do |file|
20
28
  RiCal.parse file
21
- end.flatten
22
- # attention if more than one calendar in file!
23
- @filenames << filename
29
+ end.flatten.map do |calendar|
30
+ c = Calendar.new calendar
31
+ c.filename = filename
32
+ c
33
+ end
24
34
  @calendars.flatten!
25
35
  end
26
36
 
@@ -59,19 +69,33 @@ class EventCalendar
59
69
  events.flatten
60
70
  end
61
71
 
72
+ # Find (non-recuring) events that begin, end or cover the given day.
62
73
  def find_events date
63
74
  #events = @calendars.map &:events
64
75
  @calendars.map do |calendar|
65
76
  calendar.events.select { |event|
66
- event.dtstart.to_date == date || event.dtend.to_date == date ||!event.occurrences(:overlapping => [date, date +1]).empty?
77
+ # If end-date is a Date (vs DateTime) let it be
78
+ # All day/multiple day events
79
+ if event.dtstart.class == Date && event.dtend.class == Date
80
+ event.dtstart.to_date == date || (event.dtstart < date && event.dtend > date)
81
+ else
82
+ event.dtstart.to_date == date || event.dtend.to_date == date || (event.dtstart < date && event.dtend > date)
83
+ # occurrences need to be re-enabled
84
+ #||!event.occurrences(:overlapping => [date, date +1]).empty?
85
+ end
67
86
  }
68
87
  end.flatten.map do |event|
69
88
  Event.new event
70
89
  end
90
+ # check flat_map enumerable method
71
91
  end
72
92
 
73
- def filename_of calendar
74
- @filenames[@calendars.index calendar]
93
+ def find_by_uid uuid
94
+ # we want to pick only the first! whats the method? detect is one, find another
95
+ @calendars.map(&:events).flatten.each do |event|
96
+ return Event.new(event) if event.uid == uuid
97
+ end
98
+ nil
75
99
  end
76
100
 
77
101
  private
@@ -81,13 +105,13 @@ class EventCalendar
81
105
  end
82
106
 
83
107
  def dtmonth_end year, month
84
- puts "last date for #{year} - #{month}"
108
+ #puts "last date for #{year} - #{month}"
85
109
  last_day = Date.civil(year, month, -1)
86
110
  Icalendar::Values::Date.new('20120102')#"#{year}#{month}#{last_day}")
87
111
  end
88
112
 
89
113
  def date_between? date, start_date, end_date
90
- puts "d #{date} st #{start_date} e #{end_date}"
114
+ #puts "d #{date} st #{start_date} e #{end_date}"
91
115
  date > start_date && date < end_date
92
116
  end
93
117
 
@@ -96,7 +120,8 @@ class EventCalendar
96
120
  end
97
121
 
98
122
  def event_includes? event, date
99
- event.dtstart.class == event.dtend.class && event.dtstart.class == Icalendar::Values::DateTime && (date_between?(date, event.dtstart, event.dtend))
123
+ incl = event.dtstart.class == event.dtend.class && event.dtstart.class == Icalendar::Values::DateTime && (date_between?(date, event.dtstart, event.dtend))
124
+ incl
100
125
  end
101
126
  end
102
127
 
@@ -1,6 +1,8 @@
1
1
  de:
2
2
  create_event: "Neuer Termin"
3
3
  new_event: "Neuer Termin"
4
+ edit: "ändern"
5
+ edit_event: "Termin ändern"
4
6
  start_date: "Anfangsdatum"
5
7
  when: "Uhrzeit"
6
8
  summary: "Titel"
@@ -19,6 +21,22 @@ de:
19
21
  5d: "5 Tage"
20
22
  1w: "eine Woche"
21
23
  save: "speichern"
24
+ cancel: "abbrechen"
22
25
  time:
23
26
  formats:
24
27
  short: "%d.%m.%Y"
28
+ hm: "%H:%M"
29
+ # Seems better option for names (with e.g. %a)
30
+ # http://blog.lingohub.com/developers/2013/08/internationalization-for-ruby-i18n-gem/
31
+ date:
32
+ day:
33
+ day_names:
34
+ - Montag
35
+ - Dienstag
36
+ - Mittwoch
37
+ - Donnerstag
38
+ - Freitag
39
+ - Samstag
40
+ - Sonntag
41
+ formats:
42
+ short: "%d.%m.%Y"
@@ -1,6 +1,8 @@
1
1
  en:
2
2
  create_event: "New Event"
3
3
  new_event: "New Event"
4
+ edit: "edit"
5
+ edit_event: "edit event"
4
6
  start_date: "Start Date"
5
7
  when: "Time"
6
8
  summary: "Summary"
@@ -19,6 +21,20 @@ en:
19
21
  5d: "5 days"
20
22
  1w: "a week"
21
23
  save: "save"
24
+ cancel: "cancel"
22
25
  time:
23
26
  formats:
24
27
  short: "%Y/%m/%d"
28
+ hm: "%H:%M"
29
+ date:
30
+ day:
31
+ day_names:
32
+ - Monday
33
+ - Tuesday
34
+ - Wednesday
35
+ - Thursday
36
+ - Friday
37
+ - Saturday
38
+ - Sunday
39
+ formats:
40
+ short: "%Y/%m/%d"
@@ -1,46 +1,56 @@
1
+ #main a{
2
+ font-size: smaller;
3
+ }
4
+ .dayname {
5
+ font-size: larger;
6
+ margin: 0 0 0 0;
7
+ padding: 0 0 0 0;
8
+ border-bottom: solid 1px black;
9
+ }
1
10
  ul.day_list {
2
11
  list-style: none;
3
- border-top: solid 1px;
4
- border-left: solid 1px;
5
- border-right: solid 1px;
6
- background-color: #FEEEFE;
7
12
  padding-left: 0em;
8
13
  margin-left: 0.3em;
9
14
  width: 18em;
15
+ margin-top: 0.1em;
16
+ margin-bottom: 0.1em;
10
17
  }
11
18
 
12
19
  li.day {
13
20
  border-top: solid 1px;
21
+ border-bottom: solid 1px;
14
22
  border-left: solid 1px;
15
- background-color: #EEEEEE;
23
+ border-right: solid 1px;
24
+ background-color: #F4F4F4;
25
+ margin-bottom: 0.5em;
16
26
  }
17
27
 
18
28
  li.saturday {
19
29
  border-top: solid 1px;
20
- border-left: solid 1px;
30
+ border-bottom: solid 1px;
21
31
  background-color: #DADAEE;
32
+ margin-bottom: 1em;
22
33
  }
23
34
 
24
35
  li.sunday {
25
36
  border-top: solid 1px;
26
- border-left: solid 1px;
37
+ border-bottom: solid 1px;
27
38
  background-color: #BBBBEE;
39
+ margin-bottom: 3em;
28
40
  }
29
41
 
30
42
  ul.event_list {
31
43
  list-style: none;
32
- border-top: solid 1px;
33
- border-bottom: solid 1px;
34
44
  background-color: #FEFEFE;
35
- margin-left: 0.5em;
36
45
  padding-left: 0.5em;
37
- padding-right: 0em;
46
+ padding-right: 0.5em;
38
47
  padding-top: 0em;
39
48
  padding-bottom: 0em;
49
+ margin-top: 0.1em;
50
+ margin-bottom: 0.1em;
40
51
  }
41
52
 
42
53
  ul.event_list li {
43
- border-bottom: solid 1px;
44
54
  margin-left: 0.1em;
45
55
  clear: both;
46
56
  }
@@ -51,11 +61,15 @@ ul.event_list li {
51
61
 
52
62
  #time {
53
63
  float: left;
64
+ font-size: smaller;
65
+ /*
54
66
  width: 6.8em;
67
+ */
55
68
  }
56
69
 
57
70
  #summary {
58
71
  font-weight: bold;
72
+ text-align: center;
59
73
  }
60
74
 
61
75
  .hidden_new_event_mask {
@@ -68,3 +82,7 @@ ul.event_list li {
68
82
  margin-left: 0.5em;
69
83
  font-size: 80%;
70
84
  }
85
+
86
+ #edit_event_link {
87
+ margin-left: 1em;
88
+ }
@@ -1,7 +1,7 @@
1
1
  "a#new_event_link".onClick(function () {
2
2
  console.log(this);
3
3
  //$('hidden_new_event_mask').fade();
4
- this.parent().parent().first('.hidden_new_event_mask').fade();
4
+ this.parent().first('.hidden_new_event_mask').fade();
5
5
  // Do not follow link.
6
6
  return false;
7
7
  });
@@ -10,3 +10,28 @@
10
10
  console.log(this.parent());
11
11
  this.first("#hidden_description").fade();
12
12
  });
13
+
14
+ "#cancel".onClick(function() {
15
+ this.parent.parent().fade();
16
+ });
17
+
18
+ "#show_new_event_link".onClick(function() {
19
+ console.log(this.parent().first('#day_hidden_input').value());
20
+ day = this.parent().first('#day_hidden_input').value();
21
+ this.parent().first('.new_event_mask').load('/event/new/' + day);
22
+ this.parent().first('.new_event_mask').fade();
23
+ return false;
24
+ });
25
+
26
+ "#new_event_form".onSubmit(function(event) {
27
+ event.stop();
28
+ var me = this;
29
+ this.send({
30
+ /*onComplete: function() {alert("complete");}*/
31
+ onSuccess: function(resp) {
32
+ console.log(resp);
33
+ $('main').html(resp.responseText);
34
+ },
35
+ onFailure: function(resp) {alert(resp.responseText);},
36
+ });
37
+ });
@@ -1,3 +1,3 @@
1
1
  module Kalindar
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,37 @@
1
+ form.pure-form.pure-form-stacked action="/event/edit/#{event.uid}" method="post"
2
+ input type="hidden" name="_method" value="put"
3
+ input type="hidden" name="uid" value=event.uid
4
+
5
+ fieldset
6
+ legend = t 'edit_event'
7
+
8
+ label for="start_day" = t 'start_date'
9
+ input type="text" readonly=true name="start_day" value="#{l event.start_time, :format => :short}"
10
+
11
+ label for="start_time" = t 'when'
12
+ input type="text" name="start_time" placeholder="HH:MM" value="#{l event.start_time, :format => :hm}"
13
+
14
+ label for="start" = t 'summary'
15
+ input type="text" name="summary" placeholder="summary" value=event.summary
16
+
17
+ label for="location" = t 'location'
18
+ input type="text" name="location" placeholder="place" value=event.location
19
+
20
+ label for="description" = t 'description'
21
+ textarea name="description" rows=3 width=40
22
+ = event.description
23
+
24
+ label for="duration" = t 'duration'
25
+ select name="duration"
26
+ option value="15m" = t '15m'
27
+ option value="30m" = t '30m'
28
+ option value="60m" = t '60m'
29
+ option value="90m" = t '90m'
30
+ option value="120m" = t '120m'
31
+ option value="whole" = t 'whole_day'
32
+ option value="1d" = t '1d'
33
+ option value="2d" = t '2d'
34
+ option value="5d" = t '5d'
35
+ option value="1w" = t '1w'
36
+ button.pure-button type="submit" value="save" = t 'save'
37
+ button.pure-button type="submit" value="cancel" = t 'cancel'
@@ -1,10 +1,11 @@
1
1
  ul.day_list
2
2
  - @events.each do |day, evs|
3
3
  li class=li_day_class(day)
4
- center
5
- | #{l day, :format => :short}
6
- br
7
- a#new_event_link href="/event/new/#{day.strftime('%Y%m%d')}" #{t 'create_event'}
4
+ .dayname
5
+ | #{t(:"date.day.day_names")[day.wday-1]} #{l day, :format => :short}
6
+ 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
+ .new_event_mask style="display: none;"
8
9
  .hidden_new_event_mask
9
10
  == slim :new_event, :layout => false, :locals => {'start_date' => day.strftime("%Y%m%d")}
10
11
  ul.event_list
@@ -13,11 +14,16 @@ ul.day_list
13
14
  #event
14
15
  #time
15
16
  | #{ev.time_f day}
17
+ - if ev.location && !ev.location.empty?
18
+ | [#{ev.location}]
19
+ br
16
20
  #summary
17
- | #{ev.summary}
18
- - if ev.location
19
- | [#{ev.location}]
21
+ | #{ev.summary}
22
+ a#edit_event_link href="/event/edit/#{ev.uid}" = t 'edit'
20
23
  #hidden_description
21
24
  | (#{ev.from_to_f})
22
25
  br
23
26
  | #{ev.description}
27
+ hr(width="20%")
28
+ #nav
29
+
@@ -9,4 +9,5 @@ html
9
9
  link type="text/css" rel="stylesheet" href="/kalindar.css"
10
10
  link type="text/css" rel="stylesheet" href="/pure.css"
11
11
  body
12
- ==yield
12
+ #main
13
+ ==yield
@@ -1,4 +1,4 @@
1
- form.pure-form.pure-form-stacked action="/event" method="post"
1
+ form.pure-form.pure-form-stacked#new_event_form action="/event" method="post"
2
2
  input type="hidden" name="_method" value="put"
3
3
  fieldset
4
4
  legend = t 'new_event'
@@ -8,7 +8,7 @@ form.pure-form.pure-form-stacked action="/event" method="post"
8
8
  input type="text" readonly=true name="start_day" value="#{start_date}"
9
9
  - else
10
10
  label for="start_day" = t 'start_date'
11
- input type="text" name="start_day" value="" placeholder="YYYYMMDD")
11
+ input type="text" name="start_day" value=event.start_date placeholder="YYYYMMDD")
12
12
 
13
13
  label for="start_time" = t 'when'
14
14
  input type="text" name="start_time" value="" placeholder="HH:MM"
@@ -35,3 +35,4 @@ form.pure-form.pure-form-stacked action="/event" method="post"
35
35
  option value="5d" = t '5d'
36
36
  option value="1w" = t '1w'
37
37
  button.pure-button type="submit" value="save" = t 'save'
38
+ button.pure-button#cancel type="submit" value="save" = t 'cancel'
@@ -7,80 +7,144 @@ describe Kalindar do
7
7
  end
8
8
 
9
9
  describe EventCalendar do
10
- it 'parses an ics file' do
11
- cal = EventCalendar.new 'spec/testcal.ics'
12
- end
10
+ subject { EventCalendar.new 'spec/testcal.ics' }
13
11
 
14
- it 'initializes alternatively with a list of ics files' do
15
- cal = EventCalendar.new ['spec/testcal.ics', 'spec/testcal2.ics']
16
- expect(cal.calendars.length).to eql 2
12
+ describe "#new" do
13
+ it 'parses an ics file' do
14
+ cal = EventCalendar.new 'spec/testcal.ics'
15
+ end
16
+ it 'initializes alternatively with a list of ics files' do
17
+ cal = EventCalendar.new ['spec/testcal.ics', 'spec/testcal2.ics']
18
+ expect(cal.calendars.length).to eql 2
19
+ end
17
20
  end
18
21
 
19
22
  it 'exposes filename of parsed calendar' do
20
23
  cal = EventCalendar.new ['spec/testcal.ics', 'spec/testcal2.ics']
21
- expect(cal.filename_of cal.calendars.first).to eql 'spec/testcal.ics'
24
+ expect(cal.calendars.first.filename).to eql 'spec/testcal.ics'
22
25
  end
23
26
 
24
- it 'finds events given date' do
25
- cal = EventCalendar.new 'spec/testcal.ics'
26
- events = cal.find_events (Date.new(2014, 07, 27))
27
- event_names = events.map(&:summary)
28
- expect(event_names.include? "onehour").to eq true
29
- expect(event_names.include? "allday").to eq true
27
+ describe "#find_events" do
28
+ it 'finds events given date' do
29
+ events = subject.find_events (Date.new(2014, 07, 27))
30
+ event_names = events.map(&:summary)
31
+ expect(event_names.include? "onehour").to eq true
32
+ expect(event_names.include? "allday").to eq true
33
+ end
34
+ it 'handles whole day endtime correctly (ends next day)' do
35
+ events = subject.find_events (Date.new(2014, 07, 28))
36
+ event_names = events.map(&:summary)
37
+ expect(event_names.include? "allday").to eq false
38
+ end
39
+ it 'finds multiday events that cover the given date' do
40
+ events = subject.find_events (Date.new(2014, 07, 27))
41
+ expect(events.map(&:summary).include? "multidays").to eq true
42
+ end
43
+ it 'wraps events as Event delegates' do
44
+ events = subject.find_events (Date.new(2014, 07, 27))
45
+ events.each do |event|
46
+ expect(event.is_a? Event).to eq true
47
+ end
48
+ end
30
49
  end
31
50
 
32
51
  it 'finds events that reocur' do
33
- cal = EventCalendar.new 'spec/testcal.ics'
34
- events = cal.find_events (Date.new(2014, 07, 27))
52
+ events = subject.find_events (Date.new(2014, 07, 27))
35
53
  event_names = events.map(&:summary)
36
54
  expect(event_names.include? "daily").to eq true
37
55
  end
38
56
 
39
- it '#events_in' do
40
- cal = EventCalendar.new 'spec/testcal.ics'
41
- events = cal.events_in(Date.new(2014, 07, 27), Date.new(2014, 07, 28))
42
- event_names = events.map(&:summary)
43
- expect(event_names).to eq ["allday", "onehour", "daily", "allday", "daily"]
57
+ describe "#events_in" do
58
+ it 'accesses events between two dates' do
59
+ events = subject.events_in(Date.new(2014, 07, 27), Date.new(2014, 07, 28))
60
+ event_names = events.map(&:summary)
61
+ expect(event_names).to eq ["allday", "onehour", "daily", "daily"]
62
+ end
63
+ end
64
+
65
+ describe "#events_in" do
66
+ it '#events_in by day' do
67
+ events = subject.events_in(Date.new(2014, 7, 27), Date.new(2014, 7, 28))
68
+ event_names = events.map(&:summary)
69
+ expect(event_names).to eq ["allday", "onehour", "daily", "allday", "daily"]
70
+ expect(event_names.class).to eq({}.class)
71
+ end
72
+ it 'wraps in Event Delegate' do
73
+ events = subject.events_in(Date.new(2014, 7, 27), Date.new(2014, 7, 28))
74
+ expect(events.collect{|e| e.is_a? Event}.length).to eq events.length
75
+ end
76
+ end
77
+
78
+ describe "#find_by_uid" do
79
+ it 'finds by uuid' do
80
+ event = subject.find_by_uid 'cb523dc2-eab8-49c9-a99f-ed69ac3b65d0'
81
+ expect(event.summary).to eq 'allday'
82
+ end
83
+ it 'wraps in Event Delegate' do
84
+ event = subject.find_by_uid 'cb523dc2-eab8-49c9-a99f-ed69ac3b65d0'
85
+ expect(event.is_a? Event).to eq true
86
+ end
44
87
  end
88
+ end
45
89
 
46
- it '#events_in by day' do
90
+ describe "Event" do
91
+ subject(:allday_event) {}
92
+ subject(:events) {
47
93
  cal = EventCalendar.new 'spec/testcal.ics'
48
- events = cal.events_in(Date.new(2014, 7, 27), Date.new(2014, 7, 28))
49
- event_names = events.map(&:summary)
50
- expect(event_names).to eq ["allday", "onehour", "daily", "allday", "daily"]
51
- expect(event_names.class).to eq({}.class)
94
+ cal.events_in(Date.new(2014, 8, 27), Date.new(2014, 8, 28))
95
+ }
96
+ subject(:allday_event) {
97
+ cal = EventCalendar.new 'spec/testcal.ics'
98
+ cal.find_by_uid("cb523dc2-eab8-49c9-a99f-ed69ac3b65d0")
99
+ }
100
+ subject(:multiday_event) {
101
+ cal = EventCalendar.new 'spec/testcal.ics'
102
+ cal.find_by_uid("4a129461-cd74-4b3a-a307-faa1e8846cc2")
103
+ }
104
+
105
+ describe "#start_time_f" do
106
+ it "returns the time if given day is start day" do
107
+ expect(events[0].start_time_f Date.new(2014, 8, 27)).to eq "12:00"
108
+ expect(events[0].start_time_f Date.new(2014, 8, 28)).to eq "..."
109
+ end
52
110
  end
53
111
 
54
- describe "Event" do
55
- describe "#start_time_f" do
56
- it "returns the time if given day is start day" do
57
- cal = EventCalendar.new 'spec/testcal.ics'
58
- events = cal.events_in(Date.new(2014, 8, 27), Date.new(2014, 8, 28))
59
- expect(Event.new(events[0]).start_time_f Date.new(2014, 8, 27)).to eq "12:00"
60
- expect(Event.new(events[0]).start_time_f Date.new(2014, 8, 28)).to eq ""
61
- end
112
+ describe "#finish_time_f" do
113
+ it "returns the time if given day is end day" do
114
+ expect(events[0].finish_time_f Date.new(2014, 8, 27)).to eq "..."
115
+ expect(events[0].finish_time_f Date.new(2014, 8, 28)).to eq "13:00"
62
116
  end
63
- describe "#finish_time_f" do
64
- it "returns the time if given day is end day" do
65
- cal = EventCalendar.new 'spec/testcal.ics'
66
- events = cal.events_in(Date.new(2014, 8, 27), Date.new(2014, 8, 28))
67
- expect(Event.new(events[0]).finish_time_f Date.new(2014, 8, 27)).to eq ""
68
- expect(Event.new(events[0]).finish_time_f Date.new(2014, 8, 28)).to eq "13:00"
69
- end
117
+ end
118
+
119
+ describe "#time_f" do
120
+ it "returns the from to time for given day" do
121
+ expect(allday_event.time_f Date.new(2014, 7, 27)).to eq ""
70
122
  end
71
- describe "#time_f" do
72
- it "returns the from to time for given day" do
73
- cal = EventCalendar.new 'spec/testcal.ics'
74
- events = cal.events_in(Date.new(2014, 8, 27), Date.new(2014, 8, 28))
75
- expect(Event.new(events[0]).time_f Date.new(2014, 8, 27)).to eq "12:00 - "
76
- end
123
+ it "renders multiday in between with ... " do
124
+ expect(multiday_event.time_f Date.new(2014, 7, 27)).to eq "..."
77
125
  end
78
- describe "#time_f" do
79
- it "returns the from to time" do
80
- cal = EventCalendar.new 'spec/testcal.ics'
81
- events = cal.events_in(Date.new(2014, 8, 27), Date.new(2014, 8, 28))
82
- expect(Event.new(events[0]).from_to_f).to eq "27.08. 12:00 - 28.08. 13:00"
83
- end
126
+ end
127
+ describe "#from_to_f" do
128
+ it "returns the from to time" do
129
+ expect(events[0].from_to_f).to eq "27.08. 12:00 - 28.08. 13:00"
130
+ end
131
+ end
132
+
133
+ describe "#update" do
134
+ it "updates from params" do
135
+ # should be fail safe, too
136
+ cal = EventCalendar.new 'spec/testcal.ics'
137
+ event = cal.find_by_uid("aea8d217-8025-4d9b-88e6-3df9e6abd33c")
138
+
139
+ params = {'location' => 'a place', 'description' => 'exact description', 'summary'=> 'synopsis', 'duration' => '15m', 'start_day' => '20140808', 'start_time' => '10:10'}
140
+ event.update params
141
+
142
+ event_fetched = cal.find_by_uid("aea8d217-8025-4d9b-88e6-3df9e6abd33c")
143
+ expect(event_fetched.location).to eql 'a place'
144
+ expect(event_fetched.description).to eql 'exact description'
145
+ expect(event_fetched.summary).to eql 'synopsis'
146
+ expect(event_fetched.dtstart).to eq DateTime.new(2014, 8, 8, 10, 10)
147
+ expect(event_fetched.dtend).to eq DateTime.new(2014, 8, 8, 10, 25)
84
148
  end
85
149
  end
86
150
  end
data/spec/testcal.ics CHANGED
@@ -51,6 +51,17 @@ UID:aea8d217-8025-4d9b-88e6-3df9e6abd33c
51
51
  SUMMARY:2days
52
52
  DTSTART;TZID=Europe/Berlin:20140827T120000
53
53
  DTEND;TZID=Europe/Berlin:20140828T130000
54
+ CLASS:PUBLIC
55
+ TRANSP:OPAQUE
56
+ END:VEVENT
57
+ BEGIN:VEVENT
58
+ CREATED:20140814T060630Z
59
+ LAST-MODIFIED:20140814T060654Z
60
+ DTSTAMP:20140814T060654Z
61
+ UID:4a129461-cd74-4b3a-a307-faa1e8846cc2
62
+ SUMMARY:multidays
63
+ DTSTART;TZID=Europe/Berlin:20140726T090000
64
+ DTEND;TZID=Europe/Berlin:20140729T100000
54
65
  TRANSP:OPAQUE
55
66
  CLASS:PUBLIC
56
67
  END:VEVENT
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.0.1
4
+ version: 0.1.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-07-30 00:00:00.000000000 Z
11
+ date: 2014-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ri_cal
@@ -119,7 +119,9 @@ files:
119
119
  - .rspec
120
120
  - .travis.yml
121
121
  - Gemfile
122
+ - Gemfile.lock
122
123
  - LICENSE.txt
124
+ - Procfile
123
125
  - README.md
124
126
  - Rakefile
125
127
  - config.json
@@ -127,6 +129,7 @@ files:
127
129
  - kalindar.gemspec
128
130
  - lib/kalindar.rb
129
131
  - lib/kalindar/app.rb
132
+ - lib/kalindar/calendar.rb
130
133
  - lib/kalindar/event.rb
131
134
  - lib/kalindar/event_calendar.rb
132
135
  - lib/kalindar/locales/de.yml
@@ -140,13 +143,14 @@ files:
140
143
  - lib/kalindar/public/right.js
141
144
  - lib/kalindar/version.rb
142
145
  - lib/kalindar/views/.layout.haml.swp
146
+ - lib/kalindar/views/edit_event.slim
143
147
  - lib/kalindar/views/event_list.slim
144
148
  - lib/kalindar/views/layout.slim
145
149
  - lib/kalindar/views/new_event.slim
146
150
  - spec/kalindar_spec.rb
147
151
  - spec/spec_helper.rb
148
152
  - spec/testcal.ics
149
- homepage: ''
153
+ homepage: https://github.com/fwolfst/kalindar
150
154
  licenses:
151
155
  - MIT
152
156
  metadata: {}