Module: Adapter::Hpricot
- Defined in:
- lib/premailer/adapter/hpricot.rb
Instance Method Summary collapse
-
#load_html(input) ⇒ Object
Returns an Hpricot document.
-
#to_inline_css ⇒ Object
Returns a string.
-
#to_plain_text ⇒ Object
If present, uses the <body> element as its base; otherwise uses the whole document.
-
#to_s ⇒ Object
Returns the original HTML as a string.
-
#write_unmergable_css_rules(doc, unmergable_rules) ⇒ Object
and write it into the
body
.
Instance Method Details
#load_html(input) ⇒ Object
Returns an Hpricot document.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/premailer/adapter/hpricot.rb', line 162 def load_html(input) # :nodoc: thing = nil # TODO: duplicate options if @options[:with_html_string] or @options[:inline] or input.respond_to?(:read) thing = input elsif @is_local_file @base_dir = File.dirname(input) thing = File.open(input, 'r') else thing = open(input) end # TODO: deal with Hpricot seg faults on empty input thing ? Hpricot(thing) : nil end |
#to_inline_css ⇒ Object
Returns a string.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/premailer/adapter/hpricot.rb', line 8 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| # 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 selector =~ Premailer::RE_UNMERGABLE_SELECTORS @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless @options[:preserve_styles] else begin # 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 Hpricot::Error, RuntimeError, ArgumentError $stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose] next end end end # 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. # Duplicate CSS attributes as HTML attributes if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) Premailer::RELATED_ATTRIBUTES[el.name].each do |css_att, html_att| el[html_att] = merged[css_att].gsub(/;$/, '').strip if el[html_att].nil? and not merged[css_att].empty? end end merged.create_dimensions_shorthand! # write the inline STYLE attribute el['style'] = Premailer.escape_string(merged.declarations_to_s) end doc = write_unmergable_css_rules(doc, @unmergable_rules) if @options[:remove_classes] or @options[:remove_comments] doc.search('*').each do |el| if el.comment? and @options[:remove_comments] lst = el.parent.children el.parent = nil lst.delete(el) elsif el.elem? 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 @processed_doc = doc @processed_doc.to_original_html end |
#to_plain_text ⇒ Object
If present, uses the <body> element as its base; otherwise uses the whole document.
Returns a string.
143 144 145 146 147 148 149 150 151 |
# File 'lib/premailer/adapter/hpricot.rb', line 143 def to_plain_text html_src = '' begin html_src = @doc.search("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 ⇒ Object
Returns the original HTML as a string.
155 156 157 |
# File 'lib/premailer/adapter/hpricot.rb', line 155 def to_s @doc.to_original_html end |
#write_unmergable_css_rules(doc, unmergable_rules) ⇒ Object
and write it into the body
.
doc
is an Hpricot document and unmergable_css_rules
is a Css::RuleSet.
Returns an Hpricot document.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/premailer/adapter/hpricot.rb', line 120 def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc: if head = doc.search('head') styles = '' unmergable_rules.each_selector(:all, :force_important => true) do |selector, declarations, specificity| styles += "#{selector} { #{declarations} }\n" end unless styles.empty? style_tag = "\n<style type=\"text/css\">\n#{styles}</style>\n" head.html.empty? ? head.inner_html(style_tag) : head.append(style_tag) end else $stderr.puts "Unable to write unmergable CSS rules: no <head> was found" if @options[:verbose] end doc end |