module IQ module HTML HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }.freeze # Returns HTML escaped version of supplied string. # # @example # IQ::HTML.escape('Letters, Num83r5, & -- & > -- > < -- < " -- " Ӓ') # #=> 'Letters, Num83r5, & -- &amp; > -- &gt; < -- &lt; " -- &quot; &#1234;' # # @param [String] # @return [String] the escaped string def self.escape(value) raise ArgumentError, 'Must supply a string' unless value.is_a?(String) value.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] } end # Returns HTML escaped version of supplied string leaving any existing # entities intact. # # @example # IQ::HTML.escape_once('Letters, Num83r5, & -- & > -- > < -- < " -- " Ӓ') # #=> 'Letters, Num83r5, & -- & > -- > < -- < " -- " Ӓ' # # @param [String] # @return [String] the escaped string (with existing entities intact) def self.escape_once(value) raise ArgumentError, 'Must supply a string' unless value.is_a?(String) value.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| HTML_ESCAPE[special] } end # Takes a string and returns a new hyphenated string that can safely be # used as a dom id. # # @example # IQ::HTML.sanitize_as_dom_id('product[variants][0][stock]') # #=> 'product-variants-0-stock' # # @param [String] # @return [String] the escaped string (leaving existing entities intact) def self.sanitize_as_dom_id(string_to_sanitize) raise ArgumentError, 'Argument must be a string' unless string_to_sanitize.is_a?(String) # see http://www.w3.org/TR/html4/types.html#type-name string_to_sanitize.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "-") end # Helper method for creating HTML tags of a specified name, along with # optional content and list of attributes. All attribute values and content # will be escaped, however content escaping may be dissabled by supplying # +false+ as the last argument. # # @example # IQ::HTML.tag('br') #=> "
" # IQ::HTML.tag('strong', 'Bill & Ben') #=> "Bill & Ben" # IQ::HTML.tag('strong', 'Bill & Ben', false) #=> "Bill & Ben" # IQ::HTML.tag('strong', 'B&B', { :id => 'bb' }, false) #=> "Bill & Ben" # IQ::HTML.tag('input', :title => 'B&B') #=> '' # IQ::HTML.tag('strong', 'B&B', :title => 'Bill & Ben') #=> "B&B" # # @overload self.tag(name, attributes = {}) # @param [String, Symbol] name # @param [Hash] attributes # @overload self.tag(name, content, escape = true) # @param [String, Symbol] name # @param [String] content # @param [true, false] escape # @overload self.tag(name, content, attributes, escape = true) # @param [String, Symbol] name # @param [String] content # @param [Hash] attributes # @param [true, false] escape # # @return [String] def self.tag(name, *args) raise ArgumentError, 'Name must be a symbol or string' unless name.is_a?(Symbol) || name.is_a?(String) case args.size when 3 then content, attributes, escape = *args when 2 case args.last when Hash then escape, content, attributes = true, *args when true, false then content, escape = *args else raise ArgumentError, 'Third argument must be an attribute hash or boolean escape value' end when 1 case args.last when String then escape, content = true, *args when Hash then attributes = args.last else raise ArgumentError, 'Second argument must be a content string or an attributes hash' end when 0 else raise ArgumentError, "Too many arguments" end raise ArgumentError, 'Content must be in the form of a string' unless content.nil? || content.is_a?(String) raise ArgumentError, 'Attributes must be in the form of a hash' unless attributes.nil? || attributes.is_a?(Hash) raise ArgumentError, 'Escape argument must be a boolean' unless escape.nil? || escape == true || escape == false raise ArgumentError, 'Escape option supplied, but no content to escape' if escape && content.nil? tag = "<#{name}" if attributes attributes.reject! { |key, value| value.nil? } tag << attributes.map { |key, value| %( #{key}="#{escape(value.to_s)}") }.sort.join end tag << (content ? ">#{escape ? escape(content) : content}" : ' />') end end end