module Premailer::Adapter::Nokogumbo
Nokogiri
adapter
Public Instance Methods
to_inline_css()
click to toggle source
Merge CSS into the HTML document.
@return [String] an HTML.
# File lib/premailer/adapter/nokogumbo.rb, line 12 def to_inline_css doc = @processed_doc @unmergable_rules = CssParser::Parser.new # Give all styles already in style attributes a specificity of 1000 # per http://www.w3.org/TR/CSS21/cascade.html#specificity doc.search("*[@style]").each do |el| el['style'] = '[SPEC=1000[' + el.attributes['style'] + ']]' end # Iterate through the rules and merge them into the HTML @css_parser.each_selector(:all) do |selector, declaration, specificity, media_types| # Save un-mergable rules separately selector.gsub!(/:link([\s]*)+/i) { |m| $1 } # Convert element names to lower case selector.gsub!(/([\s]|^)([\w]+)/) { |m| $1.to_s + $2.to_s.downcase } if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles] else begin if selector =~ Premailer::RE_RESET_SELECTORS # this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/ # however, this doesn't mean for testing pur @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset] end # Change single ID CSS selectors into xpath so that we can match more # than one element. Added to work around dodgy generated code. selector.gsub!(/\A\#([\w_\-]+)\Z/, '*[@id=\1]') doc.search(selector).each do |el| if el.elem? and (el.name != 'head' and el.parent.name != 'head') # Add a style attribute or append to the existing one block = "[SPEC=#{specificity}[#{declaration}]]" el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block end end rescue ::Nokogiri::SyntaxError, RuntimeError, ArgumentError $stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose] next end end end # Remove script tags doc.search("script").remove if @options[:remove_scripts] # Read STYLE attributes and perform folding doc.search("*[@style]").each do |el| style = el.attributes['style'].to_s declarations = [] style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration| rs = CssParser::RuleSet.new(nil, declaration[1].to_s, declaration[0].to_i) declarations << rs end # Perform style folding merged = CssParser.merge(declarations) merged.expand_shorthand! # Duplicate CSS attributes as HTML attributes if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) && @options[:css_to_attributes] Premailer::RELATED_ATTRIBUTES[el.name].each do |css_attr, html_attr| if el[html_attr].nil? and not merged[css_attr].empty? new_val = merged[css_attr].dup # Remove url() function wrapper new_val.gsub!(/url\((['"])(.*?)\1\)/, '\2') # Remove !important, trailing semi-colon, and leading/trailing whitespace new_val.gsub!(/;$|\s*!important/, '').strip! # For width and height tags, remove px units new_val.gsub!(/(\d+)px/, '\1') if %w[width height].include?(html_attr) # For color-related tags, convert RGB to hex if specified by options new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes] el[html_attr] = new_val end unless @options[:preserve_style_attribute] merged.instance_variable_get("@declarations").tap do |declarations| declarations.delete(css_attr) end end end end # Collapse multiple rules into one as much as possible. merged.create_shorthand! if @options[:create_shorthands] # write the inline STYLE attribute el['style'] = merged.declarations_to_s end doc = write_unmergable_css_rules(doc, @unmergable_rules) unless @options[:drop_unmergeable_css_rules] if @options[:remove_classes] or @options[:remove_comments] doc.traverse do |el| if el.comment? and @options[:remove_comments] el.remove elsif el.element? el.remove_attribute('class') if @options[:remove_classes] end end end if @options[:remove_ids] # find all anchor's targets and hash them targets = [] doc.search("a[@href^='#']").each do |el| target = el.get_attribute('href')[1..-1] targets << target el.set_attribute('href', "#" + Digest::MD5.hexdigest(target)) end # hash ids that are links target, delete others doc.search("*[@id]").each do |el| id = el.get_attribute('id') if targets.include?(id) el.set_attribute('id', Digest::MD5.hexdigest(id)) else el.remove_attribute('id') end end end if @options[:reset_contenteditable] doc.search('*[@contenteditable]').each do |el| el.remove_attribute('contenteditable') end end @processed_doc = doc if is_xhtml? # we don't want to encode carriage returns @processed_doc.to_xhtml(:encoding => @options[:output_encoding]).gsub(/&\#(xD|13);/i, "\r") else @processed_doc.to_html(:encoding => @options[:output_encoding]) end end
to_plain_text()
click to toggle source
Converts the HTML document to a format suitable for plain-text e-mail.
If present, uses the <body> element as its base; otherwise uses the whole document.
@return [String] a plain text.
# File lib/premailer/adapter/nokogumbo.rb, line 186 def to_plain_text html_src = '' begin html_src = @doc.at("body").inner_html rescue; end html_src = @doc.to_html unless html_src and not html_src.empty? convert_to_text(html_src, @options[:line_length], @html_encoding) end
to_s()
click to toggle source
Gets the original HTML as a string. @return [String] HTML.
# File lib/premailer/adapter/nokogumbo.rb, line 199 def to_s if is_xhtml? @doc.to_xhtml(:encoding => nil) else @doc.to_html(:encoding => nil) end end