roadie 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +0 -1
- data/Changelog.md +24 -4
- data/Gemfile +0 -5
- data/README.md +28 -4
- data/lib/roadie/document.rb +13 -0
- data/lib/roadie/inliner.rb +67 -8
- data/lib/roadie/style_block.rb +26 -5
- data/lib/roadie/stylesheet.rb +3 -4
- data/lib/roadie/version.rb +1 -1
- data/spec/integration_spec.rb +146 -0
- data/spec/lib/roadie/style_block_spec.rb +20 -9
- metadata +2 -4
- data/Guardfile +0 -20
- data/autotest/discover.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2c4863b0337cfe2129ee5e1184bb3ffdd422ea9
|
4
|
+
data.tar.gz: ccd82152f99fe3131773f9070ef39c07952027d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8acd0f1029e3b40c94fe11e465b6604f6f16aca3d6a33375f14e3c2ea8ded36ca45edbf29e09fe3408c1ac21632875e92093fd8bce17f72658c3a9d9112b8087
|
7
|
+
data.tar.gz: e66923f904d221f10731bf92058390106ebcbf16be9a9053c149c41919252862285e53d86eec93fc4ececaef894b4ec9df019ad5c23678fa3eabed7ab3676d27
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
### dev
|
2
2
|
|
3
|
-
[full changelog](https://github.com/Mange/roadie/compare/v3.
|
3
|
+
[full changelog](https://github.com/Mange/roadie/compare/v3.4.0...master)
|
4
4
|
|
5
|
-
|
5
|
+
Nothing yet.
|
6
6
|
|
7
|
-
### 3.
|
7
|
+
### 3.3.0
|
8
|
+
|
9
|
+
[full changelog](https://github.com/Mange/roadie/compare/v3.3.0...v3.4.0)
|
10
|
+
|
11
|
+
* Enhancements
|
12
|
+
* Better support for media queries - [BroiSatse (Stanislaw
|
13
|
+
Klajn)](https://github.com/BroiSatse) and [jeznag (Jeremy
|
14
|
+
Nagel)](https://github.com/jeznag) (#157).
|
15
|
+
|
16
|
+
Media queries should no longer be inlined in your HTML; instead they should
|
17
|
+
appear in `<head>` if `keep_uninlinable_css` is enabled. By default different
|
18
|
+
media query blocks with the same conditions will be merged together (which
|
19
|
+
might change specificity), but this behavior can be disabled by setting
|
20
|
+
`merge_media_queries` to `false`.
|
21
|
+
|
22
|
+
* Remove Guard as a development dependency. Tests run fast anyway, and I
|
23
|
+
never liked that this tool "infected" the dependencies of the project when
|
24
|
+
it should remain a user-specific tool unless the project wants to enforce
|
25
|
+
it.
|
26
|
+
|
27
|
+
### 3.3.0
|
8
28
|
|
9
29
|
[full changelog](https://github.com/Mange/roadie/compare/v3.2.2...v3.3.0)
|
10
30
|
|
@@ -12,7 +32,7 @@
|
|
12
32
|
* Allow transforming to XHTML instead of HTML - [Zhivko Draganov](https://github.com/zdraganov) (#144).
|
13
33
|
* Support partial HTML documents (fragments) - #147
|
14
34
|
* With the help of [andfx](https://github.com/andfx) - #115
|
15
|
-
* With the help of [Frida Sjoholm](https://github.com/
|
35
|
+
* With the help of [Frida Sjoholm](https://github.com/FridaSjoholm) - #146
|
16
36
|
* Skip URL rewriting on elements with `data-roadie-ignore` - #154.
|
17
37
|
* With the help of [Hamed Asghari](https://github.com/hasghari) - #138.
|
18
38
|
* Bug fixes:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,9 +4,13 @@ Roadie
|
|
4
4
|
[![Build history and status](https://travis-ci.org/Mange/roadie.svg?branch=master)](http://travis-ci.org/#!/Mange/roadie)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/Mange/roadie.png)](https://codeclimate.com/github/Mange/roadie)
|
6
6
|
[![Code coverage status](https://codecov.io/github/Mange/roadie/coverage.svg?branch=master)](https://codecov.io/github/Mange/roadie?branch=master)
|
7
|
-
[![Gem
|
7
|
+
[![Gem](https://img.shields.io/gem/v/roadie.svg)](https://rubygems.org/gems/roadie)
|
8
|
+
[![Passive maintenance](https://img.shields.io/badge/maintenance-Passive-yellow.svg)][passive]
|
8
9
|
|
9
|
-
|
10
|
+
|
11
|
+
|||
|
12
|
+
|---|---|
|
13
|
+
| :warning: | This gem is now in [passive maintenance mode][passive]. [(more)][passive] |
|
10
14
|
|
11
15
|
> Making HTML emails comfortable for the Ruby rockstars
|
12
16
|
|
@@ -35,7 +39,7 @@ Features
|
|
35
39
|
* Respects `!important` styles.
|
36
40
|
* Does not overwrite styles already present in the `style` attribute of tags.
|
37
41
|
* Supports the same CSS selectors as [Nokogiri](http://nokogiri.org/); use CSS3 selectors in your emails!
|
38
|
-
* Keeps `:hover` and friends around in a separate `<style>` element.
|
42
|
+
* Keeps `:hover`, `@media { ... }` and friends around in a separate `<style>` element.
|
39
43
|
* Makes image urls absolute.
|
40
44
|
* Hostname and port configurable on a per-environment basis.
|
41
45
|
* Can be disabled on individual elements.
|
@@ -51,7 +55,7 @@ Install & Usage
|
|
51
55
|
[Add this gem to your Gemfile as recommended by Rubygems](http://rubygems.org/gems/roadie) and run `bundle install`.
|
52
56
|
|
53
57
|
```ruby
|
54
|
-
gem 'roadie', '~> 3.
|
58
|
+
gem 'roadie', '~> 3.4'
|
55
59
|
```
|
56
60
|
|
57
61
|
You can then create a new instance of a Roadie document:
|
@@ -74,6 +78,19 @@ Your document instance can be configured with several options:
|
|
74
78
|
|
75
79
|
* `url_options` - Dictates how absolute URLs should be built.
|
76
80
|
* `keep_uninlinable_css` - Set to false to skip CSS that cannot be inlined.
|
81
|
+
* `merge_media_queries` - Set to false to not group media queries. Some users might prefer to not group rules within media queries because
|
82
|
+
it will result in rules getting reordered.
|
83
|
+
e.g.
|
84
|
+
```css
|
85
|
+
@media(max-width: 600px) { .col-6 { display: block; } }
|
86
|
+
@media(max-width: 400px) { .col-12 { display: inline-block; } }
|
87
|
+
@media(max-width: 600px) { .col-12 { display: block; } }
|
88
|
+
```
|
89
|
+
will become
|
90
|
+
```css
|
91
|
+
@media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
|
92
|
+
@media(max-width: 400px) { .col-12 { display: inline-block; } }
|
93
|
+
```
|
77
94
|
* `asset_providers` - A list of asset providers that are invoked when CSS files are referenced. See below.
|
78
95
|
* `external_asset_providers` - A list of asset providers that are invoked when absolute CSS URLs are referenced. See below.
|
79
96
|
* `before_transformation` - A callback run before transformation starts.
|
@@ -464,6 +481,12 @@ Instructions on how to do this on most platforms, see [Nokogiri's official insta
|
|
464
481
|
|
465
482
|
The CSS Parser used in Roadie does not handle keyframes. I don't think any email clients do either, but if you want to keep on trying you can add them manually to a `<style>` element (or a separate referenced stylesheet) and [tell Roadie not to touch them](#referenced-stylesheets).
|
466
483
|
|
484
|
+
### My `@media` queries are reordered, how can I fix this?
|
485
|
+
|
486
|
+
Different `@media` query blocks with the same conditions are merged by default,
|
487
|
+
which will change the order in some cases. You can disable this by setting
|
488
|
+
`merge_media_queries` to `false`. (See *Install & Usage* section above).
|
489
|
+
|
467
490
|
### How do I get rid of the `<body>` elements that are added?
|
468
491
|
|
469
492
|
It sounds like you want to transform a partial document. Maybe you are building
|
@@ -553,3 +576,4 @@ The above copyright notice and this permission notice shall be included in all c
|
|
553
576
|
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
554
577
|
|
555
578
|
[gpg]: https://gist.github.com/Mange/baf25e23e653a206ec2d#file-keybase-md
|
579
|
+
[passive]: https://github.com/Mange/roadie/issues/155
|
data/lib/roadie/document.rb
CHANGED
@@ -29,12 +29,24 @@ module Roadie
|
|
29
29
|
# Should CSS that cannot be inlined be kept in a new `<style>` element in `<head>`?
|
30
30
|
attr_accessor :keep_uninlinable_css
|
31
31
|
|
32
|
+
# Merge media queries to increase performance and reduce email size if enabled.
|
33
|
+
# This will change specificity in some cases, like for example:
|
34
|
+
# @media(max-width: 600px) { .col-6 { display: block; } }
|
35
|
+
# @media(max-width: 400px) { .col-12 { display: inline-block; } }
|
36
|
+
# @media(max-width: 600px) { .col-12 { display: block; } }
|
37
|
+
# will become
|
38
|
+
# @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
|
39
|
+
# @media(max-width: 400px) { .col-12 { display: inline-block; } }
|
40
|
+
# which would change the styling on the page
|
41
|
+
attr_accessor :merge_media_queries
|
42
|
+
|
32
43
|
# The mode to generate markup in. Valid values are `:html` (default) and `:xhtml`.
|
33
44
|
attr_reader :mode
|
34
45
|
|
35
46
|
# @param [String] html the input HTML
|
36
47
|
def initialize(html)
|
37
48
|
@keep_uninlinable_css = true
|
49
|
+
@merge_media_queries = true
|
38
50
|
@html = html
|
39
51
|
@asset_providers = ProviderList.wrap(FilesystemProvider.new)
|
40
52
|
@external_asset_providers = ProviderList.empty
|
@@ -154,6 +166,7 @@ module Roadie
|
|
154
166
|
Inliner.new(dom_stylesheets + [stylesheet], dom).inline(
|
155
167
|
keep_uninlinable_css: keep_uninlinable_css,
|
156
168
|
keep_uninlinable_in: keep_uninlinable_in,
|
169
|
+
merge_media_queries: merge_media_queries,
|
157
170
|
)
|
158
171
|
end
|
159
172
|
|
data/lib/roadie/inliner.rb
CHANGED
@@ -26,17 +26,19 @@ module Roadie
|
|
26
26
|
#
|
27
27
|
# @option options [true, false] :keep_uninlinable_css
|
28
28
|
# @option options [:root, :head] :keep_uninlinable_in
|
29
|
+
# @option options [true, false] :merge_media_queries
|
29
30
|
# @return [nil]
|
30
31
|
def inline(options = {})
|
31
32
|
keep_uninlinable_css = options.fetch(:keep_uninlinable_css, true)
|
32
33
|
keep_uninlinable_in = options.fetch(:keep_uninlinable_in, :head)
|
34
|
+
merge_media_queries = options.fetch(:merge_media_queries, true)
|
33
35
|
|
34
36
|
style_map, extra_blocks = consume_stylesheets
|
35
37
|
|
36
38
|
apply_style_map(style_map)
|
37
39
|
|
38
40
|
if keep_uninlinable_css
|
39
|
-
add_uninlinable_styles(keep_uninlinable_in, extra_blocks)
|
41
|
+
add_uninlinable_styles(keep_uninlinable_in, extra_blocks, merge_media_queries)
|
40
42
|
end
|
41
43
|
|
42
44
|
nil
|
@@ -96,7 +98,12 @@ module Roadie
|
|
96
98
|
nil
|
97
99
|
end
|
98
100
|
|
99
|
-
|
101
|
+
# Adds unlineable styles in the specified part of the document
|
102
|
+
# either the head or in the document
|
103
|
+
# @param [Symbol] parent Where to put the styles
|
104
|
+
# @param [Array<StyleBlock>] blocks Non-inlineable style blocks
|
105
|
+
# @param [Boolean] merge_media_queries Whether to group media queries
|
106
|
+
def add_uninlinable_styles(parent, blocks, merge_media_queries)
|
100
107
|
return if blocks.empty?
|
101
108
|
|
102
109
|
parent_node =
|
@@ -109,28 +116,80 @@ module Roadie
|
|
109
116
|
raise ArgumentError, "Parent must be either :head or :root. Was #{parent.inspect}"
|
110
117
|
end
|
111
118
|
|
112
|
-
create_style_element(blocks, parent_node)
|
119
|
+
create_style_element(blocks, parent_node, merge_media_queries)
|
113
120
|
end
|
114
121
|
|
115
122
|
def find_head
|
116
123
|
dom.at_xpath('html/head')
|
117
124
|
end
|
118
125
|
|
119
|
-
def create_style_element(style_blocks, parent)
|
126
|
+
def create_style_element(style_blocks, parent, merge_media_queries)
|
120
127
|
return unless parent
|
121
|
-
element = Nokogiri::XML::Node.new(
|
122
|
-
|
128
|
+
element = Nokogiri::XML::Node.new('style', parent.document)
|
129
|
+
|
130
|
+
element.content =
|
131
|
+
if merge_media_queries
|
132
|
+
styles_in_shared_media_queries(style_blocks).join("\n")
|
133
|
+
else
|
134
|
+
styles_in_individual_media_queries(style_blocks).join("\n")
|
135
|
+
end
|
123
136
|
parent.add_child(element)
|
124
137
|
end
|
125
138
|
|
139
|
+
# For performance reasons, we should group styles with the same media types within
|
140
|
+
# one media query instead of creating thousands of media queries.
|
141
|
+
# https://github.com/artifex404/media-queries-benchmark
|
142
|
+
# Example result: ["@media(max-width: 600px) { .col-12 { display: block; } }"]
|
143
|
+
# @param {Array<StyleBlock>} style_blocks Style blocks that could not be inlined
|
144
|
+
# @return {Array<String>}
|
145
|
+
def styles_in_shared_media_queries(style_blocks)
|
146
|
+
style_blocks.group_by(&:media).map do |media_types, blocks|
|
147
|
+
css_rules = blocks.map(&:to_s).join("\n")
|
148
|
+
|
149
|
+
if media_types == ['all']
|
150
|
+
css_rules
|
151
|
+
else
|
152
|
+
"@media #{media_types.join(', ')} {\n#{css_rules}\n}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Some users might prefer to not group rules within media queries because
|
158
|
+
# it will result in rules getting reordered.
|
159
|
+
# e.g.
|
160
|
+
# @media(max-width: 600px) { .col-6 { display: block; } }
|
161
|
+
# @media(max-width: 400px) { .col-12 { display: inline-block; } }
|
162
|
+
# @media(max-width: 600px) { .col-12 { display: block; } }
|
163
|
+
# will become
|
164
|
+
# @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
|
165
|
+
# @media(max-width: 400px) { .col-12 { display: inline-block; } }
|
166
|
+
# which would change the styling on the page
|
167
|
+
# (before it would've yielded display: block; for .col-12 at max-width: 600px
|
168
|
+
# and now it yields inline-block;)
|
169
|
+
#
|
170
|
+
# If merge_media_queries is set to false,
|
171
|
+
# we will generate #{style_blocks.size} media queries, potentially
|
172
|
+
# causing performance issues.
|
173
|
+
# @param {Array<StyleBlock>} style_blocks All style blocks
|
174
|
+
# @return {Array<String>}
|
175
|
+
def styles_in_individual_media_queries(style_blocks)
|
176
|
+
style_blocks.map do |css_rule|
|
177
|
+
if css_rule.media == ['all']
|
178
|
+
css_rule
|
179
|
+
else
|
180
|
+
"@media #{css_rule.media.join(', ')} {\n#{css_rule}\n}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
126
185
|
# @api private
|
127
186
|
# StyleMap is a map between a DOM element and {StyleAttributeBuilder}. Basically,
|
128
187
|
# it's an accumulator for properties, scoped on specific elements.
|
129
188
|
class StyleMap
|
130
189
|
def initialize
|
131
|
-
@map = Hash.new
|
190
|
+
@map = Hash.new do |hash, key|
|
132
191
|
hash[key] = StyleAttributeBuilder.new
|
133
|
-
|
192
|
+
end
|
134
193
|
end
|
135
194
|
|
136
195
|
def add(elements, new_properties)
|
data/lib/roadie/style_block.rb
CHANGED
@@ -5,28 +5,49 @@ module Roadie
|
|
5
5
|
# A style block is the combination of a {Selector} and a list of {StyleProperty}.
|
6
6
|
class StyleBlock
|
7
7
|
extend Forwardable
|
8
|
-
attr_reader :selector, :properties
|
8
|
+
attr_reader :selector, :properties, :media
|
9
9
|
|
10
10
|
# @param [Selector] selector
|
11
11
|
# @param [Array<StyleProperty>] properties
|
12
|
-
|
12
|
+
# @param [Array<String>] media Array of media types, e.g.
|
13
|
+
# @media screen, print and (max-width 800px) will become
|
14
|
+
# ['screen', 'print and (max-width 800px)']
|
15
|
+
def initialize(selector, properties, media)
|
13
16
|
@selector = selector
|
14
17
|
@properties = properties
|
18
|
+
@media = media.map(&:to_s)
|
15
19
|
end
|
16
20
|
|
17
21
|
# @!method specificity
|
18
22
|
# @see Selector#specificity
|
19
|
-
|
20
|
-
# @see Selector#inlinable?
|
21
|
-
def_delegators :selector, :specificity, :inlinable?
|
23
|
+
def_delegators :selector, :specificity
|
22
24
|
# @!method selector_string
|
23
25
|
# @see Selector#to_s
|
24
26
|
def_delegator :selector, :to_s, :selector_string
|
25
27
|
|
28
|
+
# Checks whether the media query can be inlined
|
29
|
+
# @see inlineable_media
|
30
|
+
# @return {Boolean}
|
31
|
+
def inlinable?
|
32
|
+
inlinable_media? && selector.inlinable?
|
33
|
+
end
|
34
|
+
|
26
35
|
# String representation of the style block. This is valid CSS and can be
|
27
36
|
# used in the DOM.
|
37
|
+
# @return {String}
|
28
38
|
def to_s
|
39
|
+
# NB - leave off redundant final semicolon - see https://www.w3.org/TR/CSS2/syndata.html#declaration
|
29
40
|
"#{selector}{#{properties.map(&:to_s).join(';')}}"
|
30
41
|
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# A media query cannot be inlined if it contains any advanced rules
|
46
|
+
# e.g. @media only screen {...} is ok to inline but
|
47
|
+
# @media only screen and (max-width: 600px) {...} cannot be inlined
|
48
|
+
# @return {Boolean}
|
49
|
+
def inlinable_media?
|
50
|
+
@media.none? { |media_query| media_query.include? '(' }
|
51
|
+
end
|
31
52
|
end
|
32
53
|
end
|
data/lib/roadie/stylesheet.rb
CHANGED
@@ -43,17 +43,16 @@ module Roadie
|
|
43
43
|
def parse_blocks(css)
|
44
44
|
blocks = []
|
45
45
|
parser = setup_parser(css)
|
46
|
-
|
47
46
|
parser.each_rule_set do |rule_set, media_types|
|
48
47
|
rule_set.selectors.each do |selector_string|
|
49
|
-
blocks << create_style_block(selector_string, rule_set)
|
48
|
+
blocks << create_style_block(selector_string, rule_set, media_types)
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
53
52
|
blocks
|
54
53
|
end
|
55
54
|
|
56
|
-
def create_style_block(selector_string, rule_set)
|
55
|
+
def create_style_block(selector_string, rule_set, media_types)
|
57
56
|
specificity = CssParser.calculate_specificity(selector_string)
|
58
57
|
selector = Selector.new(selector_string, specificity)
|
59
58
|
properties = []
|
@@ -62,7 +61,7 @@ module Roadie
|
|
62
61
|
properties << StyleProperty.new(prop, val, important, specificity)
|
63
62
|
end
|
64
63
|
|
65
|
-
StyleBlock.new(selector, properties)
|
64
|
+
StyleBlock.new(selector, properties, media_types)
|
66
65
|
end
|
67
66
|
|
68
67
|
def setup_parser(css)
|
data/lib/roadie/version.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -299,6 +299,152 @@ describe "Roadie functionality" do
|
|
299
299
|
expect(result).to include("<td>One</td><td>1</td>")
|
300
300
|
expect(result).to include("<td>Two</td><td>2</td>")
|
301
301
|
end
|
302
|
+
|
303
|
+
it "doesn't inline styles in media queries with features" do
|
304
|
+
document = Roadie::Document.new <<-HTML
|
305
|
+
<html>
|
306
|
+
<head>
|
307
|
+
<link rel="stylesheet" href="/style.css">
|
308
|
+
</head>
|
309
|
+
<body>
|
310
|
+
<div class="colorful"></div>
|
311
|
+
</body>
|
312
|
+
</html>
|
313
|
+
HTML
|
314
|
+
|
315
|
+
document.asset_providers = TestProvider.new(
|
316
|
+
"/style.css" => <<-CSS
|
317
|
+
.colorful { color: green; }
|
318
|
+
@media screen and (max-width 600px) {
|
319
|
+
.colorful { color: red; }
|
320
|
+
}
|
321
|
+
CSS
|
322
|
+
)
|
323
|
+
|
324
|
+
result = parse_html document.transform
|
325
|
+
expect(result).to have_styling('color' => 'green').at_selector('.colorful')
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'puts non-inlineable media queries in the head' do
|
329
|
+
document = Roadie::Document.new <<-HTML
|
330
|
+
<html>
|
331
|
+
<head>
|
332
|
+
<link rel="stylesheet" href="/style.css">
|
333
|
+
</head>
|
334
|
+
<body>
|
335
|
+
<div class="colorful"></div>
|
336
|
+
</body>
|
337
|
+
</html>
|
338
|
+
HTML
|
339
|
+
|
340
|
+
document.asset_providers = TestProvider.new(
|
341
|
+
"/style.css" => <<-CSS
|
342
|
+
.colorful { color: green; }
|
343
|
+
@media screen and (max-width 800px) {
|
344
|
+
.colorful { color: blue; }
|
345
|
+
}
|
346
|
+
@media screen, print and (max-width 800px) {
|
347
|
+
.colorful { color: blue; }
|
348
|
+
}
|
349
|
+
CSS
|
350
|
+
)
|
351
|
+
|
352
|
+
result = parse_html document.transform
|
353
|
+
|
354
|
+
styles = result.at_css('html > head > style').text
|
355
|
+
expected_result = <<-CSS
|
356
|
+
@media screen and (max-width 800px) { .colorful{color:blue} }
|
357
|
+
@media screen, print and (max-width 800px) { .colorful{color:blue} }
|
358
|
+
CSS
|
359
|
+
expected_result = expected_result.gsub(/[\s]+/, ' ').strip
|
360
|
+
actual_result = styles.gsub(/[\s]+/, ' ').strip
|
361
|
+
|
362
|
+
expect(actual_result).to eq(expected_result)
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'groups non-inlineable media queries in the head by default' do
|
366
|
+
document = Roadie::Document.new <<-HTML
|
367
|
+
<html>
|
368
|
+
<head>
|
369
|
+
<link rel="stylesheet" href="/style.css">
|
370
|
+
</head>
|
371
|
+
<body>
|
372
|
+
<div class="colorful"></div>
|
373
|
+
</body>
|
374
|
+
</html>
|
375
|
+
HTML
|
376
|
+
|
377
|
+
document.asset_providers = TestProvider.new(
|
378
|
+
"/style.css" => <<-CSS
|
379
|
+
.colorful { color: green; }
|
380
|
+
@media screen and (max-width 600px) {
|
381
|
+
.colorful { color: red; width: 600px; }
|
382
|
+
}
|
383
|
+
@media screen and (max-width 600px) {
|
384
|
+
.colorful-2 { color: red; width: 600px; }
|
385
|
+
}
|
386
|
+
CSS
|
387
|
+
)
|
388
|
+
|
389
|
+
result = parse_html document.transform
|
390
|
+
|
391
|
+
styles = result.at_css('html > head > style').text
|
392
|
+
expected_result = <<-CSS
|
393
|
+
@media screen and (max-width 600px) {
|
394
|
+
.colorful{color:red;width:600px}
|
395
|
+
.colorful-2{color:red;width:600px}
|
396
|
+
}
|
397
|
+
CSS
|
398
|
+
expected_result = expected_result.gsub(/[\s]+/, ' ').strip
|
399
|
+
actual_result = styles.gsub(/[\s]+/, ' ').strip
|
400
|
+
|
401
|
+
expect(actual_result).to eq(expected_result)
|
402
|
+
end
|
403
|
+
|
404
|
+
describe 'if merge_media_queries is set to false' do
|
405
|
+
it "doesn't group non-inlineable media queries in the head" do
|
406
|
+
document = Roadie::Document.new <<-HTML
|
407
|
+
<html>
|
408
|
+
<head>
|
409
|
+
<link rel="stylesheet" href="/style.css">
|
410
|
+
</head>
|
411
|
+
<body>
|
412
|
+
<div class="colorful"></div>
|
413
|
+
</body>
|
414
|
+
</html>
|
415
|
+
HTML
|
416
|
+
|
417
|
+
document.merge_media_queries = false
|
418
|
+
|
419
|
+
document.asset_providers = TestProvider.new(
|
420
|
+
"/style.css" => <<-CSS
|
421
|
+
.colorful { color: green; }
|
422
|
+
@media screen and (max-width 600px) {
|
423
|
+
.colorful { color: red; width: 600px; }
|
424
|
+
}
|
425
|
+
@media screen and (max-width 600px) {
|
426
|
+
.colorful-2 { color: red; width: 600px; }
|
427
|
+
}
|
428
|
+
CSS
|
429
|
+
)
|
430
|
+
|
431
|
+
result = parse_html document.transform
|
432
|
+
|
433
|
+
styles = result.at_css('html > head > style').text
|
434
|
+
expected_result = <<-CSS
|
435
|
+
@media screen and (max-width 600px) {
|
436
|
+
.colorful{color:red;width:600px}
|
437
|
+
}
|
438
|
+
@media screen and (max-width 600px) {
|
439
|
+
.colorful-2{color:red;width:600px}
|
440
|
+
}
|
441
|
+
CSS
|
442
|
+
expected_result = expected_result.gsub(/[\s]+/, ' ').strip
|
443
|
+
actual_result = styles.gsub(/[\s]+/, ' ').strip
|
444
|
+
|
445
|
+
expect(actual_result).to eq(expected_result)
|
446
|
+
end
|
447
|
+
end
|
302
448
|
end
|
303
449
|
|
304
450
|
describe "on partial documents" do
|
@@ -7,29 +7,40 @@ module Roadie
|
|
7
7
|
properties = []
|
8
8
|
selector = double "Selector"
|
9
9
|
|
10
|
-
block = StyleBlock.new(selector, properties)
|
10
|
+
block = StyleBlock.new(selector, properties, [:all])
|
11
11
|
expect(block.selector).to eq(selector)
|
12
12
|
expect(block.properties).to eq(properties)
|
13
13
|
end
|
14
14
|
|
15
15
|
it "delegates #specificity to the selector" do
|
16
16
|
selector = double "Selector", specificity: 45
|
17
|
-
expect(StyleBlock.new(selector, []).specificity).to eq(45)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "delegates #inlinable? to the selector" do
|
21
|
-
selector = double "Selector", inlinable?: "maybe"
|
22
|
-
expect(StyleBlock.new(selector, []).inlinable?).to eq("maybe")
|
17
|
+
expect(StyleBlock.new(selector, [], [:all]).specificity).to eq(45)
|
23
18
|
end
|
24
19
|
|
25
20
|
it "delegates #selector_string to selector#to_s" do
|
26
21
|
selector = double "Selector", to_s: "yey"
|
27
|
-
expect(StyleBlock.new(selector, []).selector_string).to eq("yey")
|
22
|
+
expect(StyleBlock.new(selector, [], [:all]).selector_string).to eq("yey")
|
28
23
|
end
|
29
24
|
|
30
25
|
it "has a string representation" do
|
31
26
|
properties = [double(to_s: "bar"), double(to_s: "baz")]
|
32
|
-
expect(StyleBlock.new(double(to_s: "foo"), properties).to_s).to eq("foo{bar;baz}")
|
27
|
+
expect(StyleBlock.new(double(to_s: "foo"), properties, [:all]).to_s).to eq("foo{bar;baz}")
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#inlinable" do
|
31
|
+
context "when no media include feature condition" do
|
32
|
+
it "delegates #inlinable? to the selector" do
|
33
|
+
selector = double "Selector", inlinable?: "maybe"
|
34
|
+
expect(StyleBlock.new(selector, [], [:all]).inlinable?).to eq("maybe")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when one of media queries includes feature condition" do
|
39
|
+
it "returns false" do
|
40
|
+
selector = double "Selector", inlinable?: "maybe"
|
41
|
+
expect(StyleBlock.new(selector, [], [:all, :'screen (min-width: 300px)']).inlinable?).to be(false)
|
42
|
+
end
|
43
|
+
end
|
33
44
|
end
|
34
45
|
end
|
35
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roadie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Magnus Bergmark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -96,11 +96,9 @@ files:
|
|
96
96
|
- ".yardopts"
|
97
97
|
- Changelog.md
|
98
98
|
- Gemfile
|
99
|
-
- Guardfile
|
100
99
|
- LICENSE
|
101
100
|
- README.md
|
102
101
|
- Rakefile
|
103
|
-
- autotest/discover.rb
|
104
102
|
- lib/roadie.rb
|
105
103
|
- lib/roadie/asset_provider.rb
|
106
104
|
- lib/roadie/asset_scanner.rb
|
data/Guardfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
rspec_options = {
|
2
|
-
cmd: 'rspec -f documentation',
|
3
|
-
failed_mode: :keep,
|
4
|
-
all_after_pass: true,
|
5
|
-
all_on_start: true,
|
6
|
-
run_all: {cmd: 'rspec -f progress'}
|
7
|
-
}
|
8
|
-
|
9
|
-
guard 'rspec', rspec_options do
|
10
|
-
watch(%r{^spec/.+_spec\.rb$})
|
11
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
12
|
-
watch('lib/roadie.rb') { "spec" }
|
13
|
-
watch('lib/roadie/errors.rb') { "spec" }
|
14
|
-
|
15
|
-
watch(%r{lib/roadie/rspec/.*\.rb}) { "spec" }
|
16
|
-
|
17
|
-
watch(%r{spec/support/.*\.rb}) { "spec" }
|
18
|
-
watch('spec/spec_helper.rb') { "spec" }
|
19
|
-
end
|
20
|
-
|
data/autotest/discover.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Autotest.add_discovery { 'rspec2' }
|