opal-browser 0.2.0.beta1 → 0.2.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.
- checksums.yaml +4 -4
- data/.travis.yml +22 -8
- data/Gemfile +1 -1
- data/README.md +59 -5
- data/index.html.erb +7 -4
- data/lib/opal-browser.rb +1 -0
- data/opal-browser.gemspec +1 -1
- data/opal/browser.rb +1 -0
- data/opal/browser/animation_frame.rb +26 -1
- data/opal/browser/canvas.rb +0 -10
- data/opal/browser/canvas/data.rb +0 -10
- data/opal/browser/canvas/gradient.rb +0 -10
- data/opal/browser/canvas/style.rb +0 -10
- data/opal/browser/canvas/text.rb +0 -10
- data/opal/browser/cookies.rb +6 -8
- data/opal/browser/database/sql.rb +194 -0
- data/opal/browser/delay.rb +25 -7
- data/opal/browser/dom.rb +2 -11
- data/opal/browser/dom/attribute.rb +12 -11
- data/opal/browser/dom/builder.rb +4 -9
- data/opal/browser/dom/document.rb +105 -41
- data/opal/browser/dom/element.rb +317 -231
- data/opal/browser/dom/element/attributes.rb +87 -0
- data/opal/browser/dom/element/data.rb +67 -0
- data/opal/browser/dom/element/input.rb +12 -1
- data/opal/browser/dom/element/offset.rb +5 -0
- data/opal/browser/dom/element/position.rb +11 -2
- data/opal/browser/dom/element/scroll.rb +77 -10
- data/opal/browser/dom/element/select.rb +36 -0
- data/opal/browser/dom/element/size.rb +5 -0
- data/opal/browser/dom/element/template.rb +9 -0
- data/opal/browser/dom/element/textarea.rb +24 -0
- data/opal/browser/dom/mutation_observer.rb +2 -2
- data/opal/browser/dom/node.rb +93 -51
- data/opal/browser/dom/node_set.rb +66 -48
- data/opal/browser/effects.rb +11 -0
- data/opal/browser/{dom/event.rb → event.rb} +32 -32
- data/opal/browser/{dom/event → event}/animation.rb +2 -2
- data/opal/browser/{dom/event → event}/audio_processing.rb +2 -2
- data/opal/browser/{dom/event → event}/base.rb +65 -7
- data/opal/browser/{dom/event → event}/before_unload.rb +2 -2
- data/opal/browser/{dom/event → event}/clipboard.rb +2 -2
- data/opal/browser/{dom/event → event}/close.rb +2 -2
- data/opal/browser/{dom/event → event}/composition.rb +2 -2
- data/opal/browser/{dom/event → event}/custom.rb +2 -2
- data/opal/browser/{dom/event → event}/device_light.rb +2 -2
- data/opal/browser/{dom/event → event}/device_motion.rb +2 -2
- data/opal/browser/{dom/event → event}/device_orientation.rb +2 -2
- data/opal/browser/{dom/event → event}/device_proximity.rb +2 -2
- data/opal/browser/{dom/event → event}/drag.rb +2 -2
- data/opal/browser/{dom/event → event}/focus.rb +2 -2
- data/opal/browser/{dom/event → event}/gamepad.rb +2 -2
- data/opal/browser/{dom/event → event}/hash_change.rb +2 -2
- data/opal/browser/{dom/event → event}/keyboard.rb +2 -2
- data/opal/browser/{dom/event → event}/message.rb +2 -2
- data/opal/browser/{dom/event → event}/mouse.rb +2 -2
- data/opal/browser/{dom/event → event}/page_transition.rb +2 -2
- data/opal/browser/{dom/event → event}/pop_state.rb +2 -2
- data/opal/browser/{dom/event → event}/progress.rb +2 -2
- data/opal/browser/{dom/event → event}/sensor.rb +2 -2
- data/opal/browser/{dom/event → event}/storage.rb +2 -2
- data/opal/browser/{dom/event → event}/touch.rb +2 -2
- data/opal/browser/{dom/event → event}/ui.rb +2 -2
- data/opal/browser/{dom/event → event}/wheel.rb +2 -2
- data/opal/browser/event_source.rb +1 -1
- data/opal/browser/http.rb +25 -0
- data/opal/browser/http/binary.rb +1 -0
- data/opal/browser/http/headers.rb +16 -2
- data/opal/browser/http/request.rb +14 -38
- data/opal/browser/immediate.rb +9 -3
- data/opal/browser/interval.rb +34 -11
- data/opal/browser/navigator.rb +23 -4
- data/opal/browser/screen.rb +1 -1
- data/opal/browser/socket.rb +5 -1
- data/opal/browser/storage.rb +51 -33
- data/opal/browser/support.rb +59 -4
- data/opal/browser/version.rb +1 -1
- data/opal/browser/window.rb +17 -9
- data/opal/browser/window/size.rb +17 -3
- data/opal/opal-browser.rb +1 -0
- data/spec/database/sql_spec.rb +131 -0
- data/spec/delay_spec.rb +38 -0
- data/spec/dom/attribute_spec.rb +49 -0
- data/spec/dom/builder_spec.rb +25 -8
- data/spec/dom/document_spec.rb +20 -0
- data/spec/dom/element/attributes_spec.rb +52 -0
- data/spec/dom/element_spec.rb +139 -4
- data/spec/dom/node_set_spec.rb +44 -0
- data/spec/interval_spec.rb +50 -0
- data/spec/runner.rb +46 -28
- data/spec/socket_spec.rb +1 -0
- data/spec/spec_helper.rb +0 -4
- data/spec/storage_spec.rb +1 -1
- metadata +57 -39
- data/opal/browser/http/parameters.rb +0 -8
data/opal/browser/delay.rb
CHANGED
@@ -17,8 +17,6 @@ class Delay
|
|
17
17
|
@window = Native.convert(window)
|
18
18
|
@after = time
|
19
19
|
@block = block
|
20
|
-
|
21
|
-
start
|
22
20
|
end
|
23
21
|
|
24
22
|
# Abort the timeout.
|
@@ -39,22 +37,42 @@ class Window
|
|
39
37
|
#
|
40
38
|
# @return [Delay] the object representing the timeout
|
41
39
|
def after(time, &block)
|
40
|
+
Delay.new(@native, time, &block).tap(&:start)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Execute a block after the given seconds, you have to call [#start] on it
|
44
|
+
# yourself.
|
45
|
+
#
|
46
|
+
# @param time [Float] the seconds after it gets called
|
47
|
+
#
|
48
|
+
# @return [Delay] the object representing the timeout
|
49
|
+
def after!(time, &block)
|
42
50
|
Delay.new(@native, time, &block)
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
46
54
|
end
|
47
55
|
|
56
|
+
module Kernel
|
57
|
+
# (see Browser::Window#after)
|
58
|
+
def after(time, &block)
|
59
|
+
$window.after(time, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
# (see Browser::Window#after!)
|
63
|
+
def after!(time, &block)
|
64
|
+
$window.after!(time, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
48
68
|
class Proc
|
49
69
|
# (see Browser::Window#after)
|
50
70
|
def after(time)
|
51
71
|
$window.after(time, &self)
|
52
72
|
end
|
53
|
-
end
|
54
73
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
$window.after(time, &block)
|
74
|
+
# (see Browser::Window#after!)
|
75
|
+
def after!(time)
|
76
|
+
$window.after!(time, &self)
|
59
77
|
end
|
60
78
|
end
|
data/opal/browser/dom.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'browser/dom/event'
|
2
1
|
require 'browser/dom/node_set'
|
3
2
|
require 'browser/dom/node'
|
4
3
|
require 'browser/dom/attribute'
|
@@ -40,14 +39,12 @@ module Kernel
|
|
40
39
|
def DOM(*args, &block)
|
41
40
|
if block
|
42
41
|
document = args.shift || $document
|
43
|
-
|
44
|
-
|
45
|
-
roots = Browser::DOM::Builder.new(document, element, &block).to_a
|
42
|
+
roots = Browser::DOM::Builder.new(document, &block).to_a
|
46
43
|
|
47
44
|
if roots.length == 1
|
48
45
|
roots.first
|
49
46
|
else
|
50
|
-
Browser::DOM::NodeSet.new(
|
47
|
+
Browser::DOM::NodeSet.new(roots)
|
51
48
|
end
|
52
49
|
else
|
53
50
|
what = args.shift
|
@@ -74,12 +71,6 @@ end
|
|
74
71
|
module Browser
|
75
72
|
|
76
73
|
class Window
|
77
|
-
include DOM::Event::Target
|
78
|
-
|
79
|
-
target {|value|
|
80
|
-
$window if `#{value} == window`
|
81
|
-
}
|
82
|
-
|
83
74
|
# Get the {DOM::Document} for this window.
|
84
75
|
#
|
85
76
|
# @return [DOM::Document]
|
@@ -4,21 +4,22 @@ module Browser; module DOM
|
|
4
4
|
class Attribute
|
5
5
|
include Native
|
6
6
|
|
7
|
-
# Returns true if the attribute is an id.
|
8
|
-
def id?
|
9
|
-
`#@native.isId`
|
10
|
-
end
|
11
|
-
|
12
7
|
# @!attribute [r] name
|
13
8
|
# @return [String] the name of the attribute
|
14
|
-
|
15
|
-
`#@native.name`
|
16
|
-
end
|
9
|
+
alias_native :name
|
17
10
|
|
18
|
-
# @!attribute
|
11
|
+
# @!attribute value
|
19
12
|
# @return [String] the value of the attribute
|
20
|
-
|
21
|
-
|
13
|
+
alias_native :value
|
14
|
+
alias_native :value=
|
15
|
+
|
16
|
+
# Returns true if the attribute is an id.
|
17
|
+
if Browser.supports? 'Attr.isId'
|
18
|
+
alias_native :id?, :isId
|
19
|
+
else
|
20
|
+
def id?
|
21
|
+
name == :id
|
22
|
+
end
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
data/opal/browser/dom/builder.rb
CHANGED
@@ -29,24 +29,19 @@ class Builder
|
|
29
29
|
def self.build(builder, item)
|
30
30
|
to_h.each {|klass, block|
|
31
31
|
if klass === item
|
32
|
-
|
32
|
+
return block.call(builder, item)
|
33
33
|
end
|
34
34
|
}
|
35
|
+
|
36
|
+
raise ArgumentError, "cannot build unknown item #{item}"
|
35
37
|
end
|
36
38
|
|
37
39
|
attr_reader :document, :element
|
38
40
|
|
39
|
-
def initialize(document,
|
41
|
+
def initialize(document, &block)
|
40
42
|
@document = document
|
41
|
-
@element = element
|
42
43
|
@builder = Paggio::HTML.new(&block)
|
43
44
|
@roots = @builder.each.map { |e| Builder.build(self, e) }
|
44
|
-
|
45
|
-
if @element
|
46
|
-
@roots.each {|root|
|
47
|
-
@element << root
|
48
|
-
}
|
49
|
-
end
|
50
45
|
end
|
51
46
|
|
52
47
|
def to_a
|
@@ -1,34 +1,11 @@
|
|
1
|
-
require 'browser/location'
|
2
|
-
|
3
1
|
module Browser; module DOM
|
4
2
|
|
5
3
|
class Document < Element
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
if Browser.supports? 'Document.view'
|
15
|
-
def window
|
16
|
-
Window.new(`#@native.defaultView`)
|
17
|
-
end
|
18
|
-
elsif Browser.supports? 'Document.window'
|
19
|
-
def window
|
20
|
-
Window.new(`#@native.parentWindow`)
|
21
|
-
end
|
22
|
-
else
|
23
|
-
def window
|
24
|
-
raise NotImplementedError, 'window from document unsupported'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def create_text(content)
|
29
|
-
DOM(`#@native.createTextNode(#{content})`)
|
30
|
-
end
|
31
|
-
|
4
|
+
# Get the first element matching the given ID, CSS selector or XPath.
|
5
|
+
#
|
6
|
+
# @param what [String] ID, CSS selector or XPath
|
7
|
+
#
|
8
|
+
# @return [Element?] the first matching element
|
32
9
|
def [](what)
|
33
10
|
%x{
|
34
11
|
var result = #@native.getElementById(what);
|
@@ -43,42 +20,129 @@ class Document < Element
|
|
43
20
|
|
44
21
|
alias at []
|
45
22
|
|
23
|
+
# @!attribute [r] body
|
24
|
+
# @return [Element?] the body element of the document
|
25
|
+
def body
|
26
|
+
DOM(`#@native.body`)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Create a new element for the document.
|
30
|
+
#
|
31
|
+
# @param name [String] the node name
|
32
|
+
# @param options [Hash] optional `:namespace` name
|
33
|
+
#
|
34
|
+
# @return [Element]
|
35
|
+
def create_element(name, options = {})
|
36
|
+
if ns = options[:namespace]
|
37
|
+
DOM(`#@native.createElementNS(#{ns}, #{name})`)
|
38
|
+
else
|
39
|
+
DOM(`#@native.createElement(name)`)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Create a new text node for the document.
|
44
|
+
#
|
45
|
+
# @param content [String] the text content
|
46
|
+
#
|
47
|
+
# @return [Text]
|
48
|
+
def create_text(content)
|
49
|
+
DOM(`#@native.createTextNode(#{content})`)
|
50
|
+
end
|
51
|
+
|
46
52
|
def document
|
47
53
|
self
|
48
54
|
end
|
49
55
|
|
56
|
+
# @!attribute [r] head
|
57
|
+
# @return [Element?] the head element of the document
|
58
|
+
def head
|
59
|
+
DOM(`#@native.getElementsByTagName("head")[0]`)
|
60
|
+
end
|
61
|
+
|
50
62
|
def inspect
|
51
|
-
"#<DOM::Document
|
63
|
+
"#<DOM::Document>"
|
52
64
|
end
|
53
65
|
|
54
|
-
|
55
|
-
|
66
|
+
if Browser.supports? 'Event.addListener'
|
67
|
+
def ready(&block)
|
68
|
+
raise ArgumentError, 'no block given' unless block
|
69
|
+
|
70
|
+
return block.call if ready?
|
71
|
+
|
72
|
+
on 'dom:load' do |e|
|
73
|
+
e.off
|
74
|
+
|
75
|
+
block.call
|
76
|
+
end
|
77
|
+
end
|
78
|
+
elsif Browser.supports? 'Event.attach'
|
79
|
+
def ready(&block)
|
80
|
+
raise ArgumentError, 'no block given' unless block
|
81
|
+
|
82
|
+
return block.call if ready?
|
83
|
+
|
84
|
+
on 'ready:state:change' do |e|
|
85
|
+
if ready?
|
86
|
+
e.off
|
87
|
+
|
88
|
+
block.call
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
# Wait for the document to be ready and call the block.
|
94
|
+
def ready(&block)
|
95
|
+
raise NotImplementedError, 'document ready unsupported'
|
96
|
+
end
|
56
97
|
end
|
57
98
|
|
58
|
-
|
59
|
-
|
99
|
+
# Check if the document is ready.
|
100
|
+
def ready?
|
101
|
+
`#@native.readyState === "complete"`
|
60
102
|
end
|
61
103
|
|
104
|
+
# @!attribute root
|
105
|
+
# @return [Element?] the root element of the document
|
62
106
|
def root
|
63
107
|
DOM(`#@native.documentElement`)
|
64
108
|
end
|
65
109
|
|
66
|
-
def
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def body
|
71
|
-
DOM(`#@native.body`)
|
110
|
+
def root=(element)
|
111
|
+
`#@native.documentElement = #{Native.convert(element)}`
|
72
112
|
end
|
73
113
|
|
114
|
+
# @!attribute [r] style_sheets
|
115
|
+
# @return [Array<CSS::StyleSheet>] the style sheets for the document
|
74
116
|
def style_sheets
|
75
117
|
Native::Array.new(`#@native.styleSheets`) {|e|
|
76
118
|
CSS::StyleSheet.new(e)
|
77
119
|
}
|
78
120
|
end
|
79
121
|
|
80
|
-
|
81
|
-
|
122
|
+
# @!attribute title
|
123
|
+
# @return [String] the document title
|
124
|
+
def title
|
125
|
+
`#@native.title`
|
126
|
+
end
|
127
|
+
|
128
|
+
def title=(value)
|
129
|
+
`#@native.title = value`
|
130
|
+
end
|
131
|
+
|
132
|
+
if Browser.supports? 'Document.view'
|
133
|
+
def window
|
134
|
+
Window.new(`#@native.defaultView`)
|
135
|
+
end
|
136
|
+
elsif Browser.supports? 'Document.window'
|
137
|
+
def window
|
138
|
+
Window.new(`#@native.parentWindow`)
|
139
|
+
end
|
140
|
+
else
|
141
|
+
# @!attribute [r] window
|
142
|
+
# @return [Window] the window for the document
|
143
|
+
def window
|
144
|
+
raise NotImplementedError, 'window from document unsupported'
|
145
|
+
end
|
82
146
|
end
|
83
147
|
end
|
84
148
|
|
data/opal/browser/dom/element.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
+
require 'browser/dom/element/attributes'
|
2
|
+
require 'browser/dom/element/data'
|
1
3
|
require 'browser/dom/element/position'
|
2
4
|
require 'browser/dom/element/offset'
|
3
5
|
require 'browser/dom/element/scroll'
|
4
6
|
require 'browser/dom/element/size'
|
5
7
|
|
6
8
|
require 'browser/dom/element/input'
|
9
|
+
require 'browser/dom/element/select'
|
7
10
|
require 'browser/dom/element/image'
|
11
|
+
require 'browser/dom/element/template'
|
12
|
+
require 'browser/dom/element/textarea'
|
8
13
|
|
9
14
|
module Browser; module DOM
|
10
15
|
|
@@ -17,7 +22,7 @@ class Element < Node
|
|
17
22
|
if self == Element
|
18
23
|
name = `node.nodeName`.capitalize
|
19
24
|
|
20
|
-
if Element.
|
25
|
+
if Element.constants.include?(name)
|
21
26
|
Element.const_get(name).new(node)
|
22
27
|
else
|
23
28
|
super
|
@@ -33,8 +38,76 @@ class Element < Node
|
|
33
38
|
DOM(value) rescue nil
|
34
39
|
}
|
35
40
|
|
36
|
-
|
41
|
+
if Browser.supports? 'Element.matches'
|
42
|
+
def =~(selector)
|
43
|
+
`#@native.matches(#{selector})`
|
44
|
+
end
|
45
|
+
elsif Browser.supports? 'Element.matches (Opera)'
|
46
|
+
def =~(selector)
|
47
|
+
`#@native.oMatchesSelector(#{selector})`
|
48
|
+
end
|
49
|
+
elsif Browser.supports? 'Element.matches (Internet Explorer)'
|
50
|
+
def =~(selector)
|
51
|
+
`#@native.msMatchesSelector(#{selector})`
|
52
|
+
end
|
53
|
+
elsif Browser.supports? 'Element.matches (Firefox)'
|
54
|
+
def =~(selector)
|
55
|
+
`#@native.mozMatchesSelector(#{selector})`
|
56
|
+
end
|
57
|
+
elsif Browser.supports? 'Element.matches (Chrome)'
|
58
|
+
def =~(selector)
|
59
|
+
`#@native.webkitMatchesSelector(#{selector})`
|
60
|
+
end
|
61
|
+
elsif Browser.loaded? 'Sizzle'
|
62
|
+
def =~(selector)
|
63
|
+
`Sizzle.matchesSelector(#@native, #{selector})`
|
64
|
+
end
|
65
|
+
else
|
66
|
+
# Check whether the element matches the given selector.
|
67
|
+
#
|
68
|
+
# @param selector [String] the CSS selector
|
69
|
+
def =~(selector)
|
70
|
+
raise NotImplementedError, 'selector matching unsupported'
|
71
|
+
end
|
72
|
+
end
|
37
73
|
|
74
|
+
# Query for children with the given XPpaths.
|
75
|
+
#
|
76
|
+
# @param paths [Array<String>] the XPaths to look for
|
77
|
+
#
|
78
|
+
# @return [NodeSet]
|
79
|
+
def /(*paths)
|
80
|
+
NodeSet[paths.map { |path| xpath(path) }]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get the attribute with the given name.
|
84
|
+
#
|
85
|
+
# @param name [String] the attribute name
|
86
|
+
# @param options [Hash] options for the attribute
|
87
|
+
#
|
88
|
+
# @option options [String] :namespace the namespace for the attribute
|
89
|
+
#
|
90
|
+
# @return [String?]
|
91
|
+
def [](name, options = {})
|
92
|
+
attributes.get(name, options)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Set the attribute with the given name and value.
|
96
|
+
#
|
97
|
+
# @param name [String] the attribute name
|
98
|
+
# @param value [Object] the attribute value
|
99
|
+
# @param options [Hash] the options for the attribute
|
100
|
+
#
|
101
|
+
# @option options [String] :namespace the namespace for the attribute
|
102
|
+
def []=(name, value, options = {})
|
103
|
+
attributes.set(name, value, options)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Add class names to the element.
|
107
|
+
#
|
108
|
+
# @param names [Array<String>] class names to add
|
109
|
+
#
|
110
|
+
# @return [self]
|
38
111
|
def add_class(*names)
|
39
112
|
classes = class_names + names
|
40
113
|
|
@@ -45,79 +118,131 @@ class Element < Node
|
|
45
118
|
self
|
46
119
|
end
|
47
120
|
|
48
|
-
|
49
|
-
|
121
|
+
# Get the first node that matches the given CSS selector or XPath.
|
122
|
+
#
|
123
|
+
# @param path_or_selector [String] an XPath or CSS selector
|
124
|
+
#
|
125
|
+
# @return [Node?]
|
126
|
+
def at(path_or_selector)
|
127
|
+
xpath(path_or_selector).first || css(path_or_selector).first
|
128
|
+
end
|
50
129
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
130
|
+
# Get the first node matching the given CSS selectors.
|
131
|
+
#
|
132
|
+
# @param rules [Array<String>] the CSS selectors to match with
|
133
|
+
#
|
134
|
+
# @return [Node?]
|
135
|
+
def at_css(*rules)
|
136
|
+
result = nil
|
56
137
|
|
57
|
-
|
138
|
+
rules.each {|rule|
|
139
|
+
if result = css(rule).first
|
140
|
+
break
|
141
|
+
end
|
142
|
+
}
|
143
|
+
|
144
|
+
result
|
58
145
|
end
|
59
146
|
|
60
|
-
|
147
|
+
# Get the first node matching the given XPath.
|
148
|
+
#
|
149
|
+
# @param paths [Array<String>] the XPath to match with
|
150
|
+
#
|
151
|
+
# @return [Node?]
|
152
|
+
def at_xpath(*paths)
|
153
|
+
result = nil
|
61
154
|
|
62
|
-
|
63
|
-
|
155
|
+
paths.each {|path|
|
156
|
+
if result = xpath(path).first
|
157
|
+
break
|
158
|
+
end
|
159
|
+
}
|
160
|
+
|
161
|
+
result
|
64
162
|
end
|
65
163
|
|
66
|
-
alias
|
164
|
+
alias attr []
|
67
165
|
|
68
|
-
|
69
|
-
Native::Array.new(`#@native.attributes`, get: :item) { |e| DOM(e) }
|
70
|
-
end
|
166
|
+
alias attribute []
|
71
167
|
|
168
|
+
# @!attribute [r] attributes
|
169
|
+
# @return [Attributes] the attributes for the element
|
72
170
|
def attributes(options = {})
|
73
171
|
Attributes.new(self, options)
|
74
172
|
end
|
75
173
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
`#@native.getAttribute(#{name.to_s}) || nil`
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def set(name, value, options = {})
|
85
|
-
if namespace = options[:namespace]
|
86
|
-
`#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
|
87
|
-
else
|
88
|
-
`#@native.setAttribute(#{name.to_s}, #{value.to_s})`
|
89
|
-
end
|
174
|
+
# @!attribute [r] attribute_nodes
|
175
|
+
# @return [NodeSet] the attribute nodes for the element
|
176
|
+
def attribute_nodes
|
177
|
+
NodeSet[Native::Array.new(`#@native.attributes`, get: :item)]
|
90
178
|
end
|
91
179
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
alias attr get
|
96
|
-
alias attribute get
|
97
|
-
|
98
|
-
alias get_attribute get
|
99
|
-
alias set_attribute set
|
180
|
+
# @!attribute [r] class_name
|
181
|
+
# @return [String] all the element class names
|
182
|
+
alias_native :class_name, :className
|
100
183
|
|
101
|
-
|
102
|
-
|
184
|
+
# @!attribute [r] class_names
|
185
|
+
# @return [Array<String>] all the element class names
|
186
|
+
def class_names
|
187
|
+
`#@native.className`.split(/\s+/).reject(&:empty?)
|
103
188
|
end
|
104
189
|
|
105
|
-
|
106
|
-
|
190
|
+
if Browser.supports? 'Query.css'
|
191
|
+
def css(path)
|
192
|
+
NodeSet[Native::Array.new(`#@native.querySelectorAll(path)`)]
|
193
|
+
rescue
|
194
|
+
NodeSet[]
|
195
|
+
end
|
196
|
+
elsif Browser.loaded? 'Sizzle'
|
197
|
+
def css(path)
|
198
|
+
NodeSet[`Sizzle(path, #@native)`]
|
199
|
+
rescue
|
200
|
+
NodeSet[]
|
201
|
+
end
|
202
|
+
else
|
203
|
+
# Query for children matching the given CSS selector.
|
204
|
+
#
|
205
|
+
# @param selector [String] the CSS selector
|
206
|
+
#
|
207
|
+
# @return [NodeSet]
|
208
|
+
def css(selector)
|
209
|
+
raise NotImplementedError, 'query by CSS selector unsupported'
|
210
|
+
end
|
107
211
|
end
|
108
212
|
|
109
|
-
|
110
|
-
|
111
|
-
|
213
|
+
# @overload data()
|
214
|
+
#
|
215
|
+
# Return the data for the element.
|
216
|
+
#
|
217
|
+
# @return [Data]
|
218
|
+
#
|
219
|
+
# @overload data(hash)
|
220
|
+
#
|
221
|
+
# Set data on the element.
|
222
|
+
#
|
223
|
+
# @param hash [Hash] the data to set
|
224
|
+
#
|
225
|
+
# @return [self]
|
226
|
+
def data(value = nil)
|
227
|
+
data = Data.new(self)
|
228
|
+
|
229
|
+
return data unless value
|
230
|
+
|
231
|
+
if Hash === value
|
232
|
+
data.assign(value)
|
233
|
+
else
|
234
|
+
raise ArgumentError, 'unknown data type'
|
235
|
+
end
|
112
236
|
|
113
|
-
|
114
|
-
`#@native.removeAttribute(name)`
|
237
|
+
self
|
115
238
|
end
|
116
239
|
|
117
|
-
|
118
|
-
|
119
|
-
|
240
|
+
alias get_attribute []
|
241
|
+
|
242
|
+
alias get []
|
120
243
|
|
244
|
+
# @!attribute height
|
245
|
+
# @return [Integer] the height of the element
|
121
246
|
def height
|
122
247
|
size.height
|
123
248
|
end
|
@@ -126,142 +251,133 @@ class Element < Node
|
|
126
251
|
size.height = value
|
127
252
|
end
|
128
253
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
size.width = value
|
135
|
-
end
|
254
|
+
# @!attribute id
|
255
|
+
# @return [String?] the ID of the element
|
256
|
+
def id
|
257
|
+
%x{
|
258
|
+
var id = #@native.id;
|
136
259
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
unless values.empty?
|
145
|
-
off.set(*values)
|
146
|
-
end
|
147
|
-
|
148
|
-
off
|
149
|
-
end
|
150
|
-
|
151
|
-
def offset=(value)
|
152
|
-
offset.set(*value)
|
260
|
+
if (id === "") {
|
261
|
+
return nil;
|
262
|
+
}
|
263
|
+
else {
|
264
|
+
return id;
|
265
|
+
}
|
266
|
+
}
|
153
267
|
end
|
154
268
|
|
155
|
-
def
|
156
|
-
|
269
|
+
def id=(value)
|
270
|
+
`#@native.id = #{value.to_s}`
|
157
271
|
end
|
158
272
|
|
273
|
+
# Set the inner DOM of the element using the {Builder}.
|
159
274
|
def inner_dom(&block)
|
275
|
+
clear
|
276
|
+
|
160
277
|
# FIXME: when block passing is fixed
|
161
278
|
doc = document
|
162
|
-
clear; Builder.new(doc, self, &block)
|
163
279
|
|
164
|
-
self
|
280
|
+
self << Builder.new(doc, self, &block).to_a
|
165
281
|
end
|
166
282
|
|
283
|
+
# Set the inner DOM with the given node.
|
284
|
+
#
|
285
|
+
# (see #append_child)
|
167
286
|
def inner_dom=(node)
|
168
|
-
clear
|
169
|
-
end
|
287
|
+
clear
|
170
288
|
|
171
|
-
|
172
|
-
paths.map { |path| xpath(path) }.flatten.uniq
|
289
|
+
self << node
|
173
290
|
end
|
174
291
|
|
175
|
-
def
|
176
|
-
|
177
|
-
end
|
292
|
+
def inspect
|
293
|
+
inspect = name.downcase
|
178
294
|
|
179
|
-
|
180
|
-
|
181
|
-
|
295
|
+
if id
|
296
|
+
inspect += '.' + id + '!'
|
297
|
+
end
|
182
298
|
|
183
|
-
|
184
|
-
|
299
|
+
unless class_names.empty?
|
300
|
+
inspect += '.' + class_names.join('.')
|
301
|
+
end
|
185
302
|
|
186
|
-
|
303
|
+
"#<DOM::Element: #{inspect}>"
|
187
304
|
end
|
188
305
|
|
189
|
-
|
190
|
-
|
191
|
-
|
306
|
+
# @!attribute offset
|
307
|
+
# @return [Offset] the offset of the element
|
308
|
+
def offset(*values)
|
309
|
+
off = Offset.new(self)
|
192
310
|
|
193
|
-
|
194
|
-
|
311
|
+
unless values.empty?
|
312
|
+
off.set(*values)
|
313
|
+
end
|
195
314
|
|
196
|
-
|
315
|
+
off
|
197
316
|
end
|
198
317
|
|
199
|
-
def
|
200
|
-
|
201
|
-
xpath(selector).to_a.concat(css(selector).to_a)
|
202
|
-
}.flatten.uniq
|
318
|
+
def offset=(value)
|
319
|
+
offset.set(*value)
|
203
320
|
end
|
204
321
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
var result = #@native.querySelectorAll(path);
|
210
|
-
|
211
|
-
return #{NodeSet.new(document,
|
212
|
-
Native::Array.new(`result`))};
|
213
|
-
}
|
214
|
-
catch(e) {
|
215
|
-
return #{NodeSet.new(document)};
|
216
|
-
}
|
217
|
-
}
|
218
|
-
end
|
219
|
-
elsif Browser.loaded? 'Sizzle'
|
220
|
-
def css(path)
|
221
|
-
NodeSet.new(document, `Sizzle(#{path}, #@native)`)
|
222
|
-
end
|
223
|
-
else
|
224
|
-
def css(selector)
|
225
|
-
raise NotImplementedError, 'query by CSS selector unsupported'
|
226
|
-
end
|
322
|
+
# @!attribute [r] position
|
323
|
+
# @return [Position] the position of the element
|
324
|
+
def position
|
325
|
+
Position.new(self)
|
227
326
|
end
|
228
327
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
328
|
+
# @!attribute [r] scroll
|
329
|
+
# @return [Scroll] the scrolling for the element
|
330
|
+
def scroll
|
331
|
+
Scroll.new(self)
|
332
|
+
end
|
233
333
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
catch (e) {
|
244
|
-
return #{NodeSet.new(document)};
|
245
|
-
}
|
246
|
-
}
|
247
|
-
end
|
248
|
-
else
|
249
|
-
def xpath(path)
|
250
|
-
raise NotImplementedError, 'query by XPath unsupported'
|
251
|
-
end
|
334
|
+
# Search for all the children matching the given XPaths or CSS selectors.
|
335
|
+
#
|
336
|
+
# @param selectors [Array<String>] mixed list of XPaths and CSS selectors
|
337
|
+
#
|
338
|
+
# @return [NodeSet]
|
339
|
+
def search(*selectors)
|
340
|
+
NodeSet.new selectors.map {|selector|
|
341
|
+
xpath(selector).to_a.concat(css(selector).to_a)
|
342
|
+
}.flatten.uniq
|
252
343
|
end
|
253
344
|
|
345
|
+
alias set []=
|
346
|
+
|
347
|
+
alias set_attribute []=
|
348
|
+
|
349
|
+
# @overload style()
|
350
|
+
#
|
351
|
+
# Return the style for the element.
|
352
|
+
#
|
353
|
+
# @return [CSS::Declaration]
|
354
|
+
#
|
355
|
+
# @overload style(data)
|
356
|
+
#
|
357
|
+
# Set the CSS style as string or set of values.
|
358
|
+
#
|
359
|
+
# @param data [String, Hash] the new style
|
360
|
+
#
|
361
|
+
# @return [self]
|
362
|
+
#
|
363
|
+
# @overload style(&block)
|
364
|
+
#
|
365
|
+
# Set the CSS style from a CSS builder DSL.
|
366
|
+
#
|
367
|
+
# @return [self]
|
254
368
|
def style(data = nil, &block)
|
255
369
|
style = CSS::Declaration.new(`#@native.style`)
|
256
370
|
|
257
371
|
return style unless data || block
|
258
372
|
|
259
|
-
if data
|
373
|
+
if String === data
|
260
374
|
style.replace(data)
|
261
|
-
elsif data
|
375
|
+
elsif Hash === data
|
262
376
|
style.assign(data)
|
263
377
|
elsif block
|
264
378
|
style.apply(&block)
|
379
|
+
else
|
380
|
+
raise ArgumentError, 'unknown data type'
|
265
381
|
end
|
266
382
|
|
267
383
|
self
|
@@ -276,111 +392,81 @@ class Element < Node
|
|
276
392
|
CSS::Declaration.new(`#@native.currentStyle`)
|
277
393
|
end
|
278
394
|
else
|
395
|
+
# @!attribute [r] style!
|
396
|
+
# @return [CSS::Declaration] get the computed style for the element
|
279
397
|
def style!
|
280
398
|
raise NotImplementedError, 'computed style unsupported'
|
281
399
|
end
|
282
400
|
end
|
283
401
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
402
|
+
# Remove an attribute from the element.
|
403
|
+
#
|
404
|
+
# @param name [String] the attribute name
|
405
|
+
def remove_attribute(name)
|
406
|
+
`#@native.removeAttribute(name)`
|
407
|
+
end
|
289
408
|
|
290
|
-
|
291
|
-
|
292
|
-
|
409
|
+
# Remove class names from the element.
|
410
|
+
#
|
411
|
+
# @param names [Array<String>] class names to remove
|
412
|
+
#
|
413
|
+
# @return [self]
|
414
|
+
def remove_class(*names)
|
415
|
+
classes = class_names - names
|
416
|
+
|
417
|
+
if classes.empty?
|
418
|
+
`#@native.removeAttribute('class')`
|
293
419
|
else
|
294
|
-
|
420
|
+
`#@native.className = #{classes.join ' '}`
|
421
|
+
end
|
295
422
|
|
296
|
-
|
423
|
+
self
|
424
|
+
end
|
297
425
|
|
298
|
-
|
299
|
-
|
426
|
+
# @!attribute [r] size
|
427
|
+
# @return [Size] the size of the element
|
428
|
+
def size(*inc)
|
429
|
+
Size.new(self, *inc)
|
430
|
+
end
|
300
431
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
return value;
|
306
|
-
}
|
307
|
-
}
|
308
|
-
end
|
432
|
+
# @!attribute width
|
433
|
+
# @return [Integer] the width of the element
|
434
|
+
def width
|
435
|
+
size.width
|
309
436
|
end
|
310
437
|
|
311
|
-
|
312
|
-
|
313
|
-
`#@native.matches(#{selector})`
|
314
|
-
end
|
315
|
-
elsif Browser.supports? 'Element.matches (Opera)'
|
316
|
-
def matches?(selector)
|
317
|
-
`#@native.oMatchesSelector(#{selector})`
|
318
|
-
end
|
319
|
-
elsif Browser.supports? 'Element.matches (Internet Explorer)'
|
320
|
-
def matches?(selector)
|
321
|
-
`#@native.msMatchesSelector(#{selector})`
|
322
|
-
end
|
323
|
-
elsif Browser.supports? 'Element.matches (Firefox)'
|
324
|
-
def matches?(selector)
|
325
|
-
`#@native.mozMatchesSelector(#{selector})`
|
326
|
-
end
|
327
|
-
elsif Browser.supports? 'Element.matches (Chrome)'
|
328
|
-
def matches?(selector)
|
329
|
-
`#@native.webkitMatchesSelector(#{selector})`
|
330
|
-
end
|
331
|
-
elsif Browser.loaded? 'Sizzle'
|
332
|
-
def matches?(selector)
|
333
|
-
`Sizzle.matchesSelector(#@native, #{selector})`
|
334
|
-
end
|
335
|
-
else
|
336
|
-
def matches?(selector)
|
337
|
-
raise NotImplementedError, 'selector matching unsupported'
|
338
|
-
end
|
438
|
+
def width=(value)
|
439
|
+
size.width = value
|
339
440
|
end
|
340
441
|
|
341
|
-
#
|
442
|
+
# @!attribute [r] window
|
443
|
+
# @return [Window] the window for the element
|
342
444
|
def window
|
343
445
|
document.window
|
344
446
|
end
|
345
447
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
class Attributes
|
351
|
-
include Enumerable
|
352
|
-
|
353
|
-
attr_reader :namespace
|
354
|
-
|
355
|
-
def initialize(element, options)
|
356
|
-
@element = element
|
357
|
-
@namespace = options[:namespace]
|
358
|
-
end
|
359
|
-
|
360
|
-
def each(&block)
|
361
|
-
return enum_for :each unless block_given?
|
362
|
-
|
363
|
-
@element.attribute_nodes.each {|attr|
|
364
|
-
yield attr.name, attr.value
|
365
|
-
}
|
366
|
-
|
367
|
-
self
|
368
|
-
end
|
369
|
-
|
370
|
-
def [](name)
|
371
|
-
@element.get_attribute(name, namespace: @namespace)
|
448
|
+
if Browser.supports?('Query.xpath') || Browser.loaded?('wicked-good-xpath')
|
449
|
+
if Browser.loaded? 'wicked-good-xpath'
|
450
|
+
`wgxpath.install()`
|
372
451
|
end
|
373
452
|
|
374
|
-
def
|
375
|
-
|
453
|
+
def xpath(path)
|
454
|
+
NodeSet[Native::Array.new(
|
455
|
+
`(#@native.ownerDocument || #@native).evaluate(path,
|
456
|
+
#@native, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)`,
|
457
|
+
get: :snapshotItem,
|
458
|
+
length: :snapshotLength)]
|
459
|
+
rescue
|
460
|
+
NodeSet[]
|
376
461
|
end
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
462
|
+
else
|
463
|
+
# Query for children matching the given XPath.
|
464
|
+
#
|
465
|
+
# @param path [String] the XPath
|
466
|
+
#
|
467
|
+
# @return [NodeSet]
|
468
|
+
def xpath(path)
|
469
|
+
raise NotImplementedError, 'query by XPath unsupported'
|
384
470
|
end
|
385
471
|
end
|
386
472
|
end
|