diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-16 16:43:11 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-16 16:43:11 +0200 |
| commit | 35dc05de97677d57123617a7c4e78aad1611b28d (patch) | |
| tree | 2960f3a8d363a12edd497fc96a022a9da77929fd /app/models | |
| parent | b701669d0d9a5d7be01f99b8e725c05c6c5d52ce (diff) | |
managed RRULE constructs now include week selection
Improve the humanizer to also understand weekly patters that
an editor can manually select, on top of the single week
rules.
Extend template and javascript controller to reflect these
changes.
Diffstat (limited to 'app/models')
| -rw-r--r-- | app/models/concerns/rrule_humanizer.rb | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/app/models/concerns/rrule_humanizer.rb b/app/models/concerns/rrule_humanizer.rb index 8231de8..ca29648 100644 --- a/app/models/concerns/rrule_humanizer.rb +++ b/app/models/concerns/rrule_humanizer.rb | |||
| @@ -15,8 +15,8 @@ module RruleHumanizer | |||
| 15 | }.freeze | 15 | }.freeze |
| 16 | 16 | ||
| 17 | ORDINAL_NAMES = { | 17 | ORDINAL_NAMES = { |
| 18 | de: { 1=>"ersten", 2=>"zweiten", 3=>"dritten", 4=>"vierten", -1=>"letzten", -2=>"vorletzten" }, | 18 | de: { 1=>"ersten", 2=>"zweiten", 3=>"dritten", 4=>"vierten", 5=>"fünften", -1=>"letzten", -2=>"vorletzten" }, |
| 19 | en: { 1=>"first", 2=>"second", 3=>"third", 4=>"fourth", -1=>"last", -2=>"second-to-last" } | 19 | en: { 1=>"first", 2=>"second", 3=>"third", 4=>"fourth", 5=>"fifth", -1=>"last", -2=>"second-to-last" } |
| 20 | }.freeze | 20 | }.freeze |
| 21 | 21 | ||
| 22 | MONTH_NAMES = { | 22 | MONTH_NAMES = { |
| @@ -35,7 +35,8 @@ module RruleHumanizer | |||
| 35 | ordinals = ORDINAL_NAMES[loc] || ORDINAL_NAMES[:en] | 35 | ordinals = ORDINAL_NAMES[loc] || ORDINAL_NAMES[:en] |
| 36 | months = MONTH_NAMES[loc] || MONTH_NAMES[:en] | 36 | months = MONTH_NAMES[loc] || MONTH_NAMES[:en] |
| 37 | 37 | ||
| 38 | days = byday&.split(",")&.map do |d| | 38 | byday_values = byday&.split(",") |
| 39 | days = byday_values&.map do |d| | ||
| 39 | if d =~ /^(-?\d+)([A-Z]{2})$/ | 40 | if d =~ /^(-?\d+)([A-Z]{2})$/ |
| 40 | "#{ordinals[$1.to_i]} #{weekdays[$2]}" | 41 | "#{ordinals[$1.to_i]} #{weekdays[$2]}" |
| 41 | else | 42 | else |
| @@ -43,6 +44,21 @@ module RruleHumanizer | |||
| 43 | end | 44 | end |
| 44 | end | 45 | end |
| 45 | 46 | ||
| 47 | excluded_monthly_ordinal = nil | ||
| 48 | excluded_monthly_weekday = nil | ||
| 49 | if freq == "MONTHLY" && byday_values.present? | ||
| 50 | ordinal_days = byday_values.map { |d| d.match(/^([1-5])([A-Z]{2})$/) } | ||
| 51 | if ordinal_days.all? | ||
| 52 | positions = ordinal_days.map { |match| match[1].to_i }.uniq.sort | ||
| 53 | weekdays_in_rule = ordinal_days.map { |match| match[2] }.uniq | ||
| 54 | missing_positions = (1..5).to_a - positions | ||
| 55 | if positions.size == 4 && weekdays_in_rule.size == 1 && missing_positions.size == 1 | ||
| 56 | excluded_monthly_ordinal = missing_positions.first | ||
| 57 | excluded_monthly_weekday = weekdays_in_rule.first | ||
| 58 | end | ||
| 59 | end | ||
| 60 | end | ||
| 61 | |||
| 46 | base = | 62 | base = |
| 47 | case loc | 63 | case loc |
| 48 | when :de | 64 | when :de |
| @@ -59,14 +75,22 @@ module RruleHumanizer | |||
| 59 | interval == 2 ? "Alle zwei Wochen" : "Wöchentlich" | 75 | interval == 2 ? "Alle zwei Wochen" : "Wöchentlich" |
| 60 | end | 76 | end |
| 61 | when "MONTHLY" | 77 | when "MONTHLY" |
| 62 | days ? "Jeden #{days.join(' und ')} im Monat" : "Monatlich" | 78 | if excluded_monthly_ordinal |
| 79 | "Jeden #{weekdays[excluded_monthly_weekday]} im Monat, außer dem #{ordinals[excluded_monthly_ordinal]} #{weekdays[excluded_monthly_weekday]}" | ||
| 80 | else | ||
| 81 | days ? "Jeden #{days.join(' und ')} im Monat" : "Monatlich" | ||
| 82 | end | ||
| 63 | end | 83 | end |
| 64 | else | 84 | else |
| 65 | case freq | 85 | case freq |
| 66 | when "WEEKLY" | 86 | when "WEEKLY" |
| 67 | days ? "#{interval == 2 ? 'Every other' : 'Every'} #{days.join(' and ')}" : (interval == 2 ? "Every other week" : "Weekly") | 87 | days ? "#{interval == 2 ? 'Every other' : 'Every'} #{days.join(' and ')}" : (interval == 2 ? "Every other week" : "Weekly") |
| 68 | when "MONTHLY" | 88 | when "MONTHLY" |
| 69 | days ? "Every #{days.join(' and ')} of the month" : "Monthly" | 89 | if excluded_monthly_ordinal |
| 90 | "Every #{weekdays[excluded_monthly_weekday]} of the month, except the #{ordinals[excluded_monthly_ordinal]} #{weekdays[excluded_monthly_weekday]}" | ||
| 91 | else | ||
| 92 | days ? "Every #{days.join(' and ')} of the month" : "Monthly" | ||
| 93 | end | ||
| 70 | end | 94 | end |
| 71 | end | 95 | end |
| 72 | return nil unless base | 96 | return nil unless base |
