File: C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/roadie-4.0.0/lib/roadie/url_rewriter.rb
# frozen_string_literal: true
module Roadie
# @api private
#
# Class that rewrites URLs in the DOM.
class UrlRewriter
# @param [UrlGenerator] generator
def initialize(generator)
@generator = generator
end
# Mutates the passed DOM tree, rewriting certain element's attributes.
#
# This will make all a[href] and img[src] into absolute URLs, as well as
# all "url()" directives inside style-attributes.
#
# [nil] is returned so no one can misunderstand that this method mutates
# the passed instance.
#
# @param [Nokogiri::HTML::Document] dom
# @return [nil] DOM tree is mutated
def transform_dom(dom)
# Use only a single loop to do this
dom.css(
"a[href]:not([data-roadie-ignore]), " \
"img[src]:not([data-roadie-ignore]), " \
"*[style]:not([data-roadie-ignore])",
).each do |element|
transform_element_style element if element.has_attribute?('style')
transform_element element
end
nil
end
# Mutates passed CSS, rewriting url() directives.
#
# This will make all URLs inside url() absolute.
#
# Copy of CSS that is mutated is returned, passed string is not mutated.
#
# @param [String] css the css to mutate
# @return [String] copy of css that is mutated
def transform_css(css)
css.gsub(CSS_URL_REGEXP) do
matches = Regexp.last_match
"url(#{matches[:quote]}#{generate_url(matches[:url])}#{matches[:quote]})"
end
end
private
def generate_url(*args) @generator.generate_url(*args) end
# Regexp matching all the url() declarations in CSS
#
# It matches without any quotes and with both single and double quotes
# inside the parenthesis. There's much room for improvement, of course.
CSS_URL_REGEXP = %r{
url\(
(?<quote>
(?:["']|%22)? # Optional opening quote
)
(?<url> # The URL.
# We match URLs with parenthesis inside it here,
# so url(foo(bar)baz) will match correctly.
[^(]* # Text leading up to before opening parens
(?:\([^)]*\))* # Texts containing parens pairs
[^(]+ # Texts without parens - required
)
\k'quote' # Closing quote
\)
}x
def transform_element(element)
case element.name
when "a" then element["href"] = generate_url element["href"]
when "img" then element["src"] = generate_url element["src"]
end
end
def transform_element_style(element)
# We need to use a setter for Nokogiri to detect the string mutation.
# If nokogiri used "dumber" data structures, this would all be redundant.
css = element["style"]
element["style"] = transform_css(css)
end
end
end