Skip to content

Commit

Permalink
TRG-668: Support sites deployed on a path other than "/" when generat…
Browse files Browse the repository at this point in the history
…ing header and footer links.

TRG-668: Support sites deployed on a path other than "/" when generating header and footer links.
  • Loading branch information
eddgrant committed May 19, 2023
1 parent 000b495 commit 6a1f3e1
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 35 deletions.
62 changes: 52 additions & 10 deletions lib/govuk_tech_docs/path_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
module GovukTechDocs
module PathHelpers
def get_path_to_resource(config, resource, current_page)
if config[:relative_links]
resource_path_segments = resource.path.split("/").reject(&:empty?)[0..-2]
resource_file_name = resource.path.split("/")[-1]

path_to_site_root = path_to_site_root config, current_page.path
resource_path = path_to_site_root + resource_path_segments
.push(resource_file_name)
.join("/")
require 'uri'

# Some useful notes from https://www.rubydoc.info/github/middleman/middleman/Middleman/Sitemap/Resource#url-instance_method :
# 'resource.path' is "The source path of this resource (relative to the source directory, without template extensions)."
# 'resource.destination_path', which is: "The output path in the build directory for this resource."
# 'resource.url' is based on 'resource.destination_path', but is further tweaked to optionally strip the index file and prefixed with any :http_prefix.

# Calculates the path to the sought resource, taking in to account whether the site has been configured
# to generate relative or absolute links.
# Identifies whether the sought resource is an internal or external target: External targets are returned untouched. Path calculation is performed for internal targets.
# Works for both "Middleman::Sitemap::Resource" resources and plain strings (which may be passed from the site configuration when generating header links).
#
# @param [Object] config
# @param [Object] resource
# @param [Object] current_page
def get_path_to_resource(config, resource, current_page)
if resource.instance_of?(Middleman::Sitemap::Resource)
if config[:relative_links]
resolved_path = get_resource_path_relative_to_current_page(config, current_page.path, resource.path)
else
resolved_path = resource.url
end
else
resource_path = resource.url
if external_url?(resource)
resolved_path = resource
else
if config[:relative_links]
resolved_path = get_resource_path_relative_to_current_page(config, current_page.path, resource)
else
resolved_path = resource
end
end
end
resource_path

resolved_path
end

def path_to_site_root(config, page_path)
Expand All @@ -26,5 +49,24 @@ def path_to_site_root(config, page_path)
end
path_to_site_root
end

private

# Calculates the path to the sought resource, relative to the current page.
# @param [Object] config Middleman config.
# @param [String] current_page path of the current page, from the site root.
# @param [String] resource_path_from_site_root path of the sought resource, from the site root.
def get_resource_path_relative_to_current_page(config, current_page, resource_path_from_site_root)
path_segments = resource_path_from_site_root.split("/").reject(&:empty?)[0..-2]
path_file_name = resource_path_from_site_root.split("/")[-1]

path_to_site_root = path_to_site_root config, current_page
path_to_site_root + path_segments.push(path_file_name).join("/")
end

def external_url?(url)
uri = URI.parse(url)
uri.scheme || uri.to_s.split("/")[0]&.include?(".")
end
end
end
2 changes: 1 addition & 1 deletion lib/source/layouts/_footer.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<ul class="govuk-footer__inline-list">
<% config[:tech_docs][:footer_links].each do |title, path| %>
<li class="govuk-footer__inline-list-item">
<a class="govuk-footer__link" href="<%= url_for path %>"><%= title %></a>
<a class="govuk-footer__link" href="<%= get_path_to_resource config, path, current_page %>"><%= title %></a>
</li>
<% end %>
</ul>
Expand Down
4 changes: 2 additions & 2 deletions lib/source/layouts/_header.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="govuk-header__container govuk-header__container--full-width">
<div class="govuk-header__logo">
<% if config[:tech_docs][:service_link] %>
<a href="<%= url_for config[:tech_docs][:service_link] %>" class="govuk-header__link govuk-header__link--homepage">
<a href="<%= get_path_to_resource config, config[:tech_docs][:service_link], current_page %>" class="govuk-header__link govuk-header__link--homepage">
<% else %>
<span class="govuk-header__link govuk-header__link--homepage">
<% end %>
Expand Down Expand Up @@ -46,7 +46,7 @@
<ul id="navigation" class="govuk-header__navigation-list">
<% config[:tech_docs][:header_links].each do |title, path| %>
<li class="govuk-header__navigation-item<% if active_page(path) %> govuk-header__navigation-item--active<% end %>">
<a class="govuk-header__link" href="<%= url_for path %>"><%= title %></a>
<a class="govuk-header__link" href="<%= get_path_to_resource config, path, current_page %>"><%= title %></a>
</li>
<% end %>
</ul>
Expand Down
108 changes: 86 additions & 22 deletions spec/govuk_tech_docs/path_helpers_spec.rb
Original file line number Diff line number Diff line change
@@ -1,63 +1,127 @@
def create_resource_double(**kwargs)
resource = instance_double(Middleman::Sitemap::Resource, **kwargs)
allow(resource).to receive(:instance_of?).with(Middleman::Sitemap::Resource).and_return(true)
resource
end

RSpec.describe GovukTechDocs::PathHelpers do
include GovukTechDocs::PathHelpers

describe "#get_path_to_resource" do
it "calculates the path to a resource when using absolute links" do
context "calculate paths for internal resources" do
resource_url = "/documentation/introduction/index.html"

config = {}
resource = double("resource", url: resource_url)
it "when the site is configured to generate absolute links" do
config = {}

resource = create_resource_double(url: resource_url)
resource_path = get_path_to_resource(config, resource, nil)

expect(resource_path).to eql(resource_url)
end

it "when the site is configured to generate relative links" do
config = {
relative_links: true,
}

resource_path = get_path_to_resource(config, resource, nil)
expect(resource_path).to eql(resource_url)
current_page_path = "/documentation/introduction/section-one/index.html"
current_page = double("current_page", path: current_page_path)
resource = create_resource_double(url: resource_url, path: resource_url)
resource_path = get_path_to_resource(config, resource, current_page)

expect(resource_path).to eql("../../../documentation/introduction/index.html")
end
end

it "calculates the path to a resource when using relative links" do
context "calculate paths for internal page paths (which are represented as strings)" do
current_page_path = "/documentation/introduction/section-one/index.html"
url = "/documentation/introduction/index.html"

config = {
relative_links: true,
}
resource = double("resource", url: url, path: url)
current_page = double("current_page", path: current_page_path)
it "when the site is configured to generate absolute links" do
config = {}

url = "/documentation/introduction/index.html"
current_page = double("current_page", path: current_page_path)
resource_path = get_path_to_resource(config, url, current_page)

expect(resource_path).to eql(url)
end

it "when the site is configured to generate relative links" do
config = {
relative_links: true,
}

url = "/documentation/introduction/index.html"
current_page = double("current_page", path: current_page_path)
resource_path = get_path_to_resource(config, url, current_page)

expect(resource_path).to eql("../../../documentation/introduction/index.html")
end
end

context "calculate URLs for external URLs" do
external_urls = [
"https://www.example.com/some-page.html", # With scheme included.
"www.example.com/some-page.html", # With scheme omitted.
]
external_urls.each { | external_url |
current_page_path = "/documentation/introduction/section-one/index.html"

it "when the site is configured to generate absolute links" do
config = {}

resource_path = get_path_to_resource(config, resource, current_page)
expect(resource_path).to eql("../../../documentation/introduction/index.html")
current_page = double("current_page", path: current_page_path)
resource_path = get_path_to_resource(config, external_url, current_page)

expect(resource_path).to eql(external_url)
end

it "when the site is configured to generate relative links" do
config = {
relative_links: true,
}

current_page = double("current_page", path: current_page_path)
resource_path = get_path_to_resource(config, external_url, current_page)

expect(resource_path).to eql(external_url)
end
}
end
end

describe "#path_to_site_root" do
it "calculates the path from a page to the site root when using absolute links" do
page_path = "/documentation/introduction/index.html"

it "calculates the path from a page to the site root when the site is configured to generate absolute links" do
config = {
http_prefix: "/", # This is Middleman's default setting.
}

page_path = "/documentation/introduction/index.html"
path_to_site_root = path_to_site_root(config, page_path)

expect(path_to_site_root).to eql("/")
end

it "calculates the path from a page to the site root when a middleman http prefix" do
page_path = "/bananas/documentation/introduction/index.html"

config = {
http_prefix: "/bananas",
}

page_path = "/bananas/documentation/introduction/index.html"
path_to_site_root = path_to_site_root(config, page_path)

expect(path_to_site_root).to eql("/bananas/")
end

it "calculates the path from a page to the site root when using relative links" do
page_path = "/documentation/introduction/index.html"

it "calculates the path from a page to the site root when the site is configured to generate relative links" do
config = {
relative_links: true,
}

page_path = "/documentation/introduction/index.html"
path_to_site_root = path_to_site_root(config, page_path)

expect(path_to_site_root).to eql("../../")
end
end
Expand Down

0 comments on commit 6a1f3e1

Please sign in to comment.