diff --git a/middleman-core/features/directory_index.feature b/middleman-core/features/directory_index.feature
index 634267de..0a7db97b 100644
--- a/middleman-core/features/directory_index.feature
+++ b/middleman-core/features/directory_index.feature
@@ -46,10 +46,21 @@ Feature: Directory Index
unknown_link_to: <%= link_to "Unknown", "/unknown.html" %>
relative_link_to: <%= link_to "Relative", "needs_index.html" %>
"""
+ And a file named "source/link_to/sub.html.erb" with:
+ """
+ link_to: <%= link_to "Needs Index", "/needs_index.html" %>
+ explicit_link_to: <%= link_to "Explicit", "/needs_index/index.html" %>
+ unknown_link_to: <%= link_to "Unknown", "/unknown.html" %>
+ relative_link_to: <%= link_to "Relative", "../needs_index.html" %>
+ """
And the Server is running at "indexable-app"
When I go to "/link_to/"
Then I should see 'link_to: Needs Index'
Then I should see 'explicit_link_to: Explicit'
Then I should see 'unknown_link_to: Unknown'
- # Relative links aren't touched
- Then I should see 'relative_link_to: Relative'
\ No newline at end of file
+ Then I should see 'relative_link_to: Relative'
+ When I go to "/link_to/sub/"
+ Then I should see 'link_to: Needs Index'
+ Then I should see 'explicit_link_to: Explicit'
+ Then I should see 'unknown_link_to: Unknown'
+ Then I should see 'relative_link_to: Relative'
\ No newline at end of file
diff --git a/middleman-core/features/helpers_relative_link_to.feature b/middleman-core/features/helpers_relative_link_to.feature
new file mode 100644
index 00000000..b9ba39d2
--- /dev/null
+++ b/middleman-core/features/helpers_relative_link_to.feature
@@ -0,0 +1,68 @@
+Feature: relative_link_to helper
+
+ Scenario: relative_link_to produces relative links
+ Given a fixture app "indexable-app"
+ And an empty file named "config.rb"
+ And a file named "source/link_to.html.erb" with:
+ """
+ absolute: <%= link_to "Needs Index", "/needs_index.html", :relative => true %>
+ relative: <%= link_to "Relative", "needs_index.html", :relative => true %>
+ """
+ And a file named "source/link_to/sub.html.erb" with:
+ """
+ absolute: <%= link_to "Needs Index", "/needs_index.html", :relative => true %>
+ relative: <%= link_to "Relative", "../needs_index.html", :relative => true %>
+ """
+ And the Server is running at "indexable-app"
+ When I go to "/link_to.html"
+ Then I should see 'absolute: Needs Index'
+ Then I should see 'relative: Relative'
+ When I go to "/link_to/sub.html"
+ Then I should see 'absolute: Needs Index'
+ Then I should see 'relative: Relative'
+
+ Scenario: relative_link_to produces relative links when :relative_links is set to true
+ Given a fixture app "indexable-app"
+ And a file named "config.rb" with:
+ """
+ set :relative_links, true
+ """
+ And a file named "source/link_to.html.erb" with:
+ """
+ absolute: <%= link_to "Needs Index", "/needs_index.html" %>
+ relative: <%= link_to "Relative", "needs_index.html", :relative => false %>
+ unknown: <%= link_to "Unknown", "foo.html" %>
+ """
+ And a file named "source/link_to/sub.html.erb" with:
+ """
+ absolute: <%= link_to "Needs Index", "/needs_index.html" %>
+ relative: <%= link_to "Relative", "../needs_index.html" %>
+ """
+ And the Server is running at "indexable-app"
+ When I go to "/link_to.html"
+ Then I should see 'absolute: Needs Index'
+ Then I should see 'relative: Relative'
+ Then I should see 'unknown: Unknown'
+ When I go to "/link_to/sub.html"
+ Then I should see 'absolute: Needs Index'
+ Then I should see 'relative: Relative'
+
+ Scenario: relative_link_to knows about directory indexes
+ Given a fixture app "indexable-app"
+ And a file named "source/link_to.html.erb" with:
+ """
+ absolute: <%= link_to "Needs Index", "/needs_index.html", :relative => true %>
+ relative: <%= link_to "Relative", "needs_index.html", :relative => true %>
+ """
+ And a file named "source/link_to/sub.html.erb" with:
+ """
+ absolute: <%= link_to "Needs Index", "/needs_index.html", :relative => true %>
+ relative: <%= link_to "Relative", "../needs_index.html", :relative => true %>
+ """
+ And the Server is running at "indexable-app"
+ When I go to "/link_to/"
+ Then I should see 'absolute: Needs Index'
+ Then I should see 'relative: Relative'
+ When I go to "/link_to/sub/"
+ Then I should see 'absolute: Needs Index'
+ Then I should see 'relative: Relative'
\ No newline at end of file
diff --git a/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb b/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb
index f695037b..23c5d306 100644
--- a/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb
+++ b/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb
@@ -20,6 +20,8 @@ module Middleman
# app.helpers ::Padrino::Helpers::TranslationHelpers
app.helpers Helpers
+
+ app.set :relative_links, false
end
alias :included :registered
end
@@ -106,18 +108,65 @@ module Middleman
"#{result_path}"
end
+ # Overload the regular link_to to be sitemap-aware - if you
+ # reference a source path, either absolutely or relatively,
+ # you'll get that resource's nice URL. Also, there is a
+ # :relative option which, if set to true, will produce
+ # relative URLs instead of absolute URLs. You can also add
+ #
+ # set :relative_links, true
+ #
+ # to config.rb to have all links default to relative.
def link_to(*args, &block)
url_arg_index = block_given? ? 0 : 1
+ options_index = block_given? ? 1 : 2
+
if url = args[url_arg_index]
- # Only try to work with absolute URLs
- if url.start_with? '/'
+ options = args[options_index] || {}
+ relative = options.delete(:relative)
+
+
+ if url.include? '://'
+ raise "Can't use the relative option with an external URL" if relative
+ else
+ # Handle relative urls
+ current_dir = Pathname('/' + current_resource.path).dirname
+ path = Pathname(url)
+
+ url = current_dir.join(path).to_s if path.relative?
+
resource = sitemap.find_resource_by_path(url)
- args[url_arg_index] = resource.url if resource
+
+ # Allow people to turn on relative paths for all links with set :relative_links, true
+ # but still override on a case by case basis with the :relative parameter.
+ effective_relative = relative || false
+ if relative.nil? && relative_links
+ effective_relative = true
+ end
+
+ if resource
+ if effective_relative
+ resource_url = resource.url
+ new_url = Pathname(resource_url).relative_path_from(current_dir).to_s
+
+ # Put back the trailing slash to avoid unnecessary Apache redirects
+ if resource_url.end_with?('/') && !new_url.end_with?('/')
+ new_url << '/'
+ end
+ else
+ new_url = resource.url
+ end
+
+ args[url_arg_index] = new_url
+ else
+ raise "No resource exists at #{url}" if relative
+ end
end
end
+
super(*args, &block)
end
end
end
end
-end
\ No newline at end of file
+end
diff --git a/middleman-core/lib/middleman-core/sitemap/resource.rb b/middleman-core/lib/middleman-core/sitemap/resource.rb
index 76054b7e..2ca7ae12 100644
--- a/middleman-core/lib/middleman-core/sitemap/resource.rb
+++ b/middleman-core/lib/middleman-core/sitemap/resource.rb
@@ -140,8 +140,8 @@ module Middleman
# just foo. Best for linking.
# @return [String]
def url
- '/' + destination_path.sub(/#{Regexp.escape(app.index_file)}$/, '')
+ ('/' + destination_path).sub(/\/#{Regexp.escape(app.index_file)}$/, '/')
end
end
end
-end
\ No newline at end of file
+end