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 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
@@ -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.send :include, DocomoCss
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
@@ -1,3 +1,3 @@
1
1
  class DocomoCss
2
- Version = "0.3.0"
2
+ Version = "0.4.0"
3
3
  end
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: 19
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.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-11-24 00:00:00 +09:00
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