opal-browser 0.1.0.beta1
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 +7 -0
- data/.gitignore +5 -0
- data/.yardopts +1 -0
- data/Gemfile +11 -0
- data/README.md +106 -0
- data/Rakefile +5 -0
- data/config.ru +63 -0
- data/lib/opal/browser.rb +4 -0
- data/opal-browser.gemspec +23 -0
- data/opal/browser.rb +10 -0
- data/opal/browser/animation_frame.rb +29 -0
- data/opal/browser/canvas.rb +277 -0
- data/opal/browser/canvas/data.rb +73 -0
- data/opal/browser/canvas/gradient.rb +37 -0
- data/opal/browser/canvas/style.rb +123 -0
- data/opal/browser/canvas/text.rb +55 -0
- data/opal/browser/compatibility.rb +59 -0
- data/opal/browser/compatibility/animation_frame.rb +93 -0
- data/opal/browser/compatibility/dom/document/window.rb +15 -0
- data/opal/browser/compatibility/dom/element/css.rb +15 -0
- data/opal/browser/compatibility/dom/element/matches.rb +31 -0
- data/opal/browser/compatibility/dom/element/offset.rb +20 -0
- data/opal/browser/compatibility/dom/element/scroll.rb +25 -0
- data/opal/browser/compatibility/dom/element/style.rb +15 -0
- data/opal/browser/compatibility/dom/mutation_observer.rb +47 -0
- data/opal/browser/compatibility/http/request.rb +15 -0
- data/opal/browser/compatibility/immediate.rb +107 -0
- data/opal/browser/compatibility/window/scroll.rb +27 -0
- data/opal/browser/compatibility/window/size.rb +13 -0
- data/opal/browser/compatibility/window/view.rb +13 -0
- data/opal/browser/console.rb +137 -0
- data/opal/browser/cookies.rb +79 -0
- data/opal/browser/css.rb +24 -0
- data/opal/browser/css/declaration.rb +88 -0
- data/opal/browser/css/rule.rb +48 -0
- data/opal/browser/css/rule/style.rb +16 -0
- data/opal/browser/css/style_sheet.rb +83 -0
- data/opal/browser/css/unit.rb +188 -0
- data/opal/browser/dom.rb +95 -0
- data/opal/browser/dom/attribute.rb +19 -0
- data/opal/browser/dom/builder.rb +97 -0
- data/opal/browser/dom/cdata.rb +9 -0
- data/opal/browser/dom/character_data.rb +37 -0
- data/opal/browser/dom/comment.rb +9 -0
- data/opal/browser/dom/compatibility.rb +8 -0
- data/opal/browser/dom/document.rb +83 -0
- data/opal/browser/dom/document_fragment.rb +7 -0
- data/opal/browser/dom/element.rb +290 -0
- data/opal/browser/dom/element/input.rb +17 -0
- data/opal/browser/dom/element/offset.rb +67 -0
- data/opal/browser/dom/element/position.rb +37 -0
- data/opal/browser/dom/element/scroll.rb +49 -0
- data/opal/browser/dom/event.rb +240 -0
- data/opal/browser/dom/event/animation.rb +26 -0
- data/opal/browser/dom/event/audio_processing.rb +31 -0
- data/opal/browser/dom/event/base.rb +207 -0
- data/opal/browser/dom/event/before_unload.rb +13 -0
- data/opal/browser/dom/event/clipboard.rb +26 -0
- data/opal/browser/dom/event/close.rb +35 -0
- data/opal/browser/dom/event/composition.rb +38 -0
- data/opal/browser/dom/event/custom.rb +30 -0
- data/opal/browser/dom/event/device_light.rb +21 -0
- data/opal/browser/dom/event/device_motion.rb +38 -0
- data/opal/browser/dom/event/device_orientation.rb +36 -0
- data/opal/browser/dom/event/device_proximity.rb +31 -0
- data/opal/browser/dom/event/drag.rb +113 -0
- data/opal/browser/dom/event/focus.rb +23 -0
- data/opal/browser/dom/event/gamepad.rb +47 -0
- data/opal/browser/dom/event/hash_change.rb +26 -0
- data/opal/browser/dom/event/keyboard.rb +93 -0
- data/opal/browser/dom/event/message.rb +50 -0
- data/opal/browser/dom/event/mouse.rb +253 -0
- data/opal/browser/dom/event/page_transition.rb +21 -0
- data/opal/browser/dom/event/pop_state.rb +21 -0
- data/opal/browser/dom/event/progress.rb +31 -0
- data/opal/browser/dom/event/sensor.rb +13 -0
- data/opal/browser/dom/event/storage.rb +41 -0
- data/opal/browser/dom/event/touch.rb +69 -0
- data/opal/browser/dom/event/ui.rb +22 -0
- data/opal/browser/dom/event/wheel.rb +49 -0
- data/opal/browser/dom/mutation_observer.rb +118 -0
- data/opal/browser/dom/node.rb +317 -0
- data/opal/browser/dom/node_set.rb +88 -0
- data/opal/browser/dom/text.rb +21 -0
- data/opal/browser/effects.rb +39 -0
- data/opal/browser/event_source.rb +67 -0
- data/opal/browser/history.rb +54 -0
- data/opal/browser/http.rb +129 -0
- data/opal/browser/http/binary.rb +57 -0
- data/opal/browser/http/compatibility.rb +1 -0
- data/opal/browser/http/headers.rb +90 -0
- data/opal/browser/http/parameters.rb +8 -0
- data/opal/browser/http/request.rb +331 -0
- data/opal/browser/http/response.rb +115 -0
- data/opal/browser/immediate.rb +43 -0
- data/opal/browser/interval.rb +93 -0
- data/opal/browser/location.rb +77 -0
- data/opal/browser/navigator.rb +151 -0
- data/opal/browser/screen.rb +40 -0
- data/opal/browser/socket.rb +115 -0
- data/opal/browser/storage.rb +149 -0
- data/opal/browser/timeout.rb +60 -0
- data/opal/browser/utils.rb +56 -0
- data/opal/browser/version.rb +3 -0
- data/opal/browser/window.rb +113 -0
- data/opal/browser/window/compatibility.rb +3 -0
- data/opal/browser/window/scroll.rb +49 -0
- data/opal/browser/window/size.rb +35 -0
- data/opal/browser/window/view.rb +18 -0
- data/spec/dom/builder_spec.rb +69 -0
- data/spec/dom/document_spec.rb +40 -0
- data/spec/dom/element_spec.rb +46 -0
- data/spec/dom/event_spec.rb +127 -0
- data/spec/dom/mutation_observer_spec.rb +37 -0
- data/spec/dom/node_spec.rb +154 -0
- data/spec/dom_spec.rb +13 -0
- data/spec/event_source_spec.rb +42 -0
- data/spec/history_spec.rb +48 -0
- data/spec/http_spec.rb +87 -0
- data/spec/immediate_spec.rb +12 -0
- data/spec/json2.js +486 -0
- data/spec/sizzle.js +5 -0
- data/spec/socket_spec.rb +43 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/storage_spec.rb +26 -0
- data/spec/window_spec.rb +10 -0
- metadata +240 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Browser
|
|
2
|
+
|
|
3
|
+
class Cookies
|
|
4
|
+
include Enumerable
|
|
5
|
+
|
|
6
|
+
def initialize(document)
|
|
7
|
+
@document = document
|
|
8
|
+
|
|
9
|
+
@options = {
|
|
10
|
+
expires: Time.now + 1.day,
|
|
11
|
+
path: '',
|
|
12
|
+
domain: '',
|
|
13
|
+
secure: ''
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def options (value = nil)
|
|
18
|
+
value ? @options.merge!(value) : @options
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def [] (name)
|
|
22
|
+
matches = `#@document.cookie`.scan(/#{Regexp.escape(key.encode_uri_component)}=([^;]*)/)
|
|
23
|
+
|
|
24
|
+
return if matches.empty?
|
|
25
|
+
|
|
26
|
+
result = matches.map {|cookie|
|
|
27
|
+
JSON.parse(cookie.match(/^.*?=(.*)$/)[1].decode_uri_component)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
result.length == 1 ? result.first : result
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def []= (name, value, options = {})
|
|
34
|
+
`#@document.cookie = #{encode name, value.is_a?(String) ? value : JSON.dump(value), @options.merge(options)}`
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def delete (name)
|
|
38
|
+
`#@document.cookie = #{encode name, '', expires: Time.now}`
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def keys
|
|
42
|
+
Array(`#@document.cookie.split(/; /)`).map {|cookie|
|
|
43
|
+
cookie.split(/\s*=\s*/).first
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def values
|
|
48
|
+
keys.map {|key|
|
|
49
|
+
self[key]
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def each
|
|
54
|
+
keys.each {|key|
|
|
55
|
+
yield key, self[key]
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def clear
|
|
60
|
+
keys.each {|key|
|
|
61
|
+
delete key
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
protected
|
|
66
|
+
def encode (key, value, options = {})
|
|
67
|
+
result = "#{key.encode_uri_component}=#{value.encode_uri_component}; "
|
|
68
|
+
|
|
69
|
+
result += "max-age=#{options[:max_age]}; " if options[:max_age]
|
|
70
|
+
result += "expires=#{options[:expires].to_utc}; " if options[:expires]
|
|
71
|
+
result += "path=#{options[:path]}; " if options[:path]
|
|
72
|
+
result += "domain=#{options[:domain]}; " if options[:domain]
|
|
73
|
+
result += 'secure' if options[:secure]
|
|
74
|
+
|
|
75
|
+
result
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
data/opal/browser/css.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'browser/css/declaration'
|
|
2
|
+
require 'browser/css/style_sheet'
|
|
3
|
+
require 'browser/css/rule'
|
|
4
|
+
require 'browser/css/rule/style'
|
|
5
|
+
|
|
6
|
+
module Kernel
|
|
7
|
+
# Create a <style> element from a string or a block using the
|
|
8
|
+
# {Browser::CSS::Builder} DSL.
|
|
9
|
+
#
|
|
10
|
+
# @param text [String] the CSS text
|
|
11
|
+
# @return [Browser::DOM::Element] the create <style> element
|
|
12
|
+
def CSS(text = nil, &block)
|
|
13
|
+
style = $document.create_element(:style)
|
|
14
|
+
style[:type] = 'text/css'
|
|
15
|
+
|
|
16
|
+
if block
|
|
17
|
+
style.inner_text = Paggio.css(&block)
|
|
18
|
+
else
|
|
19
|
+
style.inner_text = text
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
style
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Browser; module CSS
|
|
2
|
+
|
|
3
|
+
class Declaration
|
|
4
|
+
include Native
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
def rule
|
|
8
|
+
Rule.new(`#@native.parentRule`) if defined?(`#@native.parentRule`)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def assign(data)
|
|
12
|
+
data.each {|name, value|
|
|
13
|
+
self[name] = value
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def replace(string)
|
|
20
|
+
`#@native.cssText = #{string}`
|
|
21
|
+
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def apply(&block)
|
|
26
|
+
Paggio::CSS::Definition.new(&block).each {|style|
|
|
27
|
+
# FIXME: use ternary operator when it's fixed
|
|
28
|
+
if style.important
|
|
29
|
+
`#@native.setProperty(#{style.name}, #{style.value}, "important")`
|
|
30
|
+
else
|
|
31
|
+
`#@native.setProperty(#{style.name}, #{style.value}, "")`
|
|
32
|
+
end
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def delete(name)
|
|
39
|
+
`#@native.removeProperty(#{name})`
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def [](name)
|
|
43
|
+
%x{
|
|
44
|
+
var result = #@native.getPropertyValue(#{name});
|
|
45
|
+
|
|
46
|
+
if (result == null || result === "") {
|
|
47
|
+
return nil;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def []=(name, value)
|
|
55
|
+
`#@native.setProperty(#{name}, #{value.to_s}, "")`
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def important?(name)
|
|
59
|
+
`#@native.getPropertyPriority(#{name}) == "important"`
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def each(&block)
|
|
63
|
+
return enum_for :each unless block_given?
|
|
64
|
+
|
|
65
|
+
%x{
|
|
66
|
+
for (var i = 0, length = #@native.length; i < length; i++) {
|
|
67
|
+
var name = #@native.item(i);
|
|
68
|
+
|
|
69
|
+
#{yield `name`, self[`name`]}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
alias_native :length
|
|
77
|
+
alias_native :to_s, :cssText
|
|
78
|
+
|
|
79
|
+
def method_missing(name, value = nil)
|
|
80
|
+
if name.end_with? ?=
|
|
81
|
+
self[name[0 .. -2]] = value
|
|
82
|
+
else
|
|
83
|
+
self[name]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end; end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Browser; module CSS
|
|
2
|
+
|
|
3
|
+
class Rule
|
|
4
|
+
include Native
|
|
5
|
+
|
|
6
|
+
STYLE_RULE = 1
|
|
7
|
+
CHARSET_RULE = 2
|
|
8
|
+
IMPORT_RULE = 3
|
|
9
|
+
MEDIA_RULE = 4
|
|
10
|
+
FONT_FACE_RULE = 5
|
|
11
|
+
PAGE_RULE = 6
|
|
12
|
+
KEYFRAMES_RULE = 7
|
|
13
|
+
KEYFRAME_RULE = 8
|
|
14
|
+
NAMESPACE_RULE = 10
|
|
15
|
+
COUNTER_STYLE_RULE = 11
|
|
16
|
+
SUPPORTS_RULE = 12
|
|
17
|
+
DOCUMENT_RULE = 13
|
|
18
|
+
FONT_FEATURE_VALUES_RULE = 14
|
|
19
|
+
VIEWPORT_RULE = 15
|
|
20
|
+
REGION_STYLE_RULE = 16
|
|
21
|
+
|
|
22
|
+
def self.new(rule)
|
|
23
|
+
if self == Rule
|
|
24
|
+
@classes ||= [nil, Style]
|
|
25
|
+
|
|
26
|
+
if klass = @classes[`rule.type`]
|
|
27
|
+
klass.new(rule)
|
|
28
|
+
else
|
|
29
|
+
raise ArgumentError, 'cannot instantiate a non derived Rule object'
|
|
30
|
+
end
|
|
31
|
+
else
|
|
32
|
+
super(rule)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
alias_native :text, :cssText
|
|
37
|
+
alias_native :to_s, :cssText
|
|
38
|
+
|
|
39
|
+
def parent
|
|
40
|
+
Rule.new(`#@native.parentRule`) if `#@native.parentRule != null`
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def style_sheet
|
|
44
|
+
StyleSheet.new(`#@native.parentStyleSheet`) if `#@native.parentStyleSheet != null`
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end; end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Browser; module CSS; class Rule
|
|
2
|
+
|
|
3
|
+
class Style < Rule
|
|
4
|
+
alias_native :selector, :selectorText
|
|
5
|
+
alias_native :id, :selectorText
|
|
6
|
+
|
|
7
|
+
def declaration
|
|
8
|
+
Declaration.new(`#@native.style`)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def method_missing(*args, &block)
|
|
12
|
+
declaration.__send__(*args, &block)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end; end; end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Browser; module CSS
|
|
2
|
+
|
|
3
|
+
class StyleSheet
|
|
4
|
+
include Native
|
|
5
|
+
|
|
6
|
+
def initialize(what)
|
|
7
|
+
if what.is_a? DOM::Element
|
|
8
|
+
super(`#{what.to_n}.sheet`)
|
|
9
|
+
else
|
|
10
|
+
super(what)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
alias_native :disabled?, :disabled
|
|
15
|
+
alias_native :href
|
|
16
|
+
alias_native :title
|
|
17
|
+
alias_native :type
|
|
18
|
+
|
|
19
|
+
def media
|
|
20
|
+
Media.new(`#@native.media`) if `#@native.media != null`
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def owner
|
|
24
|
+
DOM(`#@native.ownerNode`)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def parent
|
|
28
|
+
Sheet.new(`#@native.parentStyleSheet`) if `#@native.parentStyleSheet != null`
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def rules
|
|
32
|
+
Native::Array.new(`#@native.cssRules`) { |e|
|
|
33
|
+
Rule.new(e)
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def delete(index)
|
|
38
|
+
`#@native.deleteRule(index)`
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def insert(index, rule)
|
|
42
|
+
`#@native.insertRule(#{rule}, #{index})`
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def rule(selector, body)
|
|
46
|
+
unless String === selector
|
|
47
|
+
selector = selector.join ', '
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
unless String === body
|
|
51
|
+
body = body.map {|name, value|
|
|
52
|
+
"#{name}: #{value};"
|
|
53
|
+
}.join "\n"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
insert(length, "#{selector} { #{body} }")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def [](id)
|
|
60
|
+
rules.find { |r| log r; r.id == id }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def method_missing(*args, &block)
|
|
64
|
+
rules.__send__(*args, &block)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class Media < Native::Array
|
|
68
|
+
alias_native :text, :mediaText
|
|
69
|
+
alias_native :to_s, :mediaText
|
|
70
|
+
|
|
71
|
+
def push(medium)
|
|
72
|
+
`#@native.appendMedium(#{medium})`
|
|
73
|
+
|
|
74
|
+
self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def delete(medium)
|
|
78
|
+
`#@native.deleteMedium(#{medium})`
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end; end
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
module Browser; module CSS
|
|
2
|
+
|
|
3
|
+
class Unit
|
|
4
|
+
COMPATIBLE = %i[in pt mm cm px pc]
|
|
5
|
+
|
|
6
|
+
attr_reader :type
|
|
7
|
+
|
|
8
|
+
def initialize(number, type)
|
|
9
|
+
@number = number
|
|
10
|
+
@type = type
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def coerce(other)
|
|
14
|
+
return self, other
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ==(other)
|
|
18
|
+
@number == convert(other, @type)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ===(other)
|
|
22
|
+
@type == other.type && @number == other.to_f
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
alias eql? ==
|
|
26
|
+
|
|
27
|
+
def hash
|
|
28
|
+
[@number, @type].hash
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
%i[em ex ch rem vh vw vmin vmax px mm cm in pt pc].each {|name|
|
|
32
|
+
define_method name do
|
|
33
|
+
Unit.new(convert(self, name), name)
|
|
34
|
+
end
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def +(other)
|
|
38
|
+
return Unit.new(@number + other, @type) unless Unit === other
|
|
39
|
+
|
|
40
|
+
if @type == other.type
|
|
41
|
+
Unit.new(@number + other.to_f, @type)
|
|
42
|
+
elsif compatible?(self) and compatible?(other)
|
|
43
|
+
Unit.new(@number + convert(other, @type), @type)
|
|
44
|
+
else
|
|
45
|
+
raise ArgumentError, "#{other.type} isn't compatible with #{@type}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def -(other)
|
|
50
|
+
return Unit.new(@number - other, @type) unless Unit === other
|
|
51
|
+
|
|
52
|
+
if @type == other.type
|
|
53
|
+
Unit.new(@number - other.to_f, @type)
|
|
54
|
+
elsif compatible?(self) and compatible?(other)
|
|
55
|
+
Unit.new(@number - convert(other, @type), @type)
|
|
56
|
+
else
|
|
57
|
+
raise ArgumentError, "#{other.type} isn't compatible with #{@type}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def *(other)
|
|
62
|
+
return Unit.new(@number * other, @type) unless Unit === other
|
|
63
|
+
|
|
64
|
+
if @type == other.type
|
|
65
|
+
Unit.new(@number * other.to_f, @type)
|
|
66
|
+
elsif compatible?(self) and compatible?(other)
|
|
67
|
+
Unit.new(@number * convert(other, @type), @type)
|
|
68
|
+
else
|
|
69
|
+
raise ArgumentError, "#{other.type} isn't compatible with #{@type}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def /(other)
|
|
74
|
+
return Unit.new(@number / other, @type) unless Unit === other
|
|
75
|
+
|
|
76
|
+
if @type == other.type
|
|
77
|
+
Unit.new(@number / other.to_f, @type)
|
|
78
|
+
elsif compatible?(self) and compatible?(other)
|
|
79
|
+
Unit.new(@number / convert(other, @type), @type)
|
|
80
|
+
else
|
|
81
|
+
raise ArgumentError, "#{other.type} isn't compatible with #{@type}"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def -@
|
|
86
|
+
Unit.new(@number * -1, @type)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def +@
|
|
90
|
+
Unit.new(@number, @type)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def to_i
|
|
94
|
+
@number.to_i
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def to_f
|
|
98
|
+
@number.to_f
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def to_u
|
|
102
|
+
self
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def to_s
|
|
106
|
+
"#{@number}#{@type}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
alias to_str to_s
|
|
110
|
+
alias inspect to_s
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
def compatible?(unit)
|
|
114
|
+
COMPATIBLE.include?(unit.type)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def convert(unit, type)
|
|
118
|
+
value = unit.to_f
|
|
119
|
+
|
|
120
|
+
return value if unit.type == type
|
|
121
|
+
|
|
122
|
+
px = case unit.type
|
|
123
|
+
when :in then value * 96
|
|
124
|
+
when :pt then value * 4.0 / 3.0
|
|
125
|
+
when :pc then value / 12 * 4.0 / 3.0
|
|
126
|
+
when :mm then value * 3.77953
|
|
127
|
+
when :cm then value * 10 * 3.77953
|
|
128
|
+
when :px then value
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
case type
|
|
132
|
+
when :in then px / 96.0
|
|
133
|
+
when :pt then px / 4.0 / 3.0
|
|
134
|
+
when :pc then px * 12 / 4.0 / 3.0
|
|
135
|
+
when :mm then px / 3.77953
|
|
136
|
+
when :cm then px / 10 / 3.77953
|
|
137
|
+
when :px then px
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end; end
|
|
143
|
+
|
|
144
|
+
class Numeric
|
|
145
|
+
Unit = Browser::CSS::Unit
|
|
146
|
+
|
|
147
|
+
%i[em ex ch rem vh vw vmin vmax px mm cm in pt pc].each {|name|
|
|
148
|
+
define_method name do
|
|
149
|
+
Unit.new(self, name)
|
|
150
|
+
end
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
alias old_percent %
|
|
154
|
+
|
|
155
|
+
def %(other = nil)
|
|
156
|
+
if other
|
|
157
|
+
old_percent(other)
|
|
158
|
+
else
|
|
159
|
+
Unit.new(self, :%)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def to_u
|
|
164
|
+
self
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
class String
|
|
169
|
+
def to_u
|
|
170
|
+
if matches = self.match(/^([\d+.]+)(.+)?$/)
|
|
171
|
+
value = matches[1].to_f
|
|
172
|
+
|
|
173
|
+
if unit = matches[2]
|
|
174
|
+
value.__send__(unit.downcase)
|
|
175
|
+
else
|
|
176
|
+
value
|
|
177
|
+
end
|
|
178
|
+
else
|
|
179
|
+
0
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
class NilClass
|
|
185
|
+
def to_u
|
|
186
|
+
0
|
|
187
|
+
end
|
|
188
|
+
end
|