Skip to content

Commit

Permalink
Fix timeline (#174)
Browse files Browse the repository at this point in the history
* fix timeline

* add error handling and parsing of unspecified dates

* add more error handling

* check for exmpty strings; fix assigning to wrong year if object has negative year

* make coderabbit happy

* keep coderabbit happy

* improve error handling

* fix date parsing (year "0000")

* refactoring code

* prettier

* change sort order, remove period heading

* fix regex

* prettier

* improve naming

---------

Co-authored-by: Moritz Mähr <[email protected]>
  • Loading branch information
koilebeit and maehr authored Nov 4, 2024
1 parent 802aaa7 commit cd9020b
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 19 deletions.
52 changes: 38 additions & 14 deletions _layouts/timeline_edtf.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@
{% else %}
{%- assign items = site.data[site.metadata] | where_exp: 'item', 'item.objectid and item.parentid == nil' -%}
{% endif %}
{% assign regex = '[-]?[\dXu]{4,}' %}
{%- assign items = items | where_exp: 'item', 'item[field]' -%}
{%- assign raw-dates = items | map: field | compact | uniq -%}
{% assign regex = '[\dX]{4}' %}
{%- capture clean-years -%}{% for date in raw-dates %}{{date | regex_match: regex | join: ';' }}{% unless forloop.last %};{% endunless %}{%- endfor -%}{%- endcapture -%}
{%- assign uniqueYears = clean-years | remove: ' ' | replace: ';;', ';' | split: ';' | uniq | sort -%}
{% assign sorted_years = uniqueYears | sort_edtf %}
{%- if site.data.theme['year-navigation'] -%}
{%- assign navYears = site.data.theme['year-navigation'] | split: ';' -%}
{%- elsif site.data.theme['year-nav-increment'] -%}
{%- capture navYears -%}
{%- for i in uniqueYears -%}{%- assign t = i | modulo: site.data.theme.year-nav-increment -%}
{%- for i in sorted_years -%}{%- assign t = i | modulo: site.data.theme.year-nav-increment -%}
{%- if t == 0 -%}{{ i }}{% unless forloop.last %};{% endunless %}{% endif %}{% endfor %}{%- endcapture -%}
{%- assign navYears = navYears | split: ';' -%}
{%- endif -%}
Expand All @@ -37,30 +38,53 @@
</button>
<div class="dropdown-menu" aria-labelledby="yearButton">
{% for y in navYears %}
<a class="dropdown-item" href="#y{{ y }}">{{ y }}</a>
{%- endfor %}
{% assign year_parts = y | split: ':' %}
{% if year_parts.size == 2 %}
<a class="dropdown-item" href="#y{{ year_parts[1] }}">{{ year_parts[0] }}</a>
{% else %}
<a class="dropdown-item" href="#y{{ y }}">{{ y }}</a>
{% endif %}
{% endfor %}
</div>
</div>
{%- endif -%}

{{ content }}

<h2>
<a href="#y{{ uniqueYears | first }}">{{ uniqueYears | first }}</a>&#8211;<a href="#y{{ uniqueYears | last }}">
{{- uniqueYears | last -}}
</a>
</h2>
{% comment %}uncomment the next lines to display a heading indicating the period of the data in text form{% endcomment %}
{% comment %}
<h2>
{% assign first_year = sorted_years | first | split: ':' %}
{% assign last_year = sorted_years | last | split: ':' %}
{% if sorted_years.size > 0 %}
{% if first_year.size == 3
and last_year.size == 3
and first_year[0] != ''
and first_year[1] != ''
and last_year[0] != ''
and last_year[1] != ''
%}
<a href="#y{{ first_year[1] }}">{{ first_year[0] }}</a> &#8211;
<a href="#y{{ last_year[1]}}">{{ last_year[0] }}</a>
{% else %}
<span class="text-muted">Invalid date range</span>
{% endif %}
{% else %}
<span class="text-muted">No items found</span>
{% endif %}
</h2>
{% endcomment %}

<table id="timeline" class="table table-striped">
<tbody>
{% for year in uniqueYears %}
<tr id="y{{ year }}">
{% for date in sorted_years %}
{% assign year = date | split: ':' %}
<tr id="y{{ year[1] }}">
<th>
<h3>{{ year }}</h3>
<h3>{{ year[0] }}</h3>
</th>
<td>
<div class="row">
{%- assign inYear = items | where_exp: 'item', 'item[field] contains year' -%}
{%- assign inYear = items | filter_items_by_year: year[1], '[-]?[\dXu]{4,}' -%}
{% for item in inYear %}
<div class="col-lg-4 col-md-6">
<figure class="figure">
Expand Down
30 changes: 30 additions & 0 deletions _plugins/jekyll_regex_match.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,36 @@ def regex_match_once(input_str, regex_str)
return nil
end
end

def filter_items_by_year(items, year, regex_pattern = '[-]?[\dXu]{4,}')
raise ArgumentError, 'Regex pattern too complex' if regex_pattern.length > 50
return [] unless items.is_a?(Array) && !year.nil?
begin

# Clear cache if it grows too large
if defined?(@cache_size) && @cache_size > 1000
items.each { |item| item.delete('cached_dates') }
@cache_size = 0
end

regex = Regexp.new(regex_pattern)
items.select do |item|
next false unless item.is_a?(Hash) && item['date'].is_a?(String)

# Track cache size
@cache_size ||= 0
@cache_size += 1 unless item['cached_dates']

dates = item['cached_dates'] ||= item['date'].scan(regex).map(&:to_s)
dates.include?(year)
end
rescue RegexpError => e
Jekyll.logger.error "RegexMatch:", "Invalid regex pattern: #{e.message}"
# Handle invalid regex pattern
[]
end
end

end
end

Expand Down
50 changes: 45 additions & 5 deletions _plugins/sort_edtf.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,50 @@
module Jekyll
module SortEDTF
def sort_edtf(array_of_strings)
sorted = array_of_strings.map { |str| str.gsub('X', '0') }
sorted.sort_by { |str| str[/\d+/].to_i }
end
module SortEDTF
def sort_edtf(array_of_strings)
non_empty_dates = array_of_strings.reject { |str| str.strip.empty? }

processed_dates = non_empty_dates.map do |str|
normalized_date_str = replace_x_with_parsable_0(str)
date_as_integer = normalize_to_integer(normalized_date_str)
display_format = create_display_format(str)

{ numeric: date_as_integer, original: str, display_format: display_format }
end

sorted_dates = processed_dates.sort_by { |date| -date[:numeric] }
sorted_dates.map { |date| "#{date[:display_format]}:#{date[:original]}" }
end

private

def replace_x_with_parsable_0(str)
str.gsub(/[Xu]/, '0')
end

def normalize_to_integer(year_str)
numeric_str = if year_str.start_with?('-')
year_str.sub(/^-0+/, '-')
else
year_str.sub(/^0+(?=\d)/, '')
end

if numeric_str.match?(/^-?\d+$/)
numeric_str.to_i
else
raise ArgumentError, "Invalid year format: #{year_str}"
end
end

def create_display_format(str)
if str.start_with?('-')
"#{str[1..-1].sub(/^0+/, '')} v. u. Z."
else
str.sub(/^0+(?=\d)/, '')
end
end


end
end

Liquid::Template.register_filter(Jekyll::SortEDTF)

0 comments on commit cd9020b

Please sign in to comment.