galakei 0.3.8 → 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/Gemfile CHANGED
@@ -10,4 +10,6 @@ group :development, :test do
10
10
  gem 'sqlite3'
11
11
  gem 'rspec-rails'
12
12
  gem 'haml'
13
+ gem 'css_parser'
14
+ gem 'fakeweb'
13
15
  end
data/README.md CHANGED
@@ -2,7 +2,27 @@
2
2
 
3
3
  [Japanese feature phones](http://www.mobalean.com/en/keitai_web_technology_guide) (a.k.a., keitai, galakei) have a number of restrictions over normal web browsers. This library adds support for them.
4
4
 
5
- ### Goals
5
+ ## Goals
6
6
 
7
7
  * Provide support for 3G handsets from the major 3 carriers in Japan (docomo, au, SoftBank)
8
8
  * Avoid modifying Rails internals as much as possible
9
+
10
+ ## Examples
11
+
12
+ ### Inlining Styles
13
+
14
+ Old docomo handsets [don't support external stylesheets](http://www.keitai-dev.net/CSS). Additionally, only very limited CSS is supported. galakei/docomo_css automatically inlines CSS and manipulates markup to overcome these limitations.
15
+
16
+ # css file
17
+ h1 { color: red; background-color: blue}
18
+
19
+ # source html
20
+ <h1>Foo</h1>
21
+
22
+ # outputted html
23
+ <div style="background-color: blue;"><h1><span style="color:red;">Foo</span></h1>/div>
24
+
25
+ ## Thanks
26
+
27
+ * To [jpmobile](https://github.com/jpmobile/jpmobile) for offering the most mature Rails plugin for Rails
28
+ * To [docomo_css](https://github.com/milk1000cc/docomo_css) for providing the inspiration for galakei/docomo_css
data/galakei.gemspec CHANGED
@@ -17,8 +17,7 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_dependency 'actionpack', '>= 3.0.3'
19
19
  s.add_dependency 'rack', '>= 1.2.1'
20
- s.add_dependency 'docomo_css', '~> 0.4.4'
21
-
20
+ s.add_dependency 'css_parser'
22
21
 
23
22
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
23
  end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+ require 'css_parser'
3
+
4
+ class Galakei::DocomoCss::InlineStylesheet
5
+ def self.filter(controller)
6
+ return unless controller.request.imode_browser_1_0?
7
+ doc = Nokogiri::HTML(controller.response.body)
8
+ stylesheets = doc.xpath('//link[@rel="stylesheet"]')
9
+ return if stylesheets.empty?
10
+ stylesheets.each do |e|
11
+ e.unlink
12
+ parser = CssParser::Parser.new
13
+ uri = URI.parse(e['href'])
14
+ uri.scheme = controller.request.scheme unless uri.scheme
15
+ uri.host = controller.request.host unless uri.host
16
+ uri.port = controller.request.port unless uri.port
17
+ parser.load_uri!(uri)
18
+ stylesheet = Galakei::DocomoCss::Stylesheet.new(parser)
19
+ stylesheet.apply(doc)
20
+ end
21
+ controller.response.body = doc.to_xhtml(:encoding => doc.encoding)
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ module Galakei
2
+ module DocomoCss
3
+ class Railtie < Rails::Railtie
4
+ initializer "galakei.docomo_css" do |app|
5
+ ActiveSupport.on_load :action_controller do
6
+ after_filter Galakei::DocomoCss::InlineStylesheet
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,70 @@
1
+ require "css_parser"
2
+
3
+ class Galakei::DocomoCss::Stylesheet
4
+ def initialize(parsed_stylesheet)
5
+ @parsed_stylesheet = parsed_stylesheet
6
+ end
7
+
8
+ def apply(doc)
9
+ pseudo_styles = []
10
+ @parsed_stylesheet.each_rule_set do |ruleset|
11
+ ruleset.each_selector do |selector, declarations_string, specificity|
12
+ if selector =~ /a:(link|focus|visited)/
13
+ pseudo_styles << "#{selector} { #{declarations_string} }"
14
+ else
15
+ embed_style(doc, ruleset, selector)
16
+ end
17
+ end
18
+ end
19
+ unless pseudo_styles.empty?
20
+ doc.at("/html/head").add_child(<<-EOD)
21
+ <style type="text/css">
22
+ <![CDATA[
23
+ #{pseudo_styles.join("\n")}
24
+ ]]>
25
+ </style>
26
+ EOD
27
+ end
28
+ doc
29
+ end
30
+
31
+ private
32
+
33
+ def merge_style(e, s)
34
+ if e["style"]
35
+ e['style'] += ";" unless e['style'] =~ /;\Z/
36
+ e['style'] += s
37
+ else
38
+ e["style"] = s
39
+ end
40
+ end
41
+
42
+ def wrap_all_children(e, s)
43
+ new_parent = e.document.parse(s).first
44
+ e.children.each {|f| new_parent.add_child(f)}
45
+ e.add_child(new_parent)
46
+ end
47
+
48
+ def embed_style(doc, ruleset, selector)
49
+ doc.css(selector).each do |e|
50
+ ruleset.each_declaration do |property, value, is_important|
51
+ s = "#{property}: #{value};"
52
+ if selector =~ /^(h\d|p)[^\s]*$/
53
+ if %w[color font-size].include?(property)
54
+ wrap_all_children(e, '<span>')
55
+ merge_style(e.children.first, s)
56
+ elsif %w[background-color].include?(property)
57
+ div = Nokogiri.make("<div>")
58
+ merge_style(div, s)
59
+ e.replace(div)
60
+ div.add_child(e)
61
+ else
62
+ merge_style(e, s)
63
+ end
64
+ else
65
+ merge_style(e, s)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,4 @@
1
+ module Galakei::DocomoCss
2
+ autoload :Stylesheet, "galakei/docomo_css/stylesheet"
3
+ autoload :InlineStylesheet, "galakei/docomo_css/inline_stylesheet"
4
+ end
@@ -1,3 +1,4 @@
1
+ require 'active_support/core_ext/string/output_safety'
1
2
  module Galakei
2
3
  class EmojiTable
3
4
  MAPPING = {
@@ -22,10 +23,24 @@ module Galakei
22
23
  :sparkle => %w[2747 E6FA E46C E32E],
23
24
  :copyright_sign => %w[00A9 E731 E558 E24E],
24
25
  :registered_sign => %w[00AE E736 E559 E24F],
25
- :trade_mark_sign => %w[2122 E732 E54E E537]
26
+ :trade_mark_sign => %w[2122 E732 E54E E537],
27
+ :hash_key => [ %w[0023 20E3] ] + %w[E6E0 EB84 E210],
28
+ :keycap_1 => [ %w[0031 20E3] ] + %w[E6E2 E522 E21C],
29
+ :keycap_2 => [ %w[0032 20E3] ] + %w[E6E3 E523 E21D],
30
+ :keycap_3 => [ %w[0033 20E3] ] + %w[E6E4 E524 E21E],
31
+ :keycap_4 => [ %w[0034 20E3] ] + %w[E6E5 E525 E21F],
32
+ :keycap_5 => [ %w[0035 20E3] ] + %w[E6E6 E526 E220],
33
+ :keycap_6 => [ %w[0036 20E3] ] + %w[E6E7 E527 E221],
34
+ :keycap_7 => [ %w[0037 20E3] ] + %w[E6E8 E528 E222],
35
+ :keycap_8 => [ %w[0040 20E3] ] + %w[E6E9 E529 E223],
36
+ :keycap_9 => [ %w[0041 20E3] ] + %w[E6EA E52A E224],
37
+ :keycap_0 => [ %w[0030 20E3] ] + %w[E6EB E52C E225],
26
38
  }
27
39
  MAPPING.each do |k,v|
28
- MAPPING[k] = v.map {|s| "&#x#{s};".html_safe}
40
+ MAPPING[k] = v.map do |a|
41
+ a = [ a ] if a.is_a?(String)
42
+ a.map {|s| "&#x#{s};"}.join.html_safe
43
+ end
29
44
  define_method k do
30
45
  MAPPING[k][@carrier]
31
46
  end
@@ -1,12 +1,9 @@
1
- require 'docomo_css'
2
-
3
1
  module Galakei
4
2
  class Railtie < Rails::Railtie
5
3
  config.galakei = ActiveSupport::OrderedOptions.new
6
- initializer "galakei.extend.action_controller", :after => "docomo_css.extend.action_controller" do |app|
4
+ initializer "galakei.extend.action_controller" do |app|
7
5
  ActiveSupport.on_load :action_controller do
8
6
  include Galakei::HelperMethods
9
- docomo_filter
10
7
  filters = %w[Views ContentType]
11
8
  filters << :Haml if defined?(Haml)
12
9
  filters.each {|f| Galakei::Filter.const_get(f).inject(self) }
@@ -19,3 +16,4 @@ module Galakei
19
16
  end
20
17
 
21
18
  require 'galakei/session_id_parameter/railtie'
19
+ require 'galakei/docomo_css/railtie'
@@ -1,5 +1,3 @@
1
- require 'docomo_css'
2
-
3
1
  module Galakei
4
2
  module SessionIdParameter
5
3
  class Railtie < Rails::Railtie
@@ -1,3 +1,3 @@
1
1
  module Galakei
2
- VERSION = "0.3.8"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/galakei.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  if defined?(Rails)
2
2
  require 'galakei/railtie'
3
3
  require 'galakei/use_rack_request_to_extract_sid'
4
- require 'docomo_css/railtie'
5
4
  end
6
5
  require 'galakei/request'
6
+ require 'galakei/docomo_css'
7
7
 
8
8
  module Galakei
9
9
  autoload :Email, "galakei/email"
@@ -1,4 +1,8 @@
1
+ !!! XML
2
+ !!! Mobile
1
3
  %html
2
4
  %head
5
+ %meta{"http-equiv" => "Content-Type", :content => "application/xhtml+xml;charset=UTF-8"}
6
+ = yield :head if content_for?(:head)
3
7
  %body
4
8
  = yield
@@ -0,0 +1,55 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/acceptance_helper')
3
+ require 'fakeweb'
4
+
5
+ class DocomoCssController < ApplicationController
6
+ def simple
7
+ html = <<-EOD
8
+ <% content_for(:head, stylesheet_link_tag("docomo_css/simple.css")) %>
9
+ <span>color</span>
10
+ EOD
11
+ render :inline => html, :layout => true
12
+ end
13
+
14
+ def external
15
+ html = <<-EOD
16
+ <% content_for(:head, stylesheet_link_tag("http://www.galakei.com/external.css")) %>
17
+ <span>color</span>
18
+ EOD
19
+ render :inline => html, :layout => true
20
+ end
21
+
22
+ def japanese
23
+ html = <<-EOD
24
+ <% content_for(:head, stylesheet_link_tag("docomo_css/simple.css")) %>
25
+ ほげ
26
+ EOD
27
+ render :inline => html, :layout => true
28
+ end
29
+ end
30
+
31
+ feature 'inlining of css' do
32
+ scenario 'requesting simple page for docomo', :driver => :docomo do
33
+ FakeWeb.register_uri(:get, 'http://www.example.com/stylesheets/docomo_css/simple.css', :body => "span { color: red }")
34
+ visit '/docomo_css/simple'
35
+ find("span")["style"].should == "color: red;"
36
+ page.should_not have_xpath("//link")
37
+ end
38
+ scenario 'requesting external page for docomo', :driver => :docomo do
39
+ FakeWeb.register_uri(:get, 'http://www.galakei.com/external.css', :body => "span { color: red }")
40
+ visit '/docomo_css/external'
41
+ find("span")["style"].should == "color: red;"
42
+ page.should_not have_xpath("//link")
43
+ end
44
+ %w[au softbank docomo_2_0].each do |carrier|
45
+ scenario "requesting simple page for #{carrier}", :driver => carrier.to_sym do
46
+ visit '/docomo_css/simple'
47
+ find("span")["style"].should be_nil
48
+ end
49
+ end
50
+
51
+ scenario 'response contains non-ascii', :driver => :docomo do
52
+ visit '/docomo_css/japanese'
53
+ page.body.should include("ほげ")
54
+ end
55
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/acceptance_helper')
3
+
4
+ class HamlController < ApplicationController
5
+ end
6
+
7
+ feature 'haml' do
8
+ %w[softbank au docomo].each do |s|
9
+ scenario "for #{s}", :driver => s.to_sym do
10
+ visit '/haml'
11
+ page.body.should include('<br />')
12
+ page.should have_css('br')
13
+ end
14
+ end
15
+ end
@@ -19,7 +19,6 @@ class HandsetDetectionController < ApplicationController
19
19
  end
20
20
  end
21
21
 
22
-
23
22
  feature 'handset detection' do
24
23
  scenario 'for docomo', :driver => :docomo do
25
24
  visit '/handset_detection'
@@ -13,6 +13,10 @@ Capybara.register_driver :docomo do |app|
13
13
  Capybara::Driver::RackTestWithUserAgent.new(app, "DoCoMo/2.0 P903i(c100;TB;W24H12)")
14
14
  end
15
15
 
16
+ Capybara.register_driver :docomo_2_0 do |app|
17
+ Capybara::Driver::RackTestWithUserAgent.new(app, "DoCoMo/2.0 SH06A3(c500;TB;W24H14)")
18
+ end
19
+
16
20
  Capybara.register_driver :au do |app|
17
21
  Capybara::Driver::RackTestWithUserAgent.new(app, "KDDI-CA32 UP.Browser/6.2.0.7.3.129 (GUI) MMP/2.0")
18
22
  end
@@ -0,0 +1,13 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/acceptance_helper')
3
+
4
+ class ViewsController < ApplicationController
5
+ def index
6
+ end
7
+ end
8
+
9
+ feature 'View path appending' do
10
+ scenario 'for docomo', :driver => :docomo do
11
+ visit '/views'
12
+ end
13
+ end
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+ require "nokogiri"
3
+
4
+ describe Galakei::DocomoCss::Stylesheet do
5
+ context "simple stylesheet" do
6
+ before do
7
+ parser = CssParser::Parser.new
8
+ parser.add_block!(<<-EOD)
9
+ span {
10
+ color: red;
11
+ }
12
+ EOD
13
+ @stylesheet = described_class.new(parser)
14
+ end
15
+ it "should apply style to matching element" do
16
+ doc = Nokogiri::HTML.fragment("<span>foo</span>")
17
+ @stylesheet.apply(doc)
18
+ doc.to_s.should == %q{<span style="color: red;">foo</span>}
19
+ end
20
+ it "should not apply style to non-matching element" do
21
+ doc = Nokogiri::HTML.fragment("<p>foo</p>")
22
+ @stylesheet.apply(doc)
23
+ doc.to_s.should == %q{<p>foo</p>}
24
+ end
25
+ end
26
+
27
+ context "stylesheet with multiple styles" do
28
+ before do
29
+ parser = CssParser::Parser.new
30
+ parser.add_block!(<<-EOD)
31
+ div {
32
+ background-color: red;
33
+ }
34
+
35
+ .alC {
36
+ text-align: center
37
+ }
38
+ EOD
39
+ @stylesheet = described_class.new(parser)
40
+ end
41
+
42
+ it "should apply style to element that matches one style" do
43
+ doc = Nokogiri::HTML.fragment("<div class='alC'>foo</span>")
44
+ @stylesheet.apply(doc)
45
+ doc.to_s.should == %q{<div class="alC" style="background-color: red;text-align: center;">foo</div>}
46
+ end
47
+ end
48
+ context "stylesheet with pseudo style" do
49
+ before do
50
+ parser = CssParser::Parser.new
51
+ parser.add_block!(<<-EOD)
52
+ a:link { color: red; }
53
+ a:focus { color: green; }
54
+ a:visited { color: blue; }
55
+ EOD
56
+ @stylesheet = described_class.new(parser)
57
+ end
58
+
59
+ it "should add to head" do
60
+ doc = Nokogiri::HTML(<<-EOD)
61
+ <html>
62
+ <head></head>
63
+ <body><a href="/">foo</a></body>
64
+ </html>
65
+ EOD
66
+ @stylesheet.apply(doc)
67
+ doc.at("//a").to_s.should == %q{<a href="/">foo</a>}
68
+ expected = <<-EOD
69
+ <style type="text/css">
70
+ <![CDATA[
71
+ a:link { color: red; }
72
+ a:focus { color: green; }
73
+ a:visited { color: blue; }
74
+ ]]>
75
+ </style>
76
+ EOD
77
+ doc.at("/html/head/style").to_s.strip.should == expected.strip
78
+ end
79
+ end
80
+
81
+ ((1..6).map {|i| "h#{i}"} + %w[p]).each do |tag|
82
+ context "style applied to #{tag}" do
83
+ before do
84
+ parser = CssParser::Parser.new
85
+ parser.add_block!(<<-EOD)
86
+ #{tag}.color { color: red; }
87
+ #{tag}.fontsize { font-size: x-small; }
88
+ #{tag}.backgroundcolor { background-color: blue; }
89
+ EOD
90
+ @stylesheet = described_class.new(parser)
91
+ end
92
+
93
+ it "should wrap children in span for color" do
94
+ doc = Nokogiri::HTML("<#{tag} class='color'>foo</#{tag}>")
95
+ @stylesheet.apply(doc)
96
+ doc.at("//#{tag}").to_s.should == %Q{<#{tag} class="color"><span style="color: red;">foo</span></#{tag}>}
97
+ end
98
+
99
+ it "should wrap children in span for font-size" do
100
+ doc = Nokogiri::HTML("<#{tag} class='fontsize'>foo</#{tag}>")
101
+ @stylesheet.apply(doc)
102
+ doc.at("//#{tag}").to_s.should == %Q{<#{tag} class="fontsize"><span style="font-size: x-small;">foo</span></#{tag}>}
103
+ end
104
+
105
+ it "should wrap multiple children in single span" do
106
+ doc = Nokogiri::HTML("<#{tag} class='fontsize'>foo<br />bar</#{tag}>")
107
+ @stylesheet.apply(doc)
108
+ doc.at("//#{tag}").to_s.should == %Q{<#{tag} class="fontsize"><span style="font-size: x-small;">foo<br>bar</span></#{tag}>}
109
+ end
110
+
111
+ it "should wrap element in div for background-color" do
112
+ doc = Nokogiri::HTML("<#{tag} class='backgroundcolor'>foo</#{tag}>")
113
+ @stylesheet.apply(doc)
114
+ doc.at("//div").to_s.should == %Q{<div style="background-color: blue;"><#{tag} class="backgroundcolor">foo</#{tag}></div>}
115
+ end
116
+ end
117
+ end
118
+
119
+ context "style applied to child of h1" do
120
+ before do
121
+ parser = CssParser::Parser.new
122
+ parser.add_block!(<<-EOD)
123
+ h1 span { color: red; }
124
+ EOD
125
+ @stylesheet = described_class.new(parser)
126
+ end
127
+
128
+ it "should not apply style to single h1" do
129
+ doc = Nokogiri::HTML("<h1>foo</h1>")
130
+ @stylesheet.apply(doc)
131
+ doc.at("//h1").to_s.should == %q{<h1>foo</h1>}
132
+ end
133
+
134
+ it "should apply style to neseted element" do
135
+ doc = Nokogiri::HTML("<h1><span>foo</span></h1>")
136
+ @stylesheet.apply(doc)
137
+ doc.at("//h1").to_s.should == %q{<h1><span style="color: red;">foo</span></h1>}
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Galakei::EmojiTable do
4
+ before do
5
+ @unicode, @docomo, @softbank, @au = %w[unicode docomo softbank au].map {|s| Galakei::EmojiTable.send(s)}
6
+ end
7
+
8
+ it "should handle single-character unicode" do
9
+ @unicode.black_sun_with_rays.should == "&#x2600;"
10
+ @docomo.black_sun_with_rays.should == "&#xE63E;"
11
+ @softbank.black_sun_with_rays.should == "&#xE04A;"
12
+ @au.black_sun_with_rays.should == "&#xE488;"
13
+ end
14
+
15
+ it "should handle multi-character unicode" do
16
+ @unicode.hash_key.should == "&#x0023;&#x20E3;"
17
+ @docomo.hash_key.should == "&#xE6E0;"
18
+ end
19
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
8
- - 8
9
- version: 0.3.8
7
+ - 4
8
+ - 0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Paul McMahon
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-24 00:00:00 +09:00
18
+ date: 2011-04-05 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -49,18 +49,16 @@ dependencies:
49
49
  type: :runtime
50
50
  version_requirements: *id002
51
51
  - !ruby/object:Gem::Dependency
52
- name: docomo_css
52
+ name: css_parser
53
53
  prerelease: false
54
54
  requirement: &id003 !ruby/object:Gem::Requirement
55
55
  none: false
56
56
  requirements:
57
- - - ~>
57
+ - - ">="
58
58
  - !ruby/object:Gem::Version
59
59
  segments:
60
60
  - 0
61
- - 4
62
- - 4
63
- version: 0.4.4
61
+ version: "0"
64
62
  type: :runtime
65
63
  version_requirements: *id003
66
64
  description: Japanese feature phones (a.k.a., keitai, galakei) have a number of restrictions over normal web browsers. This library adds support for them
@@ -79,6 +77,10 @@ files:
79
77
  - Rakefile
80
78
  - galakei.gemspec
81
79
  - lib/galakei.rb
80
+ - lib/galakei/docomo_css.rb
81
+ - lib/galakei/docomo_css/inline_stylesheet.rb
82
+ - lib/galakei/docomo_css/railtie.rb
83
+ - lib/galakei/docomo_css/stylesheet.rb
82
84
  - lib/galakei/email.rb
83
85
  - lib/galakei/emoji_table.rb
84
86
  - lib/galakei/filter/base.rb
@@ -97,13 +99,19 @@ files:
97
99
  - lib/galakei/version.rb
98
100
  - spec/acceptance/acceptance_helper.rb
99
101
  - spec/acceptance/app/.gitignore
102
+ - spec/acceptance/app/app/views/haml/index.html.haml
100
103
  - spec/acceptance/app/app/views/layouts/application.html.haml
101
104
  - spec/acceptance/app/fake.rb
105
+ - spec/acceptance/docomo_css_spec.rb
102
106
  - spec/acceptance/emoji_table_spec.rb
107
+ - spec/acceptance/haml_spec.rb
103
108
  - spec/acceptance/handset_detection_spec.rb
104
109
  - spec/acceptance/input_mode_spec.rb
105
110
  - spec/acceptance/session_spec.rb
106
111
  - spec/acceptance/support/handsets.rb
112
+ - spec/acceptance/views_spec.rb
113
+ - spec/galakei/docomo_css/stylesheet_spec.rb
114
+ - spec/galakei/emoji_table_spec.rb
107
115
  - spec/galakei/filter/content_type_spec.rb
108
116
  - spec/galakei/request_spec.rb
109
117
  - spec/spec_helper.rb