|
# typed: false |
|
# frozen_string_literal: true |
|
|
|
require 'json' |
|
|
|
module PublicLaw |
|
# Represents a breadcrumb trail on a page. |
|
class Breadcrumbs |
|
include ActionView::Helpers |
|
extend T::Sig |
|
|
|
JSON_PREFIX = "<script type=\"application/ld+json\">\n" |
|
JSON_SUFFIX = "\n</script>\n" |
|
|
|
HTML_PREFIX = "<nav aria-label=\"breadcrumb\">\n<ol class=\"breadcrumb\">" |
|
HTML_SUFFIX = "</ol>\n</nav>" |
|
|
|
Links = T.type_alias { T::Array[T::Hash[Symbol, String]] } |
|
|
|
|
|
sig {params(title: String, location: String).returns(Breadcrumbs)} |
|
def initialize(title:, location:) |
|
raise 'Title is blank' if title.blank? |
|
raise 'Location is blank' if location.blank? |
|
|
|
@all_but_last_item = T.let([], Links) |
|
@last_item = T.let({ title: sanitize(title), location: location }, T::Hash[Symbol, String]) |
|
|
|
self |
|
end |
|
|
|
|
|
sig {params(title: String, location: String).returns(Breadcrumbs)} |
|
def add(title:, location:) |
|
raise 'Title is blank' if title.blank? |
|
raise 'Location is blank' if location.blank? |
|
|
|
@all_but_last_item << @last_item |
|
@last_item = { title: sanitize(title), location: location } |
|
|
|
self |
|
end |
|
|
|
|
|
sig {returns(String)} |
|
def to_s |
|
to_html |
|
end |
|
|
|
|
|
|
|
private |
|
|
|
|
|
sig {returns(String)} |
|
def to_html |
|
(microdata_json + "\n" + html_list).html_safe |
|
end |
|
|
|
|
|
sig {returns(String)} |
|
def microdata_json |
|
microdata = { |
|
'@context' => 'http://schema.org', |
|
'@type' => 'BreadcrumbList', |
|
'itemListElement' => list_elements(@all_but_last_item + [@last_item]), |
|
} |
|
JSON_PREFIX + microdata.to_json + JSON_SUFFIX |
|
end |
|
|
|
|
|
sig {returns(String)} |
|
def html_list |
|
HTML_PREFIX + "\n" + list_items_html + HTML_SUFFIX + "\n" |
|
end |
|
|
|
|
|
sig {returns(String)} |
|
def list_items_html |
|
' ' + list_items.join("\n ") + "\n" |
|
end |
|
|
|
# |
|
# Create HTML <li> elements from the Links. All but |
|
# the last should be hyperlinks. |
|
# |
|
sig {returns(T::Array[String])} |
|
def list_items |
|
@all_but_last_item |
|
.map { |l| "<li class=\"breadcrumb-item\"><a href=\"#{l[:location]}\">#{l[:title]}</a></li>" } |
|
.push(final_list_item) |
|
end |
|
|
|
|
|
sig {returns(String)} |
|
def final_list_item |
|
"<li class=\"breadcrumb-item active\" aria-current=\"page\">#{@last_item.fetch(:title)}</li>" |
|
end |
|
|
|
sig {params(links: Links).returns(T::Array[T::Hash[String, T.untyped]])} |
|
def list_elements(links) |
|
list_elements = [] |
|
links.each_index do |index| |
|
list_elements << { |
|
'@type' => 'ListItem', |
|
'position' => index + 1, |
|
'item' => { |
|
'@id' => links[index].fetch(:location), |
|
'name' => links[index].fetch(:title), |
|
}, |
|
} |
|
end |
|
list_elements |
|
end |
|
end |
|
end |