summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/helpers/nodes_helper.rb16
-rw-r--r--app/models/concerns/rrule_humanizer.rb82
-rw-r--r--app/models/event.rb1
-rw-r--r--app/views/nodes/show.html.erb14
4 files changed, 112 insertions, 1 deletions
diff --git a/app/helpers/nodes_helper.rb b/app/helpers/nodes_helper.rb
index 4293628..329bcc5 100644
--- a/app/helpers/nodes_helper.rb
+++ b/app/helpers/nodes_helper.rb
@@ -43,4 +43,20 @@ module NodesHelper
43 link_to('add event', new_event_path(:node_id => @node.id)) 43 link_to('add event', new_event_path(:node_id => @node.id))
44 ]) 44 ])
45 end 45 end
46
47 def event_schedule_text(event)
48 if event.rrule.present?
49 recurrence = event.humanize_rrule(I18n.locale)
50 if recurrence
51 time = event.start_time&.strftime("%H:%M")
52 time ? "#{recurrence} #{t(:event_schedule_time, time: time)}" : recurrence
53 else
54 "#{event.rrule} (#{t(:event_schedule_unrecognized)})"
55 end
56 elsif event.start_time
57 I18n.l(event.start_time, format: :long)
58 else
59 t(:event_schedule_none)
60 end
61 end
46end 62end
diff --git a/app/models/concerns/rrule_humanizer.rb b/app/models/concerns/rrule_humanizer.rb
new file mode 100644
index 0000000..6cee711
--- /dev/null
+++ b/app/models/concerns/rrule_humanizer.rb
@@ -0,0 +1,82 @@
1module RruleHumanizer
2 extend ActiveSupport::Concern
3
4 WEEKDAY_NAMES = {
5 de: { "MO"=>"Montag","TU"=>"Dienstag","WE"=>"Mittwoch","TH"=>"Donnerstag","FR"=>"Freitag","SA"=>"Samstag","SU"=>"Sonntag" },
6 en: { "MO"=>"Monday","TU"=>"Tuesday","WE"=>"Wednesday","TH"=>"Thursday","FR"=>"Friday","SA"=>"Saturday","SU"=>"Sunday" }
7 }.freeze
8
9 WEEKDAY_NAMES_ADVERBIAL = {
10 de: { "MO"=>"montags","TU"=>"dienstags","WE"=>"mittwochs","TH"=>"donnerstags","FR"=>"freitags","SA"=>"samstags","SU"=>"sonntags" }
11 }.freeze
12
13 ORDINAL_NAMES = {
14 de: { 1=>"ersten", 2=>"zweiten", 3=>"dritten", 4=>"vierten", -1=>"letzten", -2=>"vorletzten" },
15 en: { 1=>"first", 2=>"second", 3=>"third", 4=>"fourth", -1=>"last", -2=>"second-to-last" }
16 }.freeze
17
18 MONTH_NAMES = {
19 de: %w[Januar Februar März April Mai Juni Juli August September Oktober November Dezember],
20 en: %w[January February March April May June July August September October November December]
21 }.freeze
22
23 def humanize_rrule(locale = I18n.locale)
24 return nil if rrule.blank?
25 parts = Hash[rrule.split(";").map { |p| p.split("=", 2) }]
26 return nil if parts["COUNT"] || parts["UNTIL"] # old one-off data, don't guess
27
28 freq, interval, byday, bymonth = parts["FREQ"], parts["INTERVAL"].to_i, parts["BYDAY"], parts["BYMONTH"]
29 loc = locale.to_sym
30 weekdays = WEEKDAY_NAMES[loc] || WEEKDAY_NAMES[:en]
31 ordinals = ORDINAL_NAMES[loc] || ORDINAL_NAMES[:en]
32 months = MONTH_NAMES[loc] || MONTH_NAMES[:en]
33
34 days = byday&.split(",")&.map do |d|
35 if d =~ /^(-?\d+)([A-Z]{2})$/
36 "#{ordinals[$1.to_i]} #{weekdays[$2]}"
37 else
38 weekdays[d]
39 end
40 end
41
42 base =
43 case loc
44 when :de
45 case freq
46 when "WEEKLY"
47 if days
48 if interval == 2
49 adverbial = byday.split(",").map { |d| WEEKDAY_NAMES_ADVERBIAL[:de][d] }
50 "Alle zwei Wochen #{adverbial.join(' und ')}"
51 else
52 "Jeden #{days.join(' und ')}"
53 end
54 else
55 interval == 2 ? "Alle zwei Wochen" : "Wöchentlich"
56 end
57 when "MONTHLY"
58 days ? "Jeden #{days.join(' und ')} im Monat" : "Monatlich"
59 end
60 else
61 case freq
62 when "WEEKLY"
63 days ? "#{interval == 2 ? 'Every other' : 'Every'} #{days.join(' and ')}" : (interval == 2 ? "Every other week" : "Weekly")
64 when "MONTHLY"
65 days ? "Every #{days.join(' and ')} of the month" : "Monthly"
66 end
67 end
68 return nil unless base
69
70 if bymonth
71 included = bymonth.split(",").map(&:to_i)
72 missing = ((1..12).to_a - included)
73 if missing.size == 1
74 excluded_name = months[missing.first - 1]
75 base += (loc == :de ? ", außer im #{excluded_name}" : ", except in #{excluded_name}")
76 end
77 # more than one missing month: bymonth pattern more complex than we handle, leave base as-is silently
78 end
79
80 base
81 end
82end
diff --git a/app/models/event.rb b/app/models/event.rb
index 26c79e4..de82674 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -1,4 +1,5 @@
1class Event < ApplicationRecord 1class Event < ApplicationRecord
2 include RruleHumanizer
2 3
3 belongs_to :node, optional: true 4 belongs_to :node, optional: true
4 has_many :occurrences 5 has_many :occurrences
diff --git a/app/views/nodes/show.html.erb b/app/views/nodes/show.html.erb
index de4d8a2..7223219 100644
--- a/app/views/nodes/show.html.erb
+++ b/app/views/nodes/show.html.erb
@@ -42,6 +42,18 @@
42 <td class="description">Tagged with:</td> 42 <td class="description">Tagged with:</td>
43 <td><%= @page.tag_list %></td> 43 <td><%= @page.tag_list %></td>
44 </tr> 44 </tr>
45 <% if @node.events.any? %>
46 <tr>
47 <td class="description">Events</td>
48 <td>
49 <ul>
50 <% @node.events.order(:start_time).each do |event| %>
51 <li><%= event_schedule_text(event) %><%= " (primary)" if event.is_primary? %></li>
52 <% end %>
53 </ul>
54 </td>
55 </tr>
56 <% end %>
45 <tr> 57 <tr>
46 <td class="description"><strong>Title</strong></td> 58 <td class="description"><strong>Title</strong></td>
47 <td><%= sanitize( @page.title ) %></td> 59 <td><%= sanitize( @page.title ) %></td>
@@ -59,4 +71,4 @@
59 <td class="right"></td> 71 <td class="right"></td>
60 </tr> 72 </tr>
61 </table> 73 </table>
62</div> \ No newline at end of file 74</div>