Instantly share code, notes, and snippets.
dogweather/breadcrumbs.rb
Created Sep 4, 2020
Breadcrumbs, OO version
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment