premailer 1.9.2 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4df1d858e475536189c6e91cb30d72194cf8d88b
4
- data.tar.gz: 39daad276db1125fc182e4da80ce8635debe9959
3
+ metadata.gz: 3b62798f9ef3929357e4fe01538d05615f37b9b3
4
+ data.tar.gz: f0224b7a6a42b88ebea688cf9d55fe30504f9751
5
5
  SHA512:
6
- metadata.gz: 335cb3dc57599aba6fe75eba289a250abed56b9180ffc11feb129a0b90f49d9845f92d475329dfc2ba9ec9623e69f295bc844af35a66ca790914988e0f733620
7
- data.tar.gz: d7401533fdfda12a308377cf6719e38461aafdf4c7f9b3c0eedef3998e8ef27c2126671e077d20e70aea82bb1dec3ee492b4b60545b5590e921bfb4a85628407
6
+ metadata.gz: 96bfa7a6374f3cd91f6004a8a988d46e789bd2cce29e12f595fee64c0e86244236e77766b1380a347329dbd71866f487ca23f9aedab0d600b2cf1a54a1c3253f
7
+ data.tar.gz: 09148edbb09bee950ad6e5c7c97709587b862136a38b5f484ab8e5f039f92f137ce7b948303796480004b31018e0f4ebe488d68c4ae1767f0f61d141d11f8db7
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Premailer README [![Build Status](https://travis-ci.org/premailer/premailer.png?branch=master)](https://travis-ci.org/premailer/premailer)
1
+ # Premailer README [![Build Status](https://travis-ci.org/premailer/premailer.png?branch=master)](https://travis-ci.org/premailer/premailer) [![Gem Version](https://badge.fury.io/rb/premailer.svg)](https://badge.fury.io/rb/premailer)
2
2
 
3
3
  ## What is this?
4
4
 
@@ -50,14 +50,13 @@ end
50
50
 
51
51
  ## Adapters
52
52
 
53
- Premailer's default adapter is nokogiri if both nokogiri and hpricot are included in the Gemfile list. However, if you want to use a different adapter, you can choose to.
53
+ Premailer's default adapter is nokogiri if both nokogiri and nokogumbo are included in the Gemfile list. However, if you want to use a different adapter, you can choose to.
54
54
 
55
- There are four adapters in total (as of premailer 1.9.1)
55
+ There are three adapters in total (as of premailer 1.9.1)
56
56
 
57
57
  1. nokogiri (default)
58
58
  2. nokogiri_fast
59
59
  3. nokogumbo
60
- 4. hpricot (deprecated and will be removed in future premailer releases)
61
60
 
62
61
  `NokogiriFast` adapter improves the Algorithmic complexity of the running time by 20x with a slight compensation on memory. To switch to any of these adapters, add the following line. For example, if you want to include the `NokogiriFast` adapter,
63
62
 
@@ -113,5 +112,5 @@ and to [Campaign Monitor](https://www.campaignmonitor.com/) for supporting the w
113
112
 
114
113
  The source code can be found on [GitHub](https://github.com/premailer/premailer).
115
114
 
116
- Copyright by Alex Dunae (dunae.ca, e-mail 'code' at the same domain), 2007-2017. See [LICENSE.md](https://github.com/alexdunae/premailer/blob/master/LICENSE.md) for license details.
115
+ Copyright by Alex Dunae (dunae.ca, e-mail 'code' at the same domain), 2007-2017. See [LICENSE.md](https://github.com/premailer/premailer/blob/master/LICENSE.md) for license details.
117
116
 
@@ -4,10 +4,8 @@ class Premailer
4
4
  # * nokogiri
5
5
  # * nokogiri_fast
6
6
  # * nokogumbo
7
- # * hpricot
8
7
  module Adapter
9
8
 
10
- autoload :Hpricot, 'premailer/adapter/hpricot'
11
9
  autoload :Nokogiri, 'premailer/adapter/nokogiri'
12
10
  autoload :NokogiriFast, 'premailer/adapter/nokogiri_fast'
13
11
  autoload :Nokogumbo, 'premailer/adapter/nokogumbo'
@@ -17,7 +15,6 @@ class Premailer
17
15
  ["nokogiri", :nokogiri],
18
16
  ["nokogiri", :nokogiri_fast],
19
17
  ["nokogumbo", :nokogumbo],
20
- ["hpricot", :hpricot],
21
18
  ]
22
19
 
23
20
  # Returns the adapter to use.
@@ -35,7 +32,6 @@ class Premailer
35
32
  return :nokogiri if defined?(::Nokogiri)
36
33
  return :nokogiri_fast if defined?(::NokogiriFast)
37
34
  return :nokogumbo if defined?(::Nokogumbo)
38
- return :hpricot if defined?(::Hpricot)
39
35
 
40
36
  REQUIREMENT_MAP.each do |(library, adapter)|
41
37
  begin
@@ -46,7 +42,7 @@ class Premailer
46
42
  end
47
43
  end
48
44
 
49
- raise RuntimeError.new("No suitable adapter for Premailer was found, please install hpricot or nokogiri")
45
+ raise RuntimeError.new("No suitable adapter for Premailer was found, please install nokogiri or nokogumbo")
50
46
  end
51
47
 
52
48
  # Sets the adapter to use.
@@ -144,25 +144,19 @@ class Premailer
144
144
  end
145
145
 
146
146
  # Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
147
- # and write it into the <tt>body</tt>.
147
+ # and write it into the <tt>head</tt>.
148
148
  #
149
149
  # <tt>doc</tt> is an Nokogiri document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
150
150
  #
151
151
  # @return [::Nokogiri::XML] a document.
152
152
  def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
153
153
  styles = unmergable_rules.to_s
154
-
155
154
  unless styles.empty?
156
- style_tag = "<style type=\"text/css\">\n#{styles}</style>"
157
- unless (body = doc.search('body')).empty?
158
- if doc.at_css('body').children && !doc.at_css('body').children.empty?
159
- doc.at_css('body').children.before(::Nokogiri::XML.fragment(style_tag))
160
- else
161
- doc.at_css('body').add_child(::Nokogiri::XML.fragment(style_tag))
162
- end
163
- else
164
- doc.inner_html = style_tag += doc.inner_html
165
- end
155
+ style_tag = doc.create_element "style", "#{styles}"
156
+ head = doc.at_css('head')
157
+ head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
158
+ head ||= doc.add_child(doc.create_element "head")
159
+ head << style_tag
166
160
  end
167
161
  doc
168
162
  end
@@ -146,26 +146,19 @@ class Premailer
146
146
  end
147
147
 
148
148
  # Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
149
- # and write it into the <tt>body</tt>.
149
+ # and write it into the <tt>head</tt>.
150
150
  #
151
151
  # <tt>doc</tt> is an Nokogiri document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
152
152
  #
153
153
  # @return [::Nokogiri::XML] a document.
154
154
  def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
155
155
  styles = unmergable_rules.to_s
156
-
157
- unless styles.empty?
158
- style_tag = "<style type=\"text/css\">\n#{styles}</style>"
159
- unless (body = doc.search('body')).empty?
160
- if doc.at_css('body').children && !doc.at_css('body').children.empty?
161
- doc.at_css('body').children.before(::Nokogiri::XML.fragment(style_tag))
162
- else
163
- doc.at_css('body').add_child(::Nokogiri::XML.fragment(style_tag))
164
- end
165
- else
166
- doc.inner_html = style_tag += doc.inner_html
167
- end
168
- end
156
+ return doc if styles.empty?
157
+ style_tag = doc.create_element "style", styles
158
+ head = doc.at_css('head')
159
+ head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
160
+ head ||= doc.add_child(doc.create_element "head")
161
+ head << style_tag
169
162
  doc
170
163
  end
171
164
 
@@ -143,26 +143,19 @@ class Premailer
143
143
  end
144
144
 
145
145
  # Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
146
- # and write it into the <tt>body</tt>.
146
+ # and write it into the <tt>head</tt>.
147
147
  #
148
148
  # <tt>doc</tt> is an Nokogiri document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
149
149
  #
150
150
  # @return [::Nokogiri::XML] a document.
151
151
  def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
152
152
  styles = unmergable_rules.to_s
153
-
154
- unless styles.empty?
155
- style_tag = "<style type=\"text/css\">\n#{styles}</style>"
156
- unless (body = doc.search('body')).empty?
157
- if doc.at_css('body').children && !doc.at_css('body').children.empty?
158
- doc.at_css('body').children.before(::Nokogiri::XML.fragment(style_tag))
159
- else
160
- doc.at_css('body').add_child(::Nokogiri::XML.fragment(style_tag))
161
- end
162
- else
163
- doc.inner_html = style_tag += doc.inner_html
164
- end
165
- end
153
+ return doc if styles.empty?
154
+ style_tag = doc.create_element "style", styles
155
+ head = doc.at_css('head')
156
+ head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
157
+ head ||= doc.add_child(doc.create_element "head")
158
+ head << style_tag
166
159
  doc
167
160
  end
168
161
 
@@ -3,11 +3,12 @@ require 'premailer'
3
3
 
4
4
  # defaults
5
5
  options = {
6
- :base_url => nil,
6
+ :base_url => nil,
7
7
  :link_query_string => nil,
8
- :remove_classes => false,
9
- :verbose => false,
10
- :line_length => 65
8
+ :remove_classes => false,
9
+ :verbose => false,
10
+ :line_length => 65,
11
+ :adapter => :nokogiri,
11
12
  }
12
13
 
13
14
  mode = :html
@@ -28,6 +29,10 @@ opts = OptionParser.new do |opts|
28
29
  mode = v
29
30
  end
30
31
 
32
+ opts.on("--adapter ADAPTER", [:nokogiri, :nokogiri_fast, :nokogumbo], "Adapter: nokogiri, nokogiri_fast or nokogumbo (default: #{options[:adapter]}") do |v|
33
+ options[:adapter] = v
34
+ end
35
+
31
36
  opts.on("-b", "--base-url STRING", String, "Base URL, useful for local files") do |v|
32
37
  options[:base_url] = v
33
38
  end
@@ -40,12 +45,12 @@ opts = OptionParser.new do |opts|
40
45
  options[:css] = v
41
46
  end
42
47
 
43
- opts.on("-r", "--remove-classes", "Remove HTML classes") do |v|
44
- options[:remove_classes] = v
48
+ opts.on("-r", "--remove-classes", "Remove HTML classes") do
49
+ options[:remove_classes] = true
45
50
  end
46
51
 
47
- opts.on("-j", "--remove-scripts", "Remove <script> elements") do |v|
48
- options[:remove_scripts] = v
52
+ opts.on("-j", "--remove-scripts", "Remove <script> elements") do
53
+ options[:remove_scripts] = true
49
54
  end
50
55
 
51
56
  opts.on("-l", "--line-length N", Integer, "Line length for plaintext (default: #{options[:line_length].to_s})") do |v|
@@ -56,12 +61,12 @@ opts = OptionParser.new do |opts|
56
61
  options[:output_encoding] = "US-ASCII"
57
62
  end
58
63
 
59
- opts.on("-d", "--io-exceptions", "Abort on I/O errors") do |v|
60
- options[:io_exceptions] = v
64
+ opts.on("-d", "--io-exceptions", "Abort on I/O errors") do
65
+ options[:io_exceptions] = true
61
66
  end
62
67
 
63
- opts.on("-v", "--verbose", "Print additional information at runtime") do |v|
64
- options[:verbose] = v
68
+ opts.on("-v", "--verbose", "Print additional information at runtime") do
69
+ options[:verbose] = true
65
70
  end
66
71
 
67
72
  opts.on_tail("-?", "--help", "Show this message") do
@@ -121,10 +121,10 @@ class Premailer
121
121
  # unmergeable CSS rules to be preserved in the head (CssParser)
122
122
  attr_reader :unmergable_rules
123
123
 
124
- # processed HTML document (Hpricot/Nokogiri)
124
+ # processed HTML document (Nokogiri/Nokogumbo)
125
125
  attr_reader :processed_doc
126
126
 
127
- # source HTML document (Hpricot/Nokogiri)
127
+ # source HTML document (Nokogiri/Nokogumbo)
128
128
  attr_reader :doc
129
129
 
130
130
  # Warning levels
@@ -174,7 +174,7 @@ class Premailer
174
174
  # @option options [String] :input_encoding Manually specify the source documents encoding. This is a good idea. Default is ASCII-8BIT.
175
175
  # @option options [Boolean] :replace_html_entities Convert HTML entities to actual characters. Default is false.
176
176
  # @option options [Boolean] :escape_url_attributes URL Escapes href, src, and background attributes on elements. Default is true.
177
- # @option options [Symbol] :adapter Which HTML parser to use, either <tt>:nokogiri</tt> or <tt>:hpricot</tt>. Default is <tt>:hpricot</tt>.
177
+ # @option options [Symbol] :adapter Which HTML parser to use, <tt>:nokogiri</tt>, <tt>:nokogiri_fast</tt> or <tt>:nokogumbo</tt>. Default is <tt>:nokogiri</tt>.
178
178
  # @option options [String] :output_encoding Output encoding option for Nokogiri adapter. Should be set to "US-ASCII" to output HTML entities instead of Unicode characters.
179
179
  # @option options [Boolean] :create_shorthands Combine several properties into a shorthand one, e.g. font: style weight size. Default is true.
180
180
  def initialize(html, options = {})
@@ -411,9 +411,9 @@ public
411
411
  # Processes <tt>href</tt> <tt>src</tt> and <tt>background</tt> attributes
412
412
  # as well as CSS <tt>url()</tt> declarations found in inline <tt>style</tt> attributes.
413
413
  #
414
- # <tt>doc</tt> is an Hpricot document and <tt>base_uri</tt> is either a string or a URI.
414
+ # <tt>doc</tt> is a document and <tt>base_uri</tt> is either a string or a URI.
415
415
  #
416
- # Returns an Hpricot document.
416
+ # Returns a document.
417
417
  def convert_inline_links(doc, base_uri) # :nodoc:
418
418
  base_uri = URI.parse(base_uri) unless base_uri.kind_of?(URI)
419
419
 
@@ -1,4 +1,4 @@
1
1
  class Premailer
2
2
  # Premailer version.
3
- VERSION = '1.9.2'.freeze
3
+ VERSION = '1.10.0'.freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: premailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.2
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dunae
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-03 00:00:00.000000000 Z
11
+ date: 2017-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: css_parser
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.4.8
19
+ version: 1.4.9
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 1.4.8
26
+ version: 1.4.9
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: htmlentities
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.3'
55
55
  - !ruby/object:Gem::Dependency
@@ -72,40 +72,20 @@ dependencies:
72
72
  - - "!="
73
73
  - !ruby/object:Gem::Version
74
74
  version: 0.9.0
75
- - !ruby/object:Gem::Dependency
76
- name: hpricot
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- version: 0.8.3
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: 0.8.3
89
75
  - !ruby/object:Gem::Dependency
90
76
  name: nokogiri
91
77
  requirement: !ruby/object:Gem::Requirement
92
78
  requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: 1.4.4
96
- - - "<="
79
+ - - "~>"
97
80
  - !ruby/object:Gem::Version
98
- version: 1.6.8
81
+ version: '1.7'
99
82
  type: :development
100
83
  prerelease: false
101
84
  version_requirements: !ruby/object:Gem::Requirement
102
85
  requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: 1.4.4
106
- - - "<="
86
+ - - "~>"
107
87
  - !ruby/object:Gem::Version
108
- version: 1.6.8
88
+ version: '1.7'
109
89
  - !ruby/object:Gem::Dependency
110
90
  name: yard
111
91
  requirement: !ruby/object:Gem::Requirement
@@ -192,7 +172,7 @@ dependencies:
192
172
  version: '0'
193
173
  description: Improve the rendering of HTML emails by making CSS inline, converting
194
174
  links and warning about unsupported code.
195
- email: code@dunae.ca
175
+ email: akzhan.abdulin@gmail.com
196
176
  executables:
197
177
  - premailer
198
178
  extensions: []
@@ -203,7 +183,6 @@ files:
203
183
  - bin/premailer
204
184
  - lib/premailer.rb
205
185
  - lib/premailer/adapter.rb
206
- - lib/premailer/adapter/hpricot.rb
207
186
  - lib/premailer/adapter/nokogiri.rb
208
187
  - lib/premailer/adapter/nokogiri_fast.rb
209
188
  - lib/premailer/adapter/nokogumbo.rb
@@ -213,7 +192,7 @@ files:
213
192
  - lib/premailer/premailer.rb
214
193
  - lib/premailer/version.rb
215
194
  - misc/client_support.yaml
216
- homepage: http://premailer.dialect.ca/
195
+ homepage: https://github.com/premailer/premailer
217
196
  licenses: []
218
197
  metadata:
219
198
  yard.run: yri
@@ -225,7 +204,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
225
204
  requirements:
226
205
  - - ">="
227
206
  - !ruby/object:Gem::Version
228
- version: 2.0.0
207
+ version: 2.1.0
229
208
  required_rubygems_version: !ruby/object:Gem::Requirement
230
209
  requirements:
231
210
  - - ">="
@@ -233,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
233
212
  version: '0'
234
213
  requirements: []
235
214
  rubyforge_project:
236
- rubygems_version: 2.6.8
215
+ rubygems_version: 2.5.1
237
216
  signing_key:
238
217
  specification_version: 4
239
218
  summary: Preflight for HTML e-mail.
@@ -1,220 +0,0 @@
1
- require 'hpricot'
2
-
3
- class Premailer
4
- module Adapter
5
- # Hpricot adapter
6
- module Hpricot
7
- include AdapterHelper::RgbToHex
8
-
9
- def self.included(base)
10
- warn <<eos
11
- [DEPRECATED] Premailer's Hpricot adapter will be removed with the next major \
12
- release. Change your :adapter option to :nokogiri or remove the `hpricot` gem \
13
- from your application to silence this warning. (Called from #{caller[2]})
14
- eos
15
- end
16
-
17
- # Merge CSS into the HTML document.
18
- # @return [String] HTML.
19
- def to_inline_css
20
- doc = @processed_doc
21
- @unmergable_rules = CssParser::Parser.new
22
-
23
- # Give all styles already in style attributes a specificity of 1000
24
- # per http://www.w3.org/TR/CSS21/cascade.html#specificity
25
- doc.search("*[@style]").each do |el|
26
- el['style'] = '[SPEC=1000[' + el.attributes['style'] + ']]'
27
- end
28
-
29
- # Iterate through the rules and merge them into the HTML
30
- @css_parser.each_selector(:all) do |selector, declaration, specificity, media_types|
31
- # Save un-mergable rules separately
32
- selector.gsub!(/:link([\s]*)+/i) {|m| $1 }
33
-
34
- # Convert element names to lower case
35
- selector.gsub!(/([\s]|^)([\w]+)/) {|m| $1.to_s + $2.to_s.downcase }
36
-
37
- if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
38
- @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
39
- else
40
- begin
41
- if selector =~ Premailer::RE_RESET_SELECTORS
42
- # this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
43
- # however, this doesn't mean for testing pur
44
- @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
45
- end
46
-
47
- # Change single ID CSS selectors into xpath so that we can match more
48
- # than one element. Added to work around dodgy generated code.
49
- selector.gsub!(/\A\#([\w_\-]+)\Z/, '*[@id=\1]')
50
-
51
- # convert attribute selectors to hpricot's format
52
- selector.gsub!(/\[([\w]+)\]/, '[@\1]')
53
- selector.gsub!(/\[([\w]+)([\=\~\^\$\*]+)([\w\s]+)\]/, '[@\1\2\'\3\']')
54
-
55
- doc.search(selector).each do |el|
56
- if el.elem? and (el.name != 'head' and el.parent.name != 'head')
57
- # Add a style attribute or append to the existing one
58
- block = "[SPEC=#{specificity}[#{declaration}]]"
59
- el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block
60
- end
61
- end
62
- rescue ::Hpricot::Error, RuntimeError, ArgumentError
63
- $stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
64
- next
65
- end
66
- end
67
- end
68
-
69
- # Remove script tags
70
- if @options[:remove_scripts]
71
- doc.search("script").remove
72
- end
73
-
74
- # Read STYLE attributes and perform folding
75
- doc.search("*[@style]").each do |el|
76
- style = el.attributes['style'].to_s
77
-
78
- declarations = []
79
-
80
- style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration|
81
- rs = CssParser::RuleSet.new(nil, declaration[1].to_s, declaration[0].to_i)
82
- declarations << rs
83
- end
84
- # Perform style folding
85
- merged = CssParser.merge(declarations)
86
- merged.expand_shorthand!
87
- merged.create_shorthand! if @options[:create_shorthands]
88
-
89
- # Duplicate CSS attributes as HTML attributes
90
- if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) && @options[:css_to_attributes]
91
- Premailer::RELATED_ATTRIBUTES[el.name].each do |css_att, html_att|
92
- if el[html_att].nil? and not merged[css_att].empty?
93
- new_html_att = merged[css_att].gsub(/url\(['|"](.*)['|"]\)/, '\1').gsub(/;$|\s*!important/, '').strip
94
- el[html_att] = css_att.end_with?('color') && @options[:rgb_to_hex_attributes] ? ensure_hex(new_html_att) : new_html_att
95
- end
96
- merged.instance_variable_get("@declarations").tap do |declarations|
97
- unless @options[:preserve_style_attribute]
98
- declarations.delete(css_att)
99
- end
100
- end
101
- end
102
- end
103
-
104
- # write the inline STYLE attribute
105
- el['style'] = Premailer.escape_string(merged.declarations_to_s)
106
- end
107
-
108
- doc = write_unmergable_css_rules(doc, @unmergable_rules)
109
-
110
- if @options[:remove_classes] or @options[:remove_comments]
111
- doc.search('*').each do |el|
112
- if el.comment? and @options[:remove_comments]
113
- lst = el.parent.children
114
- el.parent = nil
115
- lst.delete(el)
116
- elsif el.elem?
117
- el.remove_attribute('class') if @options[:remove_classes]
118
- end
119
- end
120
- end
121
-
122
- if @options[:reset_contenteditable]
123
- doc.search('*[@contenteditable]').each do |el|
124
- el.remove_attribute('contenteditable')
125
- end
126
- end
127
-
128
- if @options[:remove_ids]
129
- # find all anchor's targets and hash them
130
- targets = []
131
- doc.search("a[@href^='#']").each do |el|
132
- target = el.get_attribute('href')[1..-1]
133
- targets << target
134
- el.set_attribute('href', "#" + Digest::MD5.hexdigest(target))
135
- end
136
- # hash ids that are links target, delete others
137
- doc.search("*[@id]").each do |el|
138
- id = el.get_attribute('id')
139
- if targets.include?(id)
140
- el.set_attribute('id', Digest::MD5.hexdigest(id))
141
- else
142
- el.remove_attribute('id')
143
- end
144
- end
145
- end
146
-
147
- @processed_doc = doc
148
-
149
- @processed_doc.to_original_html
150
- end
151
-
152
- # Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
153
- # and write it into the <tt>body</tt>.
154
- #
155
- # <tt>doc</tt> is an Hpricot document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
156
- #
157
- # @return [::Hpricot] a document.
158
- def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
159
- styles = unmergable_rules.to_s
160
-
161
- unless styles.empty?
162
- style_tag = "\n<style type=\"text/css\">\n#{styles}</style>\n"
163
- if head = doc.search('head')
164
- head.append(style_tag)
165
- elsif body = doc.search('body')
166
- body.append(style_tag)
167
- else
168
- doc.inner_html= doc.inner_html << style_tag
169
- end
170
- end
171
- doc
172
- end
173
-
174
-
175
- # Converts the HTML document to a format suitable for plain-text e-mail.
176
- #
177
- # If present, uses the <body> element as its base; otherwise uses the whole document.
178
- #
179
- # @return [String] Plain text.
180
- def to_plain_text
181
- html_src = ''
182
- begin
183
- html_src = @doc.search("body").inner_html
184
- rescue; end
185
-
186
- html_src = @doc.to_html unless html_src and not html_src.empty?
187
- convert_to_text(html_src, @options[:line_length], @html_encoding)
188
- end
189
-
190
-
191
- # Gets the original HTML as a string.
192
- # @return [String] HTML.
193
- def to_s
194
- @doc.to_original_html
195
- end
196
-
197
- # Load the HTML file and convert it into an Hpricot document.
198
- #
199
- # @return [::Hpricot] a document.
200
- def load_html(input) # :nodoc:
201
- thing = nil
202
-
203
- # TODO: duplicate options
204
- if @options[:with_html_string] or @options[:inline] or input.respond_to?(:read)
205
- thing = input
206
- elsif @is_local_file
207
- @base_dir = File.dirname(input)
208
- thing = File.open(input, 'r')
209
- else
210
- thing = open(input)
211
- end
212
-
213
- # TODO: deal with Hpricot seg faults on empty input
214
- thing ? Hpricot(thing) : nil
215
- end
216
-
217
- end
218
- end
219
- end
220
-