module ActionView::Helpers::AssetTagHelper

def audio_tag(*sources)

# =>
audio_tag("sound.wav", "sound.mid")
# =>
audio_tag("sound.wav", autoplay: true, controls: true)
# =>
audio_tag("sound.wav")
# =>
audio_tag("sound")

parameter.
When the last parameter is a hash you can add HTML attributes using that

directory.
+sources+ can be full paths or files that exist in your public audios
tag with nested source tags for each source will be returned. The
a single audio tag will be returned. If +sources+ is an array, an audio
Returns an HTML audio tag for the +sources+. If +sources+ is a string,
def audio_tag(*sources)
  multiple_sources_tag_builder("audio", sources)
end

def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})

# =>
auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {title: "Example RSS"})
# =>
auto_discovery_link_tag(:rss, {controller: "news", action: "feed"})
# =>
auto_discovery_link_tag(:rss, {action: "feed"}, {title: "My RSS"})
# =>
auto_discovery_link_tag(:rss, {action: "feed"})
# =>
auto_discovery_link_tag(:json)
# =>
auto_discovery_link_tag(:atom)
# =>
auto_discovery_link_tag

==== Examples

* :title - Specify the title of the link, defaults to the +type+
* :type - Override the auto-generated mime type
* :rel - Specify the relation of this link, defaults to "alternate"

==== Options

using the +url_options+. You can modify the LINK tag itself in +tag_options+.
:atom, or :json. Control the link options in url_for format
an RSS, Atom, or JSON feed. The +type+ can be :rss (default),
Returns a link tag that browsers and feed readers can use to auto-detect
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
  if !(type == :rss || type == :atom || type == :json) && tag_options[:type].blank?
    raise ArgumentError.new("You should pass :type tag_option key explicitly, because you have passed #{type} type other than :rss, :atom, or :json.")
  end
  tag(
    "link",
    "rel"   => tag_options[:rel] || "alternate",
    "type"  => tag_options[:type] || Template::Types[type].to_s,
    "title" => tag_options[:title] || type.to_s.upcase,
    "href"  => url_options.is_a?(Hash) ? url_for(url_options.merge(only_path: false)) : url_options
  )
end

def check_for_image_tag_errors(options)

def check_for_image_tag_errors(options)
  if options[:size] && (options[:height] || options[:width])
    raise ArgumentError, "Cannot pass a :size option with a :height or :width option"
  end
end

def extract_dimensions(size)

def extract_dimensions(size)
  size = size.to_s
  if /\A(\d+|\d+.\d+)x(\d+|\d+.\d+)\z/.match?(size)
    size.split("x")
  elsif /\A(\d+|\d+.\d+)\z/.match?(size)
    [size, size]
  end
end

def favicon_link_tag(source = "favicon.ico", options = {})

# =>
favicon_link_tag 'mb-icon.png', rel: 'apple-touch-icon', type: 'image/png'

The following call would generate such a tag:
will be used if you add the page to the home screen of an iOS device.
Mobile Safari looks for a different link tag, pointing to an image that

# =>
favicon_link_tag 'myicon.ico'

# =>
favicon_link_tag

respectively:
to override their defaults, "icon" and "image/x-icon"
defaults to "favicon.ico", and also supports +:rel+ and +:type+ options
The helper gets the name of the favicon file as first argument, which

using this helper to generate its corresponding link tag.
their favicon storing the file under app/assets/images, and
To have better control applications may let the asset pipeline manage

request succeeds. If the favicon changes it is hard to get it updated.
ask for /favicon.ico automatically, and cache the file if the
If a page has no link like the one generated by this helper, browsers

Returns a link tag for a favicon managed by the asset pipeline.
def favicon_link_tag(source = "favicon.ico", options = {})
  tag("link", {
    rel: "icon",
    type: "image/x-icon",
    href: path_to_image(source, skip_pipeline: options.delete(:skip_pipeline))
  }.merge!(options.symbolize_keys))
end

def image_tag(source, options = {})

# =>
image_tag(user.avatar.variant(resize_to_limit: [100, 100]), size: '100')
# =>
image_tag(user.avatar.variant(resize_to_limit: [100, 100]))
# =>
image_tag(user.avatar)

Active Storage blobs (images that are uploaded by the users of your app):

# =>
image_tag("pic.jpg", srcset: [["pic_1024.jpg", "1024w"], ["pic_1980.jpg", "1980w"]], sizes: "100vw")
# =>
image_tag("icon.png", srcset: { "icon_2x.png" => "2x", "icon_4x.png" => "4x" })
# =>
image_tag("/icons/icon.gif", data: { title: 'Rails Application' })
# =>
image_tag("/icons/icon.gif", class: "menu_icon")
# =>
image_tag("/icons/icon.gif", height: '32', width: '32')
# =>
image_tag("/icons/icon.gif", size: "16")
# => Edit Entry
image_tag("icon.png", size: "16x10", alt: "Edit Entry")
# =>
image_tag("icon.png")
# =>
image_tag("icon")

Assets (images that are part of your app):

==== Examples

pairs, each image path will be expanded before the list is formatted as a string.
* :srcset - If supplied as a hash or array of [source, descriptor]
:size will be ignored if the value is not in the correct format.
width="30" and height="45", and "50" becomes width="50" and height="50".
* :size - Supplied as "{Width}x{Height}" or "{Number}", so "30x45" becomes

additional keys for convenience and conformance:
You can add HTML attributes using the +options+. The +options+ supports

==== Options

path, a file, or an Active Storage attachment.
Returns an HTML image tag for the +source+. The +source+ can be a full
def image_tag(source, options = {})
  options = options.symbolize_keys
  check_for_image_tag_errors(options)
  skip_pipeline = options.delete(:skip_pipeline)
  options[:src] = resolve_image_source(source, skip_pipeline)
  if options[:srcset] && !options[:srcset].is_a?(String)
    options[:srcset] = options[:srcset].map do |src_path, size|
      src_path = path_to_image(src_path, skip_pipeline: skip_pipeline)
      "#{src_path} #{size}"
    end.join(", ")
  end
  options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
  options[:loading] ||= image_loading if image_loading
  options[:decoding] ||= image_decoding if image_decoding
  tag("img", options)
end

def javascript_include_tag(*sources)

# =>
javascript_include_tag "http://www.example.com/xmlhr.js", nonce: true

# =>
javascript_include_tag "http://www.example.com/xmlhr.js"

# =>
javascript_include_tag "http://www.example.com/xmlhr"

#
# =>
javascript_include_tag "common.javascript", "/elsewhere/cools"

# =>
javascript_include_tag "xmlhr.js"

# =>
javascript_include_tag "template.jst", extname: false

# =>
javascript_include_tag "xmlhr", host: "localhost", protocol: "https"

# =>
javascript_include_tag "xmlhr"

==== Examples

you have Content Security Policy enabled.
* :nonce - When set to true, adds an automatic nonce value if
when it is set to true.
* :skip_pipeline - This option is used to bypass the asset pipeline
that path.
* :host - When a relative URL is provided the host is added to the
applies when a relative URL and +host+ options are provided.
* :protocol - Sets the protocol of the generated URL. This option only
already exists. This only applies for relative URLs.
* :extname - Append an extension to the generated URL unless the extension

parameter. The following options are supported:
When the last parameter is a hash you can add HTML attributes using that

==== Options

automatically pushed.
If the server supports Early Hints header links for these assets will be

source, and include other JavaScript or CoffeeScript files inside the manifest.
When the Asset Pipeline is enabled, you can pass the name of your manifest as

last argument.
You can modify the HTML attributes of the script tag by passing a hash as the

appended to the path extname: false can be set on the options.
When passing paths, the ".js" extension is optional. If you do not want ".js"

root. Relative paths are idiomatic, use absolute paths only when needed.
to assets/javascripts, full paths are assumed to be relative to the document
Sources may be paths to JavaScript files. Relative paths are assumed to be relative

Returns an HTML script tag for each of the +sources+ provided.
def javascript_include_tag(*sources)
  options = sources.extract_options!.stringify_keys
  path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
  preload_links = []
  nopush = options["nopush"].nil? ? true : options.delete("nopush")
  crossorigin = options.delete("crossorigin")
  crossorigin = "anonymous" if crossorigin == true
  integrity = options["integrity"]
  rel = options["type"] == "module" ? "modulepreload" : "preload"
  sources_tags = sources.uniq.map { |source|
    href = path_to_javascript(source, path_options)
    if preload_links_header && !options["defer"] && href.present? && !href.start_with?("data:")
      preload_link = "<#{href}>; rel=#{rel}; as=script"
      preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
      preload_link += "; integrity=#{integrity}" unless integrity.nil?
      preload_link += "; nopush" if nopush
      preload_links << preload_link
    end
    tag_options = {
      "src" => href,
      "crossorigin" => crossorigin
    }.merge!(options)
    if tag_options["nonce"] == true
      tag_options["nonce"] = content_security_policy_nonce
    end
    content_tag("script", "", tag_options)
  }.join("\n").html_safe
  if preload_links_header
    send_preload_links_header(preload_links)
  end
  sources_tags
end

def multiple_sources_tag_builder(type, sources)

def multiple_sources_tag_builder(type, sources)
  options       = sources.extract_options!.symbolize_keys
  skip_pipeline = options.delete(:skip_pipeline)
  sources.flatten!
  yield options if block_given?
  if sources.size > 1
    content_tag(type, options) do
      safe_join sources.map { |source| tag("source", src: send("path_to_#{type}", source, skip_pipeline: skip_pipeline)) }
    end
  else
    options[:src] = send("path_to_#{type}", sources.first, skip_pipeline: skip_pipeline)
    content_tag(type, nil, options)
  end
end

def preload_link_tag(source, options = {})


# =>
preload_link_tag("/media/audio.ogg", nopush: true)

# =>
preload_link_tag("//example.com/font.woff2", crossorigin: "use-credentials")

# =>
preload_link_tag("//example.com/font.woff2")

# =>
preload_link_tag("worker.js", as: "worker")

# =>
preload_link_tag(post_path(format: :json), as: "fetch")

# =>
preload_link_tag("/videos/video.webm")

# =>
preload_link_tag("custom_theme.css")

==== Examples

* :integrity - Specify the integrity attribute.
* :nopush - Specify if the use of server push is not desired for the resource. Defaults to +false+.
* :crossorigin - Specify the crossorigin attribute, required to load cross-origin resources.
* :as - Override the auto-generated value for as attribute, calculated using +source+ extension and mime type.
* :type - Override the auto-generated mime type, defaults to the mime type for +source+ extension.

==== Options

a full path, or an URI.
The +source+ can be the path of a resource managed by asset pipeline,
Returns a link tag that browsers can use to preload the +source+.
def preload_link_tag(source, options = {})
  href = path_to_asset(source, skip_pipeline: options.delete(:skip_pipeline))
  extname = File.extname(source).downcase.delete(".")
  mime_type = options.delete(:type) || Template::Types[extname]&.to_s
  as_type = options.delete(:as) || resolve_link_as(extname, mime_type)
  crossorigin = options.delete(:crossorigin)
  crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
  integrity = options[:integrity]
  nopush = options.delete(:nopush) || false
  rel = mime_type == "module" ? "modulepreload" : "preload"
  link_tag = tag.link(**{
    rel: rel,
    href: href,
    as: as_type,
    type: mime_type,
    crossorigin: crossorigin
  }.merge!(options.symbolize_keys))
  preload_link = "<#{href}>; rel=#{rel}; as=#{as_type}"
  preload_link += "; type=#{mime_type}" if mime_type
  preload_link += "; crossorigin=#{crossorigin}" if crossorigin
  preload_link += "; integrity=#{integrity}" if integrity
  preload_link += "; nopush" if nopush
  send_preload_links_header([preload_link])
  link_tag
end

def resolve_image_source(source, skip_pipeline)

def resolve_image_source(source, skip_pipeline)
  if source.is_a?(Symbol) || source.is_a?(String)
    path_to_image(source, skip_pipeline: skip_pipeline)
  else
    polymorphic_url(source)
  end
rescue NoMethodError => e
  raise ArgumentError, "Can't resolve image into URL: #{e}"
end

def resolve_link_as(extname, mime_type)

def resolve_link_as(extname, mime_type)
  case extname
  when "js"  then "script"
  when "css" then "style"
  when "vtt" then "track"
  else
    mime_type.to_s.split("/").first.presence_in(%w(audio video font image))
  end
end

def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)

Some HTTP client and proxies have a 8kiB header limit
def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)
  return if preload_links.empty?
  return if respond_to?(:response) && response&.sending?
  if respond_to?(:request) && request
    request.send_early_hints("Link" => preload_links.join("\n"))
  end
  if respond_to?(:response) && response
    header = response.headers["Link"]
    header = header ? header.dup : +""
    # rindex count characters not bytes, but we assume non-ascii characters
    # are rare in urls, and we have a 192 bytes margin.
    last_line_offset = header.rindex("\n")
    last_line_size = if last_line_offset
      header.bytesize - last_line_offset
    else
      header.bytesize
    end
    preload_links.each do |link|
      if link.bytesize + last_line_size + 1 < max_header_size
        unless header.empty?
          header << ","
          last_line_size += 1
        end
      else
        header << "\n"
        last_line_size = 0
      end
      header << link
      last_line_size += link.bytesize
    end
    response.headers["Link"] = header
  end
end

def stylesheet_link_tag(*sources)

#
# =>
stylesheet_link_tag "random.styles", "/css/stylish"

# =>
stylesheet_link_tag "style", media: "print"

# =>
stylesheet_link_tag "style", media: "all"

# =>
stylesheet_link_tag "style.less", extname: false, skip_pipeline: true, rel: "stylesheet/less"

# =>
stylesheet_link_tag "http://www.example.com/style.css"

# =>
stylesheet_link_tag "style.css"

# =>
stylesheet_link_tag "style"

==== Examples

when it is set to true.
* :skip_pipeline - This option is used to bypass the asset pipeline
that path.
* :host - When a relative URL is provided the host is added to the
applies when a relative URL and +host+ options are provided.
* :protocol - Sets the protocol of the generated URL. This option only
already exists. This only applies for relative URLs.
* :extname - Append an extension to the generated URL unless the extension

==== Options

automatically pushed.
If the server supports Early Hints header links for these assets will be

You can modify the link attributes by passing a hash as the last argument.
set extname: false in the options.
If you do not want .css appended to the path,
If you don't specify an extension, .css will be appended automatically.
When passing paths, the .css extension is optional.

Returns a stylesheet link tag for the sources specified as arguments.
def stylesheet_link_tag(*sources)
  options = sources.extract_options!.stringify_keys
  path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
  preload_links = []
  crossorigin = options.delete("crossorigin")
  crossorigin = "anonymous" if crossorigin == true
  nopush = options["nopush"].nil? ? true : options.delete("nopush")
  integrity = options["integrity"]
  sources_tags = sources.uniq.map { |source|
    href = path_to_stylesheet(source, path_options)
    if preload_links_header && href.present? && !href.start_with?("data:")
      preload_link = "<#{href}>; rel=preload; as=style"
      preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
      preload_link += "; integrity=#{integrity}" unless integrity.nil?
      preload_link += "; nopush" if nopush
      preload_links << preload_link
    end
    tag_options = {
      "rel" => "stylesheet",
      "crossorigin" => crossorigin,
      "href" => href
    }.merge!(options)
    if apply_stylesheet_media_default && tag_options["media"].blank?
      tag_options["media"] = "screen"
    end
    tag(:link, tag_options)
  }.join("\n").html_safe
  if preload_links_header
    send_preload_links_header(preload_links)
  end
  sources_tags
end

def video_tag(*sources)

# =>
video_tag(["trailer.ogg", "trailer.flv"], size: "160x120")
# =>
video_tag(["trailer.ogg", "trailer.flv"])
# =>
video_tag("trailer.ogg", "trailer.flv")
# =>
video_tag("/trailers/hd.avi", height: '32', width: '32')
# =>
video_tag("/trailers/hd.avi", size: "16")
# =>
video_tag("/trailers/hd.avi", size: "16x16")
# =>
video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png", poster_skip_pipeline: true)
# =>
video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png")
# =>
video_tag("trailer.ogg", controls: true, preload: 'none')
# =>
video_tag("trailer.ogg")
# =>
video_tag("trailer")

==== Examples

the :poster option instead using an asset in the public folder.
* :poster_skip_pipeline will bypass the asset pipeline when using
:size will be ignored if the value is not in the correct format.
width="30" and height="45", and "50" becomes width="50" and height="50".
* :size - Supplied as "{Width}x{Height}" or "{Number}", so "30x45" becomes
before the video loads. The path is calculated like the +src+ of +image_tag+.
* :poster - Set an image (like a screenshot) to be shown

parameter. The following options are supported:
When the last parameter is a hash you can add HTML attributes using that

==== Options

directory.
+sources+ can be full paths or files that exist in your public videos
tag with nested source tags for each source will be returned. The
a single video tag will be returned. If +sources+ is an array, a video
Returns an HTML video tag for the +sources+. If +sources+ is a string,
def video_tag(*sources)
  options = sources.extract_options!.symbolize_keys
  public_poster_folder = options.delete(:poster_skip_pipeline)
  sources << options
  multiple_sources_tag_builder("video", sources) do |tag_options|
    tag_options[:poster] = path_to_image(tag_options[:poster], skip_pipeline: public_poster_folder) if tag_options[:poster]
    tag_options[:width], tag_options[:height] = extract_dimensions(tag_options.delete(:size)) if tag_options[:size]
  end
end