opal-browser 0.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/opal/browser/dom.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'browser/dom/event'
|
2
|
+
require 'browser/dom/node_set'
|
3
|
+
require 'browser/dom/node'
|
4
|
+
require 'browser/dom/attribute'
|
5
|
+
require 'browser/dom/character_data'
|
6
|
+
require 'browser/dom/text'
|
7
|
+
require 'browser/dom/cdata'
|
8
|
+
require 'browser/dom/comment'
|
9
|
+
require 'browser/dom/element'
|
10
|
+
require 'browser/dom/document'
|
11
|
+
require 'browser/dom/document_fragment'
|
12
|
+
require 'browser/dom/builder'
|
13
|
+
require 'browser/dom/mutation_observer'
|
14
|
+
|
15
|
+
require 'browser/dom/compatibility'
|
16
|
+
|
17
|
+
module Kernel
|
18
|
+
# Parse an XML string into a DOM usable {Browser::DOM::Document}
|
19
|
+
#
|
20
|
+
# @param what [String] the string to parse
|
21
|
+
# @return [Browser::DOM::Document] the document
|
22
|
+
def XML(what)
|
23
|
+
%x{
|
24
|
+
var doc;
|
25
|
+
|
26
|
+
if (window.DOMParser) {
|
27
|
+
doc = new DOMParser().parseFromString(what, 'text/xml');
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
doc = new ActiveXObject('Microsoft.XMLDOM');
|
31
|
+
doc.async = 'false';
|
32
|
+
doc.loadXML(what);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
DOM(`doc`)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Wrap a native element or create a DOM tree using the {Paggio::HTML} DSL.
|
40
|
+
#
|
41
|
+
# @return [Browser::DOM::Node]
|
42
|
+
def DOM(*args, &block)
|
43
|
+
if block
|
44
|
+
document = args.shift || $document
|
45
|
+
element = args.shift
|
46
|
+
|
47
|
+
roots = Browser::DOM::Builder.new(document, element, &block).to_a
|
48
|
+
|
49
|
+
if roots.length == 1
|
50
|
+
roots.first
|
51
|
+
else
|
52
|
+
Browser::DOM::NodeSet.new(document, roots)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
what = args.shift
|
56
|
+
document = args.shift || $document
|
57
|
+
|
58
|
+
if native?(what)
|
59
|
+
Browser::DOM::Node.new(what)
|
60
|
+
elsif Browser::DOM::Node === what
|
61
|
+
what
|
62
|
+
elsif String === what
|
63
|
+
%x{
|
64
|
+
var doc = #{Native.try_convert(document)}.createElement('div');
|
65
|
+
doc.innerHTML = what;
|
66
|
+
|
67
|
+
return #{DOM(`doc.childNodes.length == 1 ? doc.childNodes[0] : doc`)};
|
68
|
+
}
|
69
|
+
else
|
70
|
+
raise ArgumentError, "argument not DOM convertible"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module Browser
|
77
|
+
|
78
|
+
class Window
|
79
|
+
include DOM::Event::Target
|
80
|
+
|
81
|
+
target {|value|
|
82
|
+
$window if `#{value} == window`
|
83
|
+
}
|
84
|
+
|
85
|
+
# Get the {DOM::Document} for this window.
|
86
|
+
#
|
87
|
+
# @return [DOM::Document]
|
88
|
+
def document
|
89
|
+
DOM(`#@native.document`)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
$document = $window.document
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Temporary fix for a bug in String#scan
|
2
|
+
module Paggio::Utils
|
3
|
+
def self.heredoc(string)
|
4
|
+
string
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Paggio::HTML::Element < BasicObject
|
9
|
+
def on(*args, &block)
|
10
|
+
(@on ||= []) << [args, block]
|
11
|
+
end
|
12
|
+
|
13
|
+
def style(*args, &block)
|
14
|
+
@style = [args, block]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Browser; module DOM
|
19
|
+
|
20
|
+
class Builder
|
21
|
+
def self.to_h
|
22
|
+
@builders ||= {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.for(klass, &block)
|
26
|
+
if block
|
27
|
+
to_h[klass] = block
|
28
|
+
else
|
29
|
+
to_h[klass]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.build(builder, item)
|
34
|
+
to_h.each {|klass, block|
|
35
|
+
if klass === item
|
36
|
+
break block.call(builder, item)
|
37
|
+
end
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :document, :element
|
42
|
+
|
43
|
+
def initialize(document, element = nil, &block)
|
44
|
+
@document = document
|
45
|
+
@element = element
|
46
|
+
@builder = Paggio::HTML.new(&block)
|
47
|
+
@roots = @builder.each.map { |e| Builder.build(self, e) }
|
48
|
+
|
49
|
+
if @element
|
50
|
+
@roots.each {|root|
|
51
|
+
@element << root
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_a
|
57
|
+
@roots
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Builder.for String do |b, item|
|
62
|
+
b.document.create_text(item)
|
63
|
+
end
|
64
|
+
|
65
|
+
Builder.for Paggio::HTML::Element do |b, item|
|
66
|
+
dom = b.document.create_element(`item.name`)
|
67
|
+
|
68
|
+
if Hash === `item.attributes`
|
69
|
+
dom.attributes.merge!(`item.attributes`)
|
70
|
+
end
|
71
|
+
|
72
|
+
`item.class_names`.each {|value|
|
73
|
+
dom.add_class value
|
74
|
+
}
|
75
|
+
|
76
|
+
if on = `item.on || nil`
|
77
|
+
on.each {|args, block|
|
78
|
+
dom.on(*args, &block)
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
if style = `item.style || nil`
|
83
|
+
dom.style(*style[0], &style[1])
|
84
|
+
end
|
85
|
+
|
86
|
+
if inner = `item.inner_html || nil`
|
87
|
+
dom.inner_html = inner
|
88
|
+
else
|
89
|
+
item.each {|child|
|
90
|
+
dom << Builder.build(b, child)
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
dom
|
95
|
+
end
|
96
|
+
|
97
|
+
end; end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Browser; module DOM
|
2
|
+
|
3
|
+
class CharacterData < Node
|
4
|
+
def data
|
5
|
+
`#@native.data`
|
6
|
+
end
|
7
|
+
|
8
|
+
def append(string)
|
9
|
+
`#@native.appendData(string)`
|
10
|
+
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def insert(string, offset = 0)
|
15
|
+
`#@native.insertData(offset, string)`
|
16
|
+
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete(count, offset = 0)
|
21
|
+
`#@native.deleteData(offset, count)`
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def replace(string, offset = 0, count = `#@native.length`)
|
27
|
+
`#@native.replaceData(offset, count, string)`
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def substring(count, offset = 0)
|
33
|
+
`#@native.substringData(offset, count)`
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end; end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'browser/compatibility/dom/document/window'
|
2
|
+
|
3
|
+
require 'browser/compatibility/dom/mutation_observer'
|
4
|
+
|
5
|
+
require 'browser/compatibility/dom/element/matches'
|
6
|
+
require 'browser/compatibility/dom/element/css'
|
7
|
+
require 'browser/compatibility/dom/element/offset'
|
8
|
+
require 'browser/compatibility/dom/element/style'
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'browser/location'
|
2
|
+
|
3
|
+
module Browser; module DOM
|
4
|
+
|
5
|
+
class Document < Element
|
6
|
+
def create_element(name, options = {})
|
7
|
+
if ns = options[:namespace]
|
8
|
+
DOM(`#@native.createElementNS(#{ns}, #{name})`)
|
9
|
+
else
|
10
|
+
DOM(`#@native.createElement(name)`)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def window
|
15
|
+
Window.new(`#@native.defaultView`)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_text(content)
|
19
|
+
DOM(`#@native.createTextNode(#{content})`)
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](what)
|
23
|
+
%x{
|
24
|
+
var result = #@native.getElementById(what);
|
25
|
+
|
26
|
+
if (result) {
|
27
|
+
return #{DOM(`result`)};
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
xpath(what).first || css(what).first
|
32
|
+
end
|
33
|
+
|
34
|
+
alias at []
|
35
|
+
|
36
|
+
def cookies
|
37
|
+
Cookies.new(@native) if defined?(`#@native.cookie`)
|
38
|
+
end
|
39
|
+
|
40
|
+
def document
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
"#<DOM::Document: #{children.inspect}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def location
|
49
|
+
Location.new(`#@native.location`) if `#@native.location`
|
50
|
+
end
|
51
|
+
|
52
|
+
def title
|
53
|
+
`#@native.title`
|
54
|
+
end
|
55
|
+
|
56
|
+
def title=(value)
|
57
|
+
`#@native.title = value`
|
58
|
+
end
|
59
|
+
|
60
|
+
def root
|
61
|
+
DOM(`#@native.documentElement`)
|
62
|
+
end
|
63
|
+
|
64
|
+
def head
|
65
|
+
DOM(`#@native.getElementsByTagName("head")[0]`)
|
66
|
+
end
|
67
|
+
|
68
|
+
def body
|
69
|
+
DOM(`#@native.body`)
|
70
|
+
end
|
71
|
+
|
72
|
+
def style_sheets
|
73
|
+
Native::Array.new(`#@native.styleSheets`) {|e|
|
74
|
+
CSS::StyleSheet.new(e)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def root=(element)
|
79
|
+
`#@native.documentElement = #{Native.convert(element)}`
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end; end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
require 'browser/dom/element/position'
|
2
|
+
require 'browser/dom/element/offset'
|
3
|
+
require 'browser/dom/element/scroll'
|
4
|
+
|
5
|
+
require 'browser/dom/element/input'
|
6
|
+
|
7
|
+
module Browser; module DOM
|
8
|
+
|
9
|
+
class Element < Node
|
10
|
+
def self.create(*args)
|
11
|
+
$document.create_element(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.new(node)
|
15
|
+
if self == Element
|
16
|
+
case `node.nodeName`.downcase
|
17
|
+
when :input
|
18
|
+
Input.new(node)
|
19
|
+
|
20
|
+
else super
|
21
|
+
end
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
include Event::Target
|
28
|
+
|
29
|
+
target {|value|
|
30
|
+
DOM(value) rescue nil
|
31
|
+
}
|
32
|
+
|
33
|
+
alias_native :id
|
34
|
+
|
35
|
+
def add_class(*names)
|
36
|
+
`#@native.className = #{(class_names + names).uniq.join ' '}`
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove_class(*names)
|
42
|
+
`#@native.className = #{(class_names - names).join ' '}`
|
43
|
+
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_native :class_name, :className
|
48
|
+
|
49
|
+
def class_names
|
50
|
+
`#@native.className`.split(/\s+/).reject(&:empty?)
|
51
|
+
end
|
52
|
+
|
53
|
+
alias attribute attr
|
54
|
+
|
55
|
+
def attribute_nodes
|
56
|
+
Native::Array.new(`#@native.attributes`, get: :item) { |e| DOM(e) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def attributes(options = {})
|
60
|
+
Attributes.new(self, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
def get(name, options = {})
|
64
|
+
if namespace = options[:namespace]
|
65
|
+
`#@native.getAttributeNS(#{namespace.to_s}, #{name.to_s}) || nil`
|
66
|
+
else
|
67
|
+
`#@native.getAttribute(#{name.to_s}) || nil`
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def set(name, value, options = {})
|
72
|
+
if namespace = options[:namespace]
|
73
|
+
`#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
|
74
|
+
else
|
75
|
+
`#@native.setAttribute(#{name.to_s}, #{value.to_s})`
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
alias [] get
|
80
|
+
alias []= set
|
81
|
+
|
82
|
+
alias attr get
|
83
|
+
alias attribute get
|
84
|
+
|
85
|
+
alias get_attribute get
|
86
|
+
alias set_attribute set
|
87
|
+
|
88
|
+
def key?(name)
|
89
|
+
!!self[name]
|
90
|
+
end
|
91
|
+
|
92
|
+
def keys
|
93
|
+
attributes_nodesmap(&:name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def values
|
97
|
+
attribute_nodes.map(&:value)
|
98
|
+
end
|
99
|
+
|
100
|
+
def remove_attribute(name)
|
101
|
+
`#@native.removeAttribute(name)`
|
102
|
+
end
|
103
|
+
|
104
|
+
def size(*inc)
|
105
|
+
Size.new(`#@native.offsetWidth`, `#@native.offsetHeight`)
|
106
|
+
end
|
107
|
+
|
108
|
+
def position
|
109
|
+
Position.new(self)
|
110
|
+
end
|
111
|
+
|
112
|
+
def offset(*values)
|
113
|
+
off = Offset.new(self)
|
114
|
+
|
115
|
+
unless values.empty?
|
116
|
+
off.set(*values)
|
117
|
+
end
|
118
|
+
|
119
|
+
off
|
120
|
+
end
|
121
|
+
|
122
|
+
def offset=(value)
|
123
|
+
offset.set(*value)
|
124
|
+
end
|
125
|
+
|
126
|
+
def scroll
|
127
|
+
Scroll.new(self)
|
128
|
+
end
|
129
|
+
|
130
|
+
def inner_dom(&block)
|
131
|
+
# FIXME: when block passing is fixed
|
132
|
+
doc = document
|
133
|
+
clear; Builder.new(doc, self, &block)
|
134
|
+
|
135
|
+
self
|
136
|
+
end
|
137
|
+
|
138
|
+
def inner_dom=(node)
|
139
|
+
clear; self << node
|
140
|
+
end
|
141
|
+
|
142
|
+
def /(*paths)
|
143
|
+
paths.map { |path| xpath(path) }.flatten.uniq
|
144
|
+
end
|
145
|
+
|
146
|
+
def at(path)
|
147
|
+
xpath(path).first || css(path).first
|
148
|
+
end
|
149
|
+
|
150
|
+
def at_css(*rules)
|
151
|
+
rules.each {|rule|
|
152
|
+
found = css(rule).first
|
153
|
+
|
154
|
+
return found if found
|
155
|
+
}
|
156
|
+
|
157
|
+
nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def at_xpath(*paths)
|
161
|
+
paths.each {|path|
|
162
|
+
found = xpath(path).first
|
163
|
+
|
164
|
+
return found if found
|
165
|
+
}
|
166
|
+
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
|
170
|
+
def search(*selectors)
|
171
|
+
NodeSet.new document, selectors.map {|selector|
|
172
|
+
xpath(selector).to_a.concat(css(selector).to_a)
|
173
|
+
}.flatten.uniq
|
174
|
+
end
|
175
|
+
|
176
|
+
def css(path)
|
177
|
+
NodeSet.new(document, Native::Array.new(`#@native.querySelectorAll(path)`))
|
178
|
+
end
|
179
|
+
|
180
|
+
def xpath(path)
|
181
|
+
result = []
|
182
|
+
|
183
|
+
begin
|
184
|
+
%x{
|
185
|
+
var tmp = (#@native.ownerDocument || #@native).evaluate(
|
186
|
+
path, #@native, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
187
|
+
|
188
|
+
result = #{Native::Array.new(`tmp`, get: :snapshotItem, length: :snapshotLength)};
|
189
|
+
}
|
190
|
+
rescue; end
|
191
|
+
|
192
|
+
NodeSet.new(document, result)
|
193
|
+
end
|
194
|
+
|
195
|
+
def style(data = nil, &block)
|
196
|
+
style = CSS::Declaration.new(`#@native.style`)
|
197
|
+
|
198
|
+
return style unless data || block
|
199
|
+
|
200
|
+
if data.is_a?(String)
|
201
|
+
style.replace(data)
|
202
|
+
elsif data.is_a?(Enumerable)
|
203
|
+
style.assign(data)
|
204
|
+
end
|
205
|
+
|
206
|
+
if block
|
207
|
+
style.apply(&block)
|
208
|
+
end
|
209
|
+
|
210
|
+
self
|
211
|
+
end
|
212
|
+
|
213
|
+
def style!
|
214
|
+
CSS::Declaration.new(`#{window.to_n}.getComputedStyle(#@native, null)`)
|
215
|
+
end
|
216
|
+
|
217
|
+
def data(what)
|
218
|
+
unless defined?(`#@native.$data`)
|
219
|
+
`#@native.$data = {}`
|
220
|
+
end
|
221
|
+
|
222
|
+
if Hash === what
|
223
|
+
what.each {|name, value|
|
224
|
+
`#@native.$data[name] = value`
|
225
|
+
}
|
226
|
+
else
|
227
|
+
%x{
|
228
|
+
var value = #@native.$data[what];
|
229
|
+
|
230
|
+
if (value === undefined) {
|
231
|
+
return nil;
|
232
|
+
}
|
233
|
+
else {
|
234
|
+
return value;
|
235
|
+
}
|
236
|
+
}
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def matches?(selector)
|
241
|
+
`#@native.matches(#{selector})`
|
242
|
+
end
|
243
|
+
|
244
|
+
def window
|
245
|
+
document.window
|
246
|
+
end
|
247
|
+
|
248
|
+
def inspect
|
249
|
+
"#<DOM::Element: #{name}>"
|
250
|
+
end
|
251
|
+
|
252
|
+
class Attributes
|
253
|
+
include Enumerable
|
254
|
+
|
255
|
+
attr_reader :namespace
|
256
|
+
|
257
|
+
def initialize(element, options)
|
258
|
+
@element = element
|
259
|
+
@namespace = options[:namespace]
|
260
|
+
end
|
261
|
+
|
262
|
+
def each(&block)
|
263
|
+
return enum_for :each unless block_given?
|
264
|
+
|
265
|
+
@element.attribute_nodes.each {|attr|
|
266
|
+
yield attr.name, attr.value
|
267
|
+
}
|
268
|
+
|
269
|
+
self
|
270
|
+
end
|
271
|
+
|
272
|
+
def [](name)
|
273
|
+
@element.get_attribute(name, namespace: @namespace)
|
274
|
+
end
|
275
|
+
|
276
|
+
def []=(name, value)
|
277
|
+
@element.set_attribute(name, value, namespace: @namespace)
|
278
|
+
end
|
279
|
+
|
280
|
+
def merge!(hash)
|
281
|
+
hash.each {|name, value|
|
282
|
+
self[name] = value
|
283
|
+
}
|
284
|
+
|
285
|
+
self
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
end; end
|