lib/roda/plugins/assets.rb in roda-2.18.0 vs lib/roda/plugins/assets.rb in roda-2.19.0
- old
+ new
@@ -317,19 +317,21 @@
CSS_SUFFIX = '.css'.freeze
HTTP_ACCEPT_ENCODING = 'HTTP_ACCEPT_ENCODING'.freeze
CONTENT_ENCODING = 'Content-Encoding'.freeze
GZIP = 'gzip'.freeze
DOTGZ = '.gz'.freeze
+ EMPTY_ATTRS = {}.freeze
# Internal exception raised when a compressor cannot be found
CompressorNotFound = Class.new(RodaError)
- # Load the render and caching plugins plugins, since the assets plugin
+ # Load the render, caching, and h plugins, since the assets plugin
# depends on them.
def self.load_dependencies(app, _opts = nil)
app.plugin :render
app.plugin :caching
+ app.plugin :h
end
# Setup the options for the plugin. See the Assets module RDoc
# for a description of the supported options.
def self.configure(app, opts = {})
@@ -603,39 +605,27 @@
module InstanceMethods
# Return an array of paths for the given asset type and optionally
# asset group. See the assets function documentation for details.
def assets_paths(type)
o = self.class.assets_opts
- type, *dirs = type if type.is_a?(Array)
- stype = type.to_s
- ru = Rack::Utils
+ if type.is_a?(Array)
+ ltype, *dirs = type
+ else
+ ltype = type
+ end
+ stype = ltype.to_s
url_prefix = request.script_name if self.class.opts[:add_script_name]
if compiled = o[:compiled]
- asset_host = o[:compiled_asset_host]
- if dirs && !dirs.empty?
- key = dirs.join(DOT)
- ckey = "#{stype}.#{key}"
- if hash = ukey = compiled[ckey]
- ukey = "#{key}.#{ukey}"
- end
+ if ukey = _compiled_assets_hash(type, true)
+ ["#{o[:compiled_asset_host]}#{url_prefix}/#{o[:"compiled_#{stype}_prefix"]}.#{ukey}.#{stype}"]
else
- hash = ukey = compiled[stype]
- end
-
- if ukey
- if algo = o[:sri]
- integrity = "\" integrity=\"#{algo}-#{ru.escape_html([[hash].pack('H*')].pack('m').tr("\n", EMPTY_STRING))}"
- end
-
- [ "#{asset_host}#{url_prefix}/#{o[:"compiled_#{stype}_prefix"]}.#{ukey}.#{stype}#{integrity}" ]
- else
[]
end
else
- asset_dir = o[type]
+ asset_dir = o[ltype]
if dirs && !dirs.empty?
dirs.each{|f| asset_dir = asset_dir[f]}
prefix = "#{dirs.join(SLASH)}/" if o[:group_subdirs]
end
Array(asset_dir).map{|f| "#{url_prefix}/#{o[:"#{stype}_prefix"]}#{prefix}#{f}#{o[:"#{stype}_suffix"]}"}
@@ -650,32 +640,30 @@
# the type, such as [:css, :frontend].
#
# When the assets are not compiled, this will result in a separate
# tag for each asset file. When the assets are compiled, this will
# result in a single tag to the compiled asset file.
- def assets(type, attrs = nil)
- ru = Rack::Utils
- attrs = if attrs
- attrs.map{|k,v| "#{k}=\"#{ru.escape_html(v.to_s)}\""}.join(SPACE)
- else
- EMPTY_STRING
- end
+ def assets(type, attrs = EMPTY_ATTRS)
+ ltype = type.is_a?(Array) ? type[0] : type
- ltype = if type.is_a?(Array)
- type[0]
- else
- type
+ o = self.class.assets_opts
+ if o[:compiled] && (algo = o[:sri]) && (hash = _compiled_assets_hash(type))
+ attrs = Hash[attrs]
+ attrs[:integrity] = "#{algo}-#{h([[hash].pack('H*')].pack('m').tr("\n", EMPTY_STRING))}"
end
+
+ attrs = attrs.map{|k,v| "#{k}=\"#{h(v)}\""}.join(SPACE)
+
if ltype == :js
tag_start = "<script type=\"text/javascript\" #{attrs} src=\""
tag_end = JS_END
else
tag_start = "<link rel=\"stylesheet\" #{attrs} href=\""
tag_end = CSS_END
end
- assets_paths(type).map{|p| "#{tag_start}#{p}#{tag_end}"}.join(NEWLINE)
+ assets_paths(type).map{|p| "#{tag_start}#{h(p)}#{tag_end}"}.join(NEWLINE)
end
# Render the asset with the given filename. When assets are compiled,
# or when the file is already of the given type (no rendering necessary),
# this returns the contents of the compiled file.
@@ -716,9 +704,27 @@
o[:postprocessor] ? o[:postprocessor].call(file, type, content) : content
end
private
+
+ def _compiled_assets_hash(type, return_ukey=false)
+ compiled = self.class.assets_opts[:compiled]
+ type, *dirs = type if type.is_a?(Array)
+ stype = type.to_s
+
+ if dirs && !dirs.empty?
+ key = dirs.join(DOT)
+ ckey = "#{stype}.#{key}"
+ if hash = ukey = compiled[ckey]
+ ukey = "#{key}.#{ukey}"
+ end
+ else
+ hash = ukey = compiled[stype]
+ end
+
+ return_ukey ? ukey : hash
+ end
# Return when the file was last modified. If the file depends on any
# other files, check the modification times of all dependencies and
# return the maximum.
def asset_last_modified(file)