docomo_css 0.3.0 → 0.4.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.
- data/README.rdoc +10 -0
- data/lib/docomo_css/filter.rb +118 -0
- data/lib/docomo_css/railtie.rb +7 -1
- data/lib/docomo_css/version.rb +1 -1
- data/lib/docomo_css.rb +0 -116
- metadata +21 -4
data/README.rdoc
CHANGED
@@ -13,6 +13,16 @@ Instead, every element must use its own style attribute, for example
|
|
13
13
|
|
14
14
|
docomo_css works around this by inlining all CSS automatically for you.
|
15
15
|
|
16
|
+
Also, docomo does not support styling some elements such as h1, but does if you nest the contents in a span. This library automatically handles transforming
|
17
|
+
|
18
|
+
<h1>foo</h1>
|
19
|
+
|
20
|
+
to
|
21
|
+
|
22
|
+
<h1><span>foo</span></h1>
|
23
|
+
|
24
|
+
so you don't need to change any styling.
|
25
|
+
|
16
26
|
== Install
|
17
27
|
|
18
28
|
sudo gem install docomo_css
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'docomo_css/stylesheet'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'tiny_css'
|
4
|
+
|
5
|
+
module DocomoCss
|
6
|
+
class Filter
|
7
|
+
def after(controller)
|
8
|
+
return unless controller.response.content_type =~ /application\/xhtml\+xml/
|
9
|
+
return unless controller.request.user_agent =~ /docomo/i
|
10
|
+
return if docomo_2_0_browser?(controller)
|
11
|
+
body = escape_numeric_character_reference controller.response.body
|
12
|
+
body = embed_css remove_xml_declare(body)
|
13
|
+
controller.response.body = unescape_numeric_character_reference body
|
14
|
+
end
|
15
|
+
|
16
|
+
def embed_css(body)
|
17
|
+
doc = Nokogiri::HTML(body)
|
18
|
+
|
19
|
+
stylesheet_link_node(doc).each do |linknode|
|
20
|
+
stylesheet = DocomoCss::Stylesheet.new(linknode['href'])
|
21
|
+
next unless stylesheet.valid?
|
22
|
+
css = TinyCss.new.read(stylesheet.path)
|
23
|
+
embed_pseudo_style(doc, extract_pseudo_style(css))
|
24
|
+
embed_style(doc, css)
|
25
|
+
end
|
26
|
+
xml_declare(doc) + doc.to_xhtml(:indent => 0, :encoding => doc.encoding)
|
27
|
+
end
|
28
|
+
|
29
|
+
def xml_declare(doc)
|
30
|
+
<<-XML
|
31
|
+
<?xml version="1.0" encoding="#{doc.encoding}"?>
|
32
|
+
XML
|
33
|
+
end
|
34
|
+
|
35
|
+
def remove_xml_declare(body)
|
36
|
+
body.gsub(%r'<\?xml[^\?]*?\?>', '')
|
37
|
+
end
|
38
|
+
|
39
|
+
def embed_style(doc, css)
|
40
|
+
css.style.each do |selector, style|
|
41
|
+
stringified_style = stringify_style(style)
|
42
|
+
doc.css(selector).each do |element|
|
43
|
+
# inject support for unsupported styles
|
44
|
+
if /h\d/ =~ element.name
|
45
|
+
# font-size needs to be changed in span
|
46
|
+
element.children.wrap('<span>')
|
47
|
+
element.children.first['style'] = merge_style element['style'], stringified_style
|
48
|
+
|
49
|
+
# background-color should be changed in div to give 100% width
|
50
|
+
div = Nokogiri.make("<div>")
|
51
|
+
div['style'] = merge_style element['style'], stringified_style
|
52
|
+
element.replace(div)
|
53
|
+
div.add_child(element)
|
54
|
+
else
|
55
|
+
element['style'] = merge_style element['style'], stringified_style
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def stringify_style(style)
|
62
|
+
style.map { |k, v| "#{ k }:#{ v }" }.join ';'
|
63
|
+
end
|
64
|
+
|
65
|
+
def merge_style(style, other_style)
|
66
|
+
return other_style if style == nil
|
67
|
+
style += ";" unless style =~ /;\Z/
|
68
|
+
style + other_style
|
69
|
+
end
|
70
|
+
|
71
|
+
def escape_numeric_character_reference(text)
|
72
|
+
text.gsub /&#(\d+|x[\da-fA-F]+);/, 'HTMLCSSINLINERESCAPE\1::::::::'
|
73
|
+
end
|
74
|
+
|
75
|
+
def unescape_numeric_character_reference(text)
|
76
|
+
text.gsub /HTMLCSSINLINERESCAPE(\d+|x[\da-fA-F]+)::::::::/, '&#\1;'
|
77
|
+
end
|
78
|
+
|
79
|
+
def stylesheet_link_node(document)
|
80
|
+
document.xpath '//link[@rel="stylesheet"]'
|
81
|
+
end
|
82
|
+
|
83
|
+
def css_path(stylesheet)
|
84
|
+
stylesheet.path
|
85
|
+
end
|
86
|
+
|
87
|
+
def extract_pseudo_style(css)
|
88
|
+
pseudo_style = TinyCss.new
|
89
|
+
pseudo_selectors(css).each do |v|
|
90
|
+
pseudo_style.style[v] = css.style[v]
|
91
|
+
css.style.delete(v)
|
92
|
+
end
|
93
|
+
pseudo_style
|
94
|
+
end
|
95
|
+
|
96
|
+
def embed_pseudo_style(doc, pseudo_style)
|
97
|
+
return if pseudo_style.style.keys.empty?
|
98
|
+
|
99
|
+
raise unless doc.at('/html/head')
|
100
|
+
doc.at('/html/head').add_child <<-STYLE
|
101
|
+
<style type="text/css">
|
102
|
+
#{pseudo_style.write_string}
|
103
|
+
</style>
|
104
|
+
STYLE
|
105
|
+
doc
|
106
|
+
end
|
107
|
+
|
108
|
+
def pseudo_selectors(css)
|
109
|
+
css.style.keys.grep(/a:(link|focus|visited)/)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def docomo_2_0_browser?(controller)
|
115
|
+
controller.request.user_agent =~ /DoCoMo\/2\.0 [^(]*\(c(\d+);/ && $1.to_i >= 500
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/docomo_css/railtie.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
require 'docomo_css/filter'
|
2
|
+
|
1
3
|
class DocomoCss::Railtie < Rails::Railtie
|
2
4
|
initializer "docomo_css.extend.action_controller" do
|
3
|
-
ActionController::Base.
|
5
|
+
ActionController::Base.class_eval do
|
6
|
+
def self.docomo_filter
|
7
|
+
after_filter DocomoCss::Filter.new
|
8
|
+
end
|
9
|
+
end
|
4
10
|
end
|
5
11
|
end
|
data/lib/docomo_css/version.rb
CHANGED
data/lib/docomo_css.rb
CHANGED
@@ -1,117 +1 @@
|
|
1
|
-
require 'nokogiri'
|
2
|
-
require 'tiny_css'
|
3
|
-
require 'docomo_css/stylesheet'
|
4
1
|
require 'docomo_css/railtie'
|
5
|
-
|
6
|
-
module DocomoCss
|
7
|
-
|
8
|
-
def self.included(base)
|
9
|
-
base.extend ClassMethods
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def docomo_filter
|
14
|
-
after_filter DocomoCssFilter.new
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class DocomoCssFilter
|
19
|
-
def after(controller)
|
20
|
-
return unless controller.response.content_type =~ /application\/xhtml\+xml/
|
21
|
-
return unless controller.request.user_agent =~ /docomo/i
|
22
|
-
return if docomo_2_0_browser?(controller)
|
23
|
-
body = escape_numeric_character_reference controller.response.body
|
24
|
-
body = embed_css remove_xml_declare(body)
|
25
|
-
controller.response.body = unescape_numeric_character_reference body
|
26
|
-
end
|
27
|
-
|
28
|
-
def embed_css(body)
|
29
|
-
doc = Nokogiri::HTML(body)
|
30
|
-
|
31
|
-
stylesheet_link_node(doc).each do |linknode|
|
32
|
-
stylesheet = DocomoCss::Stylesheet.new(linknode['href'])
|
33
|
-
next unless stylesheet.valid?
|
34
|
-
css = TinyCss.new.read(stylesheet.path)
|
35
|
-
embed_pseudo_style(doc, extract_pseudo_style(css))
|
36
|
-
embed_style(doc, css)
|
37
|
-
end
|
38
|
-
xml_declare(doc) + doc.to_xhtml(:indent => 0, :encoding => doc.encoding)
|
39
|
-
end
|
40
|
-
|
41
|
-
def xml_declare(doc)
|
42
|
-
<<-XML
|
43
|
-
<?xml version="1.0" encoding="#{doc.encoding}"?>
|
44
|
-
XML
|
45
|
-
end
|
46
|
-
|
47
|
-
def remove_xml_declare(body)
|
48
|
-
body.gsub(%r'<\?xml[^\?]*?\?>', '')
|
49
|
-
end
|
50
|
-
|
51
|
-
def embed_style(doc, css)
|
52
|
-
css.style.each do |selector, style|
|
53
|
-
stringified_style = stringify_style(style)
|
54
|
-
doc.css(selector).each do |element|
|
55
|
-
element['style'] = merge_style element['style'], stringified_style
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def stringify_style(style)
|
61
|
-
style.map { |k, v| "#{ k }:#{ v }" }.join ';'
|
62
|
-
end
|
63
|
-
|
64
|
-
def merge_style(style, other_style)
|
65
|
-
return other_style if style == nil
|
66
|
-
style += ";" unless style =~ /;\Z/
|
67
|
-
style + other_style
|
68
|
-
end
|
69
|
-
|
70
|
-
def escape_numeric_character_reference(text)
|
71
|
-
text.gsub /&#(\d+|x[\da-fA-F]+);/, 'HTMLCSSINLINERESCAPE\1::::::::'
|
72
|
-
end
|
73
|
-
|
74
|
-
def unescape_numeric_character_reference(text)
|
75
|
-
text.gsub /HTMLCSSINLINERESCAPE(\d+|x[\da-fA-F]+)::::::::/, '&#\1;'
|
76
|
-
end
|
77
|
-
|
78
|
-
def stylesheet_link_node(document)
|
79
|
-
document.xpath '//link[@rel="stylesheet"]'
|
80
|
-
end
|
81
|
-
|
82
|
-
def css_path(stylesheet)
|
83
|
-
stylesheet.path
|
84
|
-
end
|
85
|
-
|
86
|
-
def extract_pseudo_style(css)
|
87
|
-
pseudo_style = TinyCss.new
|
88
|
-
pseudo_selectors(css).each do |v|
|
89
|
-
pseudo_style.style[v] = css.style[v]
|
90
|
-
css.style.delete(v)
|
91
|
-
end
|
92
|
-
pseudo_style
|
93
|
-
end
|
94
|
-
|
95
|
-
def embed_pseudo_style(doc, pseudo_style)
|
96
|
-
return if pseudo_style.style.keys.empty?
|
97
|
-
|
98
|
-
raise unless doc.at('/html/head')
|
99
|
-
doc.at('/html/head').add_child <<-STYLE
|
100
|
-
<style type="text/css">
|
101
|
-
#{pseudo_style.write_string}
|
102
|
-
</style>
|
103
|
-
STYLE
|
104
|
-
doc
|
105
|
-
end
|
106
|
-
|
107
|
-
def pseudo_selectors(css)
|
108
|
-
css.style.keys.grep(/a:(link|focus|visited)/)
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
|
113
|
-
def docomo_2_0_browser?(controller)
|
114
|
-
controller.request.user_agent =~ /DoCoMo\/2\.0 [^(]*\(c(\d+);/ && $1.to_i >= 500
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docomo_css
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- milk1000cc
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-
|
19
|
+
date: 2010-12-16 00:00:00 +09:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -47,6 +47,22 @@ dependencies:
|
|
47
47
|
version: "0"
|
48
48
|
type: :runtime
|
49
49
|
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rails
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 7
|
59
|
+
segments:
|
60
|
+
- 3
|
61
|
+
- 0
|
62
|
+
- 0
|
63
|
+
version: 3.0.0
|
64
|
+
type: :runtime
|
65
|
+
version_requirements: *id003
|
50
66
|
description: Inlines CSS so that you can use external CSS with docomo handsets.
|
51
67
|
email: info@milk1000.cc
|
52
68
|
executables: []
|
@@ -58,6 +74,7 @@ extra_rdoc_files: []
|
|
58
74
|
files:
|
59
75
|
- MIT-LICENSE
|
60
76
|
- README.rdoc
|
77
|
+
- lib/docomo_css/filter.rb
|
61
78
|
- lib/docomo_css/railtie.rb
|
62
79
|
- lib/docomo_css/stylesheet.rb
|
63
80
|
- lib/docomo_css/version.rb
|