diff --git a/middleman-core/features/relative_assets_helpers_only.feature b/middleman-core/features/relative_assets_helpers_only.feature
new file mode 100644
index 00000000..9d508977
--- /dev/null
+++ b/middleman-core/features/relative_assets_helpers_only.feature
@@ -0,0 +1,123 @@
+Feature: Relative Assets (Helpers Only)
+
+ Scenario: Rendering css with the feature enabled
+ Given a fixture app "relative-assets-app"
+ And a file named "config.rb" with:
+ """
+ activate :relative_assets, helpers_only: true
+ """
+ And a file named "source/stylesheets/relative_assets.css.sass.erb" with:
+ """
+ h1
+ background: url("<%= asset_url('images/blank.gif') %>")
+ h2
+ background: url("<%= asset_url('/images/blank2.gif') %>")
+ """
+ And a file named "source/javascripts/application.js.erb" with:
+ """
+ function foo() {
+ var img = document.createElement('img');
+ img.src = '<%= asset_url("images/100px.jpg") %>';
+ var body = document.getElementsByTagName('body')[0];
+ body.insertBefore(img, body.firstChild);
+ }
+
+ window.onload = foo;
+ """
+ And a file named "source/stylesheets/fonts3.css.erb" with:
+ """
+ @font-face {
+ font-family: 'Roboto2';
+ src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot") %>);
+ src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot?#iefix") %>) format('embedded-opentype'),
+ url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.woff") %>) format('woff'),
+ url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.ttf") %>) format('truetype'),
+ url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.svg#robotoregular") %>) format('svg');
+ font-weight: normal;
+ font-style: normal;
+ }
+ """
+ And the Server is running at "relative-assets-app"
+ When I go to "/stylesheets/relative_assets.css"
+ Then I should see 'url("../images/blank.gif'
+ And I should see 'url("../images/blank2.gif'
+ When I go to "/javascripts/application.js"
+ Then I should not see "../"
+ When I go to "/stylesheets/fonts3.css"
+ Then I should see 'url(../fonts/roboto/roboto-regular-webfont.eot'
+ And I should see 'url(../fonts/roboto/roboto-regular-webfont.woff'
+ And I should see 'url(../fonts/roboto/roboto-regular-webfont.ttf'
+ And I should see 'url(../fonts/roboto/roboto-regular-webfont.svg'
+
+ Scenario: Relative css reference with directory indexes
+ Given a fixture app "relative-assets-app"
+ And a file named "config.rb" with:
+ """
+ activate :directory_indexes
+ activate :relative_assets, helpers_only: true
+ """
+ And the Server is running at "relative-assets-app"
+ When I go to "/relative_image/index.html"
+ Then I should see "../stylesheets/relative_assets.css"
+
+ Scenario: Relative assets via image_tag
+ Given a fixture app "relative-assets-app"
+ And a file named "config.rb" with:
+ """
+ activate :relative_assets, helpers_only: true
+ """
+ And a file named "source/sub/image_tag.html.erb" with:
+ """
+ <%= image_tag '/img/blank.gif' %>
+ """
+ And the Server is running at "relative-assets-app"
+ When I go to "/sub/image_tag.html"
+ Then I should see ''
+
+ Scenario: Relative assets should not break data URIs in image_tag
+ Given a fixture app "relative-assets-app"
+ And a file named "config.rb" with:
+ """
+ activate :relative_assets, helpers_only: true
+ """
+ And a file named "source/sub/image_tag.html.erb" with:
+ """
+ <%= image_tag "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" %>
+ """
+ And the Server is running at "relative-assets-app"
+ When I go to "/sub/image_tag.html"
+ Then I should see ''
+
+ Scenario: URLs are not rewritten for rewrite ignored paths
+ Given a fixture app "relative-assets-app"
+ And a file named "config.rb" with:
+ """
+ activate :relative_assets, rewrite_ignore: [
+ '/stylesheets/fonts3.css',
+ ], helpers_only: true
+ """
+ And a file named "source/stylesheets/relative_assets.css.sass.erb" with:
+ """
+ h1
+ background: url("<%= asset_url('images/blank.gif') %>")
+ h2
+ background: url("<%= asset_url('/images/blank2.gif') %>")
+ """
+ And a file named "source/stylesheets/fonts3.css.erb" with:
+ """
+ @font-face {
+ font-family: 'Roboto2';
+ src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot") %>);
+ src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot?#iefix") %>) format('embedded-opentype'),
+ url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.woff") %>) format('woff'),
+ url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.ttf") %>) format('truetype'),
+ url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.svg#robotoregular") %>) format('svg');
+ font-weight: normal;
+ font-style: normal;
+ }
+ """
+ And the Server is running at "relative-assets-app"
+ When I go to "/stylesheets/relative_assets.css"
+ Then I should see 'url("../images/blank.gif'
+ When I go to "/stylesheets/fonts3.css"
+ Then I should see 'url(/fonts/roboto/roboto-regular-webfont.eot'
diff --git a/middleman-core/fixtures/relative-assets-app/source/images/blank2.gif b/middleman-core/fixtures/relative-assets-app/source/images/blank2.gif
new file mode 100644
index 00000000..e69de29b
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 33b411e1..774522db 100644
--- a/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb
+++ b/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb
@@ -1,4 +1,5 @@
require 'padrino-helpers'
+require 'middleman-core/contracts'
# Don't fail on invalid locale, that's not what our current
# users expect.
diff --git a/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb b/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb
index 24d541fa..43354e97 100644
--- a/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb
+++ b/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb
@@ -11,13 +11,12 @@ module Middleman
expose_to_application rewrite_inline_urls: :add
- IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
REWRITER_DESCRIPTOR = {
id: Symbol,
proc: Or[Proc, Method],
url_extensions: ArrayOf[String],
source_extensions: ArrayOf[String],
- ignore: ArrayOf[IGNORE_DESCRIPTOR],
+ ignore: ArrayOf[::Middleman::Util::IGNORE_DESCRIPTOR],
after: Maybe[Symbol]
}.freeze
@@ -109,7 +108,7 @@ module Middleman
next unless source_exts.include?(::File.extname(path))
ignore = rewriter.fetch(:ignore)
- next if ignore.any? { |r| should_ignore?(r, full_asset_path) }
+ next if ignore.any? { |r| ::Middleman::Util.should_ignore?(r, full_asset_path) }
rewrite_ignore = Array(rewriter[:rewrite_ignore] || [])
next if rewrite_ignore.any? { |i| ::Middleman::Util.path_match(i, path) }
@@ -130,24 +129,6 @@ module Middleman
headers
).finish
end
-
- Contract IGNORE_DESCRIPTOR, String => Bool
- def should_ignore?(validator, value)
- if validator.is_a? Regexp
- # Treat as Regexp
- !!(value =~ validator)
- elsif validator.respond_to? :call
- # Treat as proc
- validator.call(value)
- elsif validator.is_a? String
- # Treat as glob
- File.fnmatch(value, validator)
- else
- # If some unknown thing, don't ignore
- false
- end
- end
- memoize :should_ignore?
end
end
end
diff --git a/middleman-core/lib/middleman-core/extensions/relative_assets.rb b/middleman-core/lib/middleman-core/extensions/relative_assets.rb
index 33ac420e..853a7005 100644
--- a/middleman-core/lib/middleman-core/extensions/relative_assets.rb
+++ b/middleman-core/lib/middleman-core/extensions/relative_assets.rb
@@ -2,15 +2,20 @@ require 'addressable/uri'
# Relative Assets extension
class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
- option :exts, nil, 'List of extensions that get cache busters strings appended to them.'
+ option :exts, nil, 'List of extensions that get converted to relative paths.'
option :sources, %w(.css .htm .html .xhtml), 'List of extensions that are searched for relative assets.'
- option :ignore, [], 'Regexes of filenames to skip adding query strings to'
- option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'
+ option :ignore, [], 'Regexes of filenames to skip converting to relative paths.'
+ option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites.'
+ option :helpers_only, false, 'Allow only Ruby helpers to change paths.'
def initialize(app, options_hash={}, &block)
super
- app.rewrite_inline_urls id: :asset_hash,
+ if options[:helpers_only]
+ return
+ end
+
+ app.rewrite_inline_urls id: :relative_assets,
url_extensions: options.exts || app.config[:asset_extensions],
source_extensions: options.sources,
ignore: options.ignore,
@@ -18,16 +23,37 @@ class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
proc: method(:rewrite_url)
end
- helpers do
- # asset_url override for relative assets
- # @param [String] path
- # @param [String] prefix
- # @param [Hash] options Additional options.
- # @return [String]
- def asset_url(path, prefix='', options={})
- options[:relative] = true unless options.key?(:relative)
+ def mark_as_relative(file_path, opts, current_resource)
+ result = opts.dup
- super(path, prefix, options)
+ valid_exts = options.sources
+
+ return result unless current_resource
+ return result unless valid_exts.include?(current_resource.ext)
+
+ rewrite_ignores = Array(options.rewrite_ignore || [])
+
+ path = current_resource.destination_path
+ return result if rewrite_ignores.any? do |i|
+ ::Middleman::Util.path_match(i, path) || ::Middleman::Util.path_match(i, "/#{path}")
+ end
+
+ return result if Array(options.ignore || []).any? do |r|
+ ::Middleman::Util.should_ignore?(r, file_path)
+ end
+
+ result[:relative] = true unless result.key?(:relative)
+
+ result
+ end
+
+ helpers do
+ def asset_url(path, prefix='', options={})
+ super(path, prefix, app.extensions[:relative_assets].mark_as_relative(super, options, current_resource))
+ end
+
+ def asset_path(kind, source, options={})
+ super(kind, source, app.extensions[:relative_assets].mark_as_relative(super, options, current_resource))
end
end
diff --git a/middleman-core/lib/middleman-core/util/paths.rb b/middleman-core/lib/middleman-core/util/paths.rb
index fa25e818..26f29442 100644
--- a/middleman-core/lib/middleman-core/util/paths.rb
+++ b/middleman-core/lib/middleman-core/util/paths.rb
@@ -45,6 +45,25 @@ module Middleman
end
memoize :strip_leading_slash
+ IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
+ Contract IGNORE_DESCRIPTOR, String => Bool
+ def should_ignore?(validator, value)
+ if validator.is_a? Regexp
+ # Treat as Regexp
+ !!(value =~ validator)
+ elsif validator.respond_to? :call
+ # Treat as proc
+ validator.call(value)
+ elsif validator.is_a? String
+ # Treat as glob
+ File.fnmatch(value, validator)
+ else
+ # If some unknown thing, don't ignore
+ false
+ end
+ end
+ memoize :should_ignore?
+
# Get the path of a file of a given type
#
# @param [Middleman::Application] app The app.