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