webkit_remote 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -2
- data/Gemfile +1 -0
- data/Gemfile.lock +10 -1
- data/README.md +36 -1
- data/VERSION +1 -1
- data/lib/webkit_remote.rb +2 -0
- data/lib/webkit_remote/client/console.rb +131 -0
- data/lib/webkit_remote/client/console_events.rb +24 -95
- data/lib/webkit_remote/client/dom.rb +297 -0
- data/lib/webkit_remote/client/dom_events.rb +18 -0
- data/lib/webkit_remote/client/network_events.rb +2 -2
- data/lib/webkit_remote/client/runtime.rb +66 -47
- data/lib/webkit_remote/process.rb +124 -6
- data/lib/webkit_remote/top_level.rb +5 -0
- data/test/fixtures/html/console.html +4 -0
- data/test/fixtures/html/dom.html +23 -0
- data/test/helper.rb +1 -0
- data/test/webkit_remote/browser_test.rb +1 -1
- data/test/webkit_remote/client/console_test.rb +63 -6
- data/test/webkit_remote/client/dom_test.rb +149 -0
- data/test/webkit_remote/client/{remote_object_group_test.rb → js_object_group_test.rb} +1 -1
- data/test/webkit_remote/client/{remote_object_test.rb → js_object_test.rb} +28 -21
- data/test/webkit_remote/client/runtime_test.rb +6 -6
- data/test/webkit_remote/client_test.rb +1 -1
- data/test/webkit_remote/process_test.rb +82 -30
- data/test/webkit_remote/rpc_test.rb +1 -1
- data/test/webkit_remote_test.rb +2 -2
- data/webkit_remote.gemspec +11 -4
- metadata +25 -5
@@ -0,0 +1,297 @@
|
|
1
|
+
module WebkitRemote
|
2
|
+
|
3
|
+
class Client
|
4
|
+
|
5
|
+
# API for the DOM domain.
|
6
|
+
module Dom
|
7
|
+
# @return [WebkitRemote::Client::DomNode] the root DOM node
|
8
|
+
def dom_root
|
9
|
+
@dom_root ||= dom_root!
|
10
|
+
end
|
11
|
+
|
12
|
+
# Obtains the root DOM node, bypassing the cache.
|
13
|
+
#
|
14
|
+
# @return [WebkitRemote::Client::DomNode] the root DOM node
|
15
|
+
def dom_root!
|
16
|
+
result = @rpc.call 'DOM.getDocument'
|
17
|
+
@dom_root = dom_update_node result['root']
|
18
|
+
end
|
19
|
+
|
20
|
+
# Removes all the cached DOM information.
|
21
|
+
#
|
22
|
+
# @return [WebkitRemote::Client] self
|
23
|
+
def clear_dom
|
24
|
+
@dom_root = nil
|
25
|
+
@dom_nodes.clear
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Looks up cached information about a DOM node.
|
30
|
+
#
|
31
|
+
# @private Use WebkitRemote::Client::Dom#querySelector or the other public
|
32
|
+
# APIs instead of calling this directly
|
33
|
+
#
|
34
|
+
# @param [String] remote_id value of the nodeId attribute in the JSON
|
35
|
+
# returned by a Webkit remote debugging server
|
36
|
+
# @return [WebkitRemote::Client::DomNode] cached information about the given
|
37
|
+
# DOM node
|
38
|
+
def dom_node(remote_id)
|
39
|
+
@dom_nodes[remote_id] ||= WebkitRemote::Client::DomNode.new remote_id, self
|
40
|
+
end
|
41
|
+
|
42
|
+
# @private Called by the Client constructor to set up Dom data.
|
43
|
+
def initialize_dom
|
44
|
+
@dom_nodes = {}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Updates cached information about a DOM node.
|
48
|
+
#
|
49
|
+
# @param [Hash<String, Object>] raw_node a Node data structure in the DOM
|
50
|
+
# domain, as returned by a raw JSON RPC call to a Webkit remote debugging
|
51
|
+
# server
|
52
|
+
# @return [WebkitRemote::Client::DomNode] the updated cached information
|
53
|
+
def dom_update_node(raw_node)
|
54
|
+
remote_id = raw_node['nodeId']
|
55
|
+
dom_node(remote_id).update_all raw_node
|
56
|
+
end
|
57
|
+
end # module WebkitRemote::Client::Dom
|
58
|
+
|
59
|
+
initializer :initialize_dom
|
60
|
+
clearer :clear_dom
|
61
|
+
include WebkitRemote::Client::Dom
|
62
|
+
|
63
|
+
# Cached information about a DOM node.
|
64
|
+
class DomNode
|
65
|
+
# @return [Array<WebkitRemote::Client::DomNode>] children nodes
|
66
|
+
attr_reader :children
|
67
|
+
|
68
|
+
# @return [String] the node's local name
|
69
|
+
attr_reader :local_name
|
70
|
+
# @return [String] the node's name
|
71
|
+
attr_reader :name
|
72
|
+
# @return [String] the node's value
|
73
|
+
attr_reader :value
|
74
|
+
# @return [Symbol] the DOM node type (such as :element, :text, :attribute)
|
75
|
+
attr_reader :node_type
|
76
|
+
|
77
|
+
# @return [String] name, for attribute nodes
|
78
|
+
attr_reader :attr_name
|
79
|
+
# @return [String] value, for attribute nodes
|
80
|
+
attr_reader :attr_value
|
81
|
+
|
82
|
+
# @return [String] internal subset, for doctype nodes
|
83
|
+
attr_reader :internal_subset
|
84
|
+
# @return [String] public ID, for doctype nodes
|
85
|
+
attr_reader :public_id
|
86
|
+
# @return [String] system ID, for doctype nodes
|
87
|
+
attr_reader :system_id
|
88
|
+
|
89
|
+
# @return [WebkitRemote::Client::DomNode] content document, for frameowner
|
90
|
+
# nodes
|
91
|
+
# @return [String] the document URL, for document and frameowner nodes
|
92
|
+
attr_reader :document_url
|
93
|
+
# @return [String] the XML version, for document nodes
|
94
|
+
attr_reader :xml_version
|
95
|
+
|
96
|
+
# @return [Hash<String, Object>] the node's attributes
|
97
|
+
def attributes
|
98
|
+
@attributes ||= attributes!
|
99
|
+
end
|
100
|
+
|
101
|
+
# Retrieves this node's attributes, bypassing its cache.
|
102
|
+
#
|
103
|
+
# @return [Hash<String, Object>] the node's attributes
|
104
|
+
def attributes!
|
105
|
+
result = @client.rpc.call 'DOM.getAttributes', nodeId: @remote_id
|
106
|
+
@attributes = Hash[result['attributes'].each_slice(2).to_a]
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [WebkitRemote::Client::JsObject] this node's JavaScript object
|
110
|
+
def js_object
|
111
|
+
@js_object ||= js_object!
|
112
|
+
end
|
113
|
+
|
114
|
+
# Retrieves this node's JavaScript object, bypassing the node's cache.
|
115
|
+
#
|
116
|
+
# @param [String] group the name of an object group (think memory pools); the
|
117
|
+
# objects in a group can be released together by one call to
|
118
|
+
# WebkitRemote::Client::JsObjectGroup#release
|
119
|
+
# @return [WebkitRemote::Client::JsObject] this node's JavaScript object
|
120
|
+
def js_object!(group = nil)
|
121
|
+
group ||= @client.object_group_auto_name
|
122
|
+
result = @client.rpc.call 'DOM.resolveNode', nodeId: @remote_id,
|
123
|
+
groupName: group
|
124
|
+
WebkitRemote::Client::JsObject.for result['object'], @client, group
|
125
|
+
end
|
126
|
+
|
127
|
+
# @return [String] HTML markup for the node and all its contents
|
128
|
+
def outer_html
|
129
|
+
@outer_html ||= outer_html!
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return [String] HTML markup for the node and all its contents
|
133
|
+
def outer_html!
|
134
|
+
result = @client.rpc.call 'DOM.getOuterHTML', nodeId: @remote_id
|
135
|
+
@outer_html = result['outerHTML']
|
136
|
+
end
|
137
|
+
|
138
|
+
# Retrieves the first descendant of this node that matches a CSS selector.
|
139
|
+
#
|
140
|
+
# @param [String] css_selector the CSS selector that must be matched by the
|
141
|
+
# returned node
|
142
|
+
# @return [WebkitRemote::Client::DomNode] DOM nodes in this node's subtree
|
143
|
+
# that match the given selector
|
144
|
+
def query_selector(css_selector)
|
145
|
+
result = @client.rpc.call 'DOM.querySelector', nodeId: @remote_id,
|
146
|
+
selector: css_selector
|
147
|
+
@client.dom_node result['nodeId']
|
148
|
+
end
|
149
|
+
|
150
|
+
# Retrieves all this node's descendants that match a CSS selector.
|
151
|
+
#
|
152
|
+
# @param [String] css_selector the CSS selector used to filter this node's
|
153
|
+
# subtree
|
154
|
+
# @return [Array<WebkitRemote::Client::DomNode>] DOM nodes in this node's
|
155
|
+
# subtree that match the given selector
|
156
|
+
def query_selector_all(css_selector)
|
157
|
+
result = @client.rpc.call 'DOM.querySelectorAll', nodeId: @remote_id,
|
158
|
+
selector: css_selector
|
159
|
+
result['nodeIds'].map { |remote_id| @client.dom_node remote_id }
|
160
|
+
end
|
161
|
+
|
162
|
+
# Deletes one of the node (element)'s attributes.
|
163
|
+
#
|
164
|
+
# @param [String] attr_name name of the attribute that will be deleted
|
165
|
+
# @return [WebkitRemote::Client::DomNode] self
|
166
|
+
def remove_attribute(attr_name)
|
167
|
+
@attributes.delete attr_name if @attributes
|
168
|
+
@client.rpc.call 'DOM.removeAttribute', nodeId: @remote_id, name: attr_name
|
169
|
+
self
|
170
|
+
end
|
171
|
+
|
172
|
+
# Removes this node from the document.
|
173
|
+
#
|
174
|
+
# @return [WebkitRemote::Client::DomNode] self
|
175
|
+
def remove
|
176
|
+
@client.rpc.call 'DOM.removeNode', nodeId: @remote_id
|
177
|
+
self
|
178
|
+
end
|
179
|
+
|
180
|
+
# Highlights this DOM node.
|
181
|
+
#
|
182
|
+
# @param [Hash<Symbol, Hash>] options colors to be used for highlighting
|
183
|
+
# @option options [Hash<Symbol, Number>] margin color used for highlighting
|
184
|
+
# the element's border
|
185
|
+
# @option options [Hash<Symbol, Number>] border color used for highlighting
|
186
|
+
# the element's border
|
187
|
+
# @option options [Hash<Symbol, Number>] padding color used for highlighting
|
188
|
+
# the element's padding
|
189
|
+
# @option options [Hash<Symbol, Number>] content color used for highlighting
|
190
|
+
# the element's content
|
191
|
+
# @option options [Boolean] tooltip if true, a tooltip containing node
|
192
|
+
# information is also shown
|
193
|
+
def highlight!(options)
|
194
|
+
config = {}
|
195
|
+
config[:marginColor] = options[:margin] if options[:margin]
|
196
|
+
config[:borderColor] = options[:border] if options[:border]
|
197
|
+
config[:paddingColor] = options[:padding] if options[:padding]
|
198
|
+
config[:contentColor] = options[:content] if options[:content]
|
199
|
+
config[:showInfo] = true if options[:tooltip]
|
200
|
+
@client.rpc.call 'DOM.highlightNode', nodeId: @remote_id,
|
201
|
+
highlightConfig: config
|
202
|
+
end
|
203
|
+
|
204
|
+
# @private Use WebkitRemote::Client::Dom#dom_node instead of calling this
|
205
|
+
def initialize(remote_id, client)
|
206
|
+
@remote_id = remote_id
|
207
|
+
@client = client
|
208
|
+
|
209
|
+
@attributes = nil
|
210
|
+
@attr_name = nil
|
211
|
+
@attr_value = nil
|
212
|
+
@children = nil
|
213
|
+
@content_document = nil
|
214
|
+
@document_url = nil
|
215
|
+
@internal_subset = nil
|
216
|
+
@js_object = nil
|
217
|
+
@local_name = nil
|
218
|
+
@name = nil
|
219
|
+
@node_type = nil
|
220
|
+
@outer_html = nil
|
221
|
+
@public_id = nil
|
222
|
+
@system_id = nil
|
223
|
+
@value = nil
|
224
|
+
@xml_version = nil
|
225
|
+
end
|
226
|
+
|
227
|
+
# Updates node state to reflect new data from the Webkit debugging server.
|
228
|
+
#
|
229
|
+
# @private Use WebkitRemote::Client::Dom#dom_node instead of calling this
|
230
|
+
#
|
231
|
+
# @param [Hash<String, Object>] raw_node a Node data structure in the DOM
|
232
|
+
# domain, as returned by a raw JSON RPC call to a Webkit remote debugging
|
233
|
+
# server
|
234
|
+
# @return [WebkitRemote::Client::DomNode] self
|
235
|
+
def update_all(raw_node)
|
236
|
+
if raw_node['attributes']
|
237
|
+
@attributes = Hash[raw_node['attributes'].each_slice(2).to_a]
|
238
|
+
end
|
239
|
+
if raw_node['children']
|
240
|
+
@children = raw_node['children'].map do |child_node|
|
241
|
+
@client.dom_update_node child_node
|
242
|
+
end
|
243
|
+
end
|
244
|
+
if raw_node['contentDocument']
|
245
|
+
@content_document = @client.dom_update_node raw_node['contentDocument']
|
246
|
+
end
|
247
|
+
@document_url = raw_node['documentURL'] if raw_node['documentURL']
|
248
|
+
@internal_subset = raw_node['internalSubset'] if raw_node['internalSubset']
|
249
|
+
@node_local_name = raw_node['localName'] if raw_node['localName']
|
250
|
+
@attr_name = raw_node['name'] if raw_node['name']
|
251
|
+
@name = raw_node['nodeName'] if raw_node['nodeName']
|
252
|
+
if raw_node['nodeType']
|
253
|
+
@node_type = NODE_TYPES[raw_node['nodeType'].to_i] || raw_node['nodeType']
|
254
|
+
end
|
255
|
+
@value = raw_node['nodeValue'] if raw_node['nodeValue']
|
256
|
+
@public_id = raw_node['publicId'] if raw_node['publicId']
|
257
|
+
@system_id = raw_node['systemId'] if raw_node['systemId']
|
258
|
+
@attr_value = raw_node['value'] if raw_node['value']
|
259
|
+
@xml_version = raw_node['xmlVersion'] if raw_node['xmlVersion']
|
260
|
+
|
261
|
+
self
|
262
|
+
end
|
263
|
+
|
264
|
+
# Maps numeric DOM types to their symbolic representation.
|
265
|
+
NODE_TYPES = {
|
266
|
+
1 => :element, 2 => :attribute, 3 => :text, 4 => :cdata_section,
|
267
|
+
5 => :entity_reference, 6 => :entity, 7 => :processing_instruction,
|
268
|
+
8 => :comment, 9 => :document, 10 => :document_type,
|
269
|
+
11 => :document_fragment, 12 => :notation
|
270
|
+
}.freeze
|
271
|
+
end # class WebkitRemote::Client::DomNode
|
272
|
+
|
273
|
+
class JsObject
|
274
|
+
# @return [WebkitRemote::Client::DomNode] the DOM node wrapped by this
|
275
|
+
# JavaScript object
|
276
|
+
def dom_node
|
277
|
+
@dom_node ||= dom_node!
|
278
|
+
end
|
279
|
+
|
280
|
+
# Fetches the wrapped DOM node, bypassing the object's cache.
|
281
|
+
#
|
282
|
+
# @return [WebkitRemote::Client::DomNode] the DOM domain object wrapped by
|
283
|
+
# this JavaScript object
|
284
|
+
def dom_node!
|
285
|
+
result = @client.rpc.call 'DOM.requestNode', objectId: @remote_id
|
286
|
+
@dom_node = if result['nodeId']
|
287
|
+
@client.dom_node result['nodeId']
|
288
|
+
else
|
289
|
+
nil
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end # class WebkitRemote::Client::JsObject
|
293
|
+
|
294
|
+
end # namespace WebkitRemote::Client
|
295
|
+
|
296
|
+
end # namespace WebkitRemote
|
297
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module WebkitRemote
|
2
|
+
|
3
|
+
class Event
|
4
|
+
|
5
|
+
# Emitted when the entire document has changed, and all DOM structure is lost.
|
6
|
+
class DomReset < WebkitRemote::Event
|
7
|
+
register 'Dom.documentUpdated'
|
8
|
+
|
9
|
+
# @private Use Event#for instead of calling this constructor directly.
|
10
|
+
def initialize(rpc_event, client)
|
11
|
+
super
|
12
|
+
client.clear_dom
|
13
|
+
end
|
14
|
+
end # class WebkitRemote::Event::DomReset
|
15
|
+
|
16
|
+
end # namespace WebkitRemote::Event
|
17
|
+
|
18
|
+
end # namepspace WebkitRemote
|
@@ -200,7 +200,7 @@ class NetworkRequest < WebkitRemote::Event
|
|
200
200
|
raw_data['redirectResponse'])
|
201
201
|
end
|
202
202
|
if raw_data['stackTrace']
|
203
|
-
@stack_trace = WebkitRemote::
|
203
|
+
@stack_trace = WebkitRemote::Client::ConsoleMessage.parse_stack_trace(
|
204
204
|
raw_initiator['stackTrace'])
|
205
205
|
else
|
206
206
|
@stack_trace = nil
|
@@ -568,7 +568,7 @@ class NetworkRequestInitiator
|
|
568
568
|
else
|
569
569
|
@line = nil
|
570
570
|
end
|
571
|
-
@stack_trace = WebkitRemote::
|
571
|
+
@stack_trace = WebkitRemote::Client::ConsoleMessage.parse_stack_trace(
|
572
572
|
raw_initiator['stackTrace'])
|
573
573
|
@type = (raw_initiator['type'] || 'other').to_sym
|
574
574
|
@url = raw_initiator['url']
|
@@ -10,15 +10,15 @@ module Runtime
|
|
10
10
|
# @param [Hash] opts tweaks
|
11
11
|
# @option opts [String, Symbol] group the name of an object group (think
|
12
12
|
# memory pools); the objects in a group can be released together by one
|
13
|
-
# call to WebkitRemote::Client::
|
14
|
-
# @return [WebkitRemote::Client::
|
13
|
+
# call to WebkitRemote::Client::JsObjectGroup#release
|
14
|
+
# @return [WebkitRemote::Client::JsObject, Boolean, Number, String] the
|
15
15
|
# result of evaluating the expression
|
16
16
|
def remote_eval(expression, opts = {})
|
17
|
-
group_name = opts[:group] ||
|
17
|
+
group_name = opts[:group] || object_group_auto_name
|
18
18
|
# NOTE: returnByValue is always set to false to avoid some extra complexity
|
19
19
|
result = @rpc.call 'Runtime.evaluate', expression: expression,
|
20
20
|
objectGroup: group_name
|
21
|
-
object = WebkitRemote::Client::
|
21
|
+
object = WebkitRemote::Client::JsObject.for result['result'], self,
|
22
22
|
group_name
|
23
23
|
if result['wasThrown']
|
24
24
|
# TODO(pwnall): some wrapper for exceptions?
|
@@ -35,9 +35,9 @@ module Runtime
|
|
35
35
|
# un-grouped objects created by Console#MessageReceived
|
36
36
|
# @param [Boolean] create if true, fetching a group that does not exist will
|
37
37
|
# create the group; this parameter should only be used internally
|
38
|
-
# @return [WebkitRemote::Client::
|
38
|
+
# @return [WebkitRemote::Client::JsObject, Boolean, Number, String, nil]
|
39
39
|
# a Ruby wrapper for the evaluation result; primitives get wrapped by
|
40
|
-
# standard Ruby classes, and objects get wrapped by
|
40
|
+
# standard Ruby classes, and objects get wrapped by JsObject
|
41
41
|
# instances
|
42
42
|
def object_group(group_name, create = false)
|
43
43
|
group_name = group_name.nil? ? nil : group_name.to_s
|
@@ -45,15 +45,24 @@ module Runtime
|
|
45
45
|
return group if group
|
46
46
|
if create
|
47
47
|
@runtime_groups[group_name] =
|
48
|
-
WebkitRemote::Client::
|
48
|
+
WebkitRemote::Client::JsObjectGroup.new(group_name, self)
|
49
49
|
else
|
50
50
|
nil
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
# Generates a temporary group name for JavaScript objects.
|
55
|
+
#
|
56
|
+
# This is useful when the API user does not
|
57
|
+
#
|
58
|
+
# @return [String] an automatically-generated JS object name
|
59
|
+
def object_group_auto_name
|
60
|
+
'_'
|
61
|
+
end
|
62
|
+
|
54
63
|
# Removes a group from the list of tracked groups.
|
55
64
|
#
|
56
|
-
# @private Use WebkitRemote::Client::
|
65
|
+
# @private Use WebkitRemote::Client::JsObjectGroup#release instead of
|
57
66
|
# calling this directly.
|
58
67
|
# @return [WebkitRemote::Client] self
|
59
68
|
def object_group_remove(group)
|
@@ -122,8 +131,8 @@ end # class WebkitRemote::Client::UndefinedClass
|
|
122
131
|
|
123
132
|
Undefined = UndefinedClass.new
|
124
133
|
|
125
|
-
# Mirrors a
|
126
|
-
class
|
134
|
+
# Mirrors a JsObject, defined in the Runtime domain.
|
135
|
+
class JsObject
|
127
136
|
# @return [String] the class name computed by WebKit for this object
|
128
137
|
attr_reader :js_class_name
|
129
138
|
|
@@ -154,18 +163,18 @@ class RemoteObject
|
|
154
163
|
# that owns the objects in this group
|
155
164
|
attr_reader :client
|
156
165
|
|
157
|
-
# @return [WebkitRemote::Client::
|
166
|
+
# @return [WebkitRemote::Client::JsObjectGroup] the group that contains
|
158
167
|
# this object; the object can be released by calling release_all on the
|
159
168
|
# group
|
160
169
|
attr_reader :group
|
161
170
|
|
162
171
|
# @return [String] identifies this object in the remote debugger
|
163
|
-
# @private Use the
|
172
|
+
# @private Use the JsObject methods instead of calling this directly.
|
164
173
|
attr_reader :remote_id
|
165
174
|
|
166
175
|
# Releases this remote object on the browser side.
|
167
176
|
#
|
168
|
-
# @return [Webkit::Client::
|
177
|
+
# @return [Webkit::Client::JsObject] self
|
169
178
|
def release
|
170
179
|
return if @released
|
171
180
|
@client.rpc.call 'Runtime.releaseObject', objectId: @remote_id
|
@@ -178,7 +187,7 @@ class RemoteObject
|
|
178
187
|
# If the object's properties have not been retrieved, this method retrieves
|
179
188
|
# them via a RPC call.
|
180
189
|
#
|
181
|
-
# @return [Hash<
|
190
|
+
# @return [Hash<String, Webkit::Client::JsProperty>] frozen Hash containg
|
182
191
|
# the object's properties
|
183
192
|
def properties
|
184
193
|
@properties || properties!
|
@@ -188,13 +197,13 @@ class RemoteObject
|
|
188
197
|
#
|
189
198
|
# This method always reloads the object's properties via a RPC call.
|
190
199
|
#
|
191
|
-
# @return [Hash<Symbol, Webkit::Client::
|
200
|
+
# @return [Hash<Symbol, Webkit::Client::JsProperty>] frozen Hash containg
|
192
201
|
# the object's properties
|
193
202
|
def properties!
|
194
203
|
result = @client.rpc.call 'Runtime.getProperties', objectId: @remote_id
|
195
204
|
@properties = Hash[
|
196
205
|
result['result'].map do |raw_property|
|
197
|
-
property = WebkitRemote::Client::
|
206
|
+
property = WebkitRemote::Client::JsProperty.new raw_property, self
|
198
207
|
[property.name, property]
|
199
208
|
end
|
200
209
|
].freeze
|
@@ -206,13 +215,13 @@ class RemoteObject
|
|
206
215
|
# evaluate to a function
|
207
216
|
# @param [Array<WebkitRemote::Client::Object, String, Number, Boolean, nil>]
|
208
217
|
# args the arguments passed to the function
|
209
|
-
# @return [WebkitRemote::Client::
|
218
|
+
# @return [WebkitRemote::Client::JsObject, Boolean, Number, String, nil]
|
210
219
|
# a Ruby wrapper for the given raw object; primitives get wrapped by
|
211
|
-
# standard Ruby classes, and objects get wrapped by
|
220
|
+
# standard Ruby classes, and objects get wrapped by JsObject
|
212
221
|
# instances
|
213
222
|
def bound_call(function_expression, *args)
|
214
223
|
call_args = args.map do |arg|
|
215
|
-
if arg.kind_of? WebkitRemote::Client::
|
224
|
+
if arg.kind_of? WebkitRemote::Client::JsObject
|
216
225
|
{ objectId: arg.remote_id }
|
217
226
|
else
|
218
227
|
{ value: arg }
|
@@ -221,7 +230,7 @@ class RemoteObject
|
|
221
230
|
result = @client.rpc.call 'Runtime.callFunctionOn', objectId: @remote_id,
|
222
231
|
functionDeclaration: function_expression, arguments: call_args,
|
223
232
|
returnByValue: false
|
224
|
-
object = WebkitRemote::Client::
|
233
|
+
object = WebkitRemote::Client::JsObject.for result['result'], @client,
|
225
234
|
@group.name
|
226
235
|
if result['wasThrown']
|
227
236
|
# TODO(pwnall): some wrapper for exceptions?
|
@@ -236,22 +245,22 @@ class RemoteObject
|
|
236
245
|
# @private Use WebkitRemote::Client::Runtime#remote_eval instead of calling
|
237
246
|
# this directly.
|
238
247
|
#
|
239
|
-
# @param [Hash<String, Object>] raw_object a
|
248
|
+
# @param [Hash<String, Object>] raw_object a JsObject instance, according
|
240
249
|
# to the Webkit remote debugging protocol; this is the return value of a
|
241
250
|
# 'Runtime.evaluate' RPC call
|
242
251
|
# @param [WebkitRemote::Client::Runtime] client remote debugging client for
|
243
252
|
# the browser tab that owns this object
|
244
253
|
# @param [String] group_name name of the object group that will hold this
|
245
254
|
# object; object groups work like memory pools
|
246
|
-
# @return [WebkitRemote::Client::
|
255
|
+
# @return [WebkitRemote::Client::JsObject, Boolean, Number, String] a
|
247
256
|
# Ruby wrapper for the given raw object; primitives get wrapped by
|
248
|
-
# standard Ruby classes, and objects get wrapped by
|
257
|
+
# standard Ruby classes, and objects get wrapped by JsObject
|
249
258
|
# instances
|
250
259
|
def self.for(raw_object, client, group_name)
|
251
260
|
if remote_id = raw_object['objectId']
|
252
261
|
group = client.object_group group_name, true
|
253
262
|
return group.get(remote_id) ||
|
254
|
-
WebkitRemote::Client::
|
263
|
+
WebkitRemote::Client::JsObject.new(raw_object, group)
|
255
264
|
else
|
256
265
|
# primitive types
|
257
266
|
case raw_object['type'] ? raw_object['type'].to_sym : nil
|
@@ -272,7 +281,7 @@ class RemoteObject
|
|
272
281
|
|
273
282
|
# Wraps a remote JavaScript object
|
274
283
|
#
|
275
|
-
# @private
|
284
|
+
# @private JsObject#for should be used instead of this, as it handles
|
276
285
|
# some edge cases
|
277
286
|
def initialize(raw_object, group)
|
278
287
|
@group = group
|
@@ -290,21 +299,22 @@ class RemoteObject
|
|
290
299
|
@js_subtype = nil
|
291
300
|
end
|
292
301
|
@value = raw_object['value']
|
302
|
+
@dom_node = nil
|
293
303
|
|
294
304
|
group.add self
|
295
305
|
end
|
296
306
|
|
297
307
|
# Informs this object that it was released as part of a group release.
|
298
308
|
#
|
299
|
-
# @private Called by
|
309
|
+
# @private Called by JsObjectGroup#release_all.
|
300
310
|
def released!
|
301
311
|
@released = true
|
302
312
|
@group = nil
|
303
313
|
end
|
304
|
-
end # class WebkitRemote::Client::
|
314
|
+
end # class WebkitRemote::Client::JsObject
|
305
315
|
|
306
316
|
# Tracks the remote objects in a group (think memory pool).
|
307
|
-
class
|
317
|
+
class JsObjectGroup
|
308
318
|
# @return [String] the name of the group of remote objects
|
309
319
|
attr_reader :name
|
310
320
|
|
@@ -318,7 +328,7 @@ class RemoteObjectGroup
|
|
318
328
|
|
319
329
|
# Releases all the remote objects in this group.
|
320
330
|
#
|
321
|
-
# @return [Webkit::Client::
|
331
|
+
# @return [Webkit::Client::JsObjectGroup] self
|
322
332
|
def release_all
|
323
333
|
return if @objects.empty?
|
324
334
|
|
@@ -368,9 +378,9 @@ class RemoteObjectGroup
|
|
368
378
|
# @private Use WebkitRemote::Client::Runtime#remote_eval instead of calling
|
369
379
|
# this directly.
|
370
380
|
#
|
371
|
-
# @param [WebkitRemote::Client::
|
381
|
+
# @param [WebkitRemote::Client::JsObject] object the object to be added
|
372
382
|
# to this group
|
373
|
-
# @return [WebkitRemote::Client::
|
383
|
+
# @return [WebkitRemote::Client::JsObjectGroup] self
|
374
384
|
def add(object)
|
375
385
|
if @released
|
376
386
|
raise RuntimeError, 'Remote object group already released'
|
@@ -381,12 +391,12 @@ class RemoteObjectGroup
|
|
381
391
|
|
382
392
|
# Removes a remote object that was individually released.
|
383
393
|
#
|
384
|
-
# @private Use WebkitRemote::Client::
|
394
|
+
# @private Use WebkitRemote::Client::JsObject#release instead of calling
|
385
395
|
# this directly
|
386
396
|
#
|
387
|
-
# @param [WebkitRemote::Client::
|
397
|
+
# @param [WebkitRemote::Client::JsObject] object the object that will be
|
388
398
|
# removed from the group
|
389
|
-
# @return [WebkitRemote::Client::
|
399
|
+
# @return [WebkitRemote::Client::JsObjectGroup] self
|
390
400
|
def remove(object)
|
391
401
|
@objects.delete object.remote_id
|
392
402
|
if @objects.empty?
|
@@ -401,21 +411,21 @@ class RemoteObjectGroup
|
|
401
411
|
# This helps avoid creating multiple wrappers for the same object.
|
402
412
|
#
|
403
413
|
# @param [String] remote_id the id to look for
|
404
|
-
# @return [WebkitRemote::Client::
|
414
|
+
# @return [WebkitRemote::Client::JsObject, nil] nil if there is no object
|
405
415
|
# whose remote_id matches the method's parameter
|
406
416
|
def get(remote_id)
|
407
417
|
@objects.fetch remote_id, nil
|
408
418
|
end
|
409
|
-
end # class WebkitRemote::Client::
|
419
|
+
end # class WebkitRemote::Client::JsObjectGroup
|
410
420
|
|
411
421
|
# A property of a remote JavaScript object.
|
412
|
-
class
|
413
|
-
# @return [
|
422
|
+
class JsProperty
|
423
|
+
# @return [String] the property's name
|
414
424
|
attr_reader :name
|
415
425
|
|
416
|
-
# @return [WebkitRemote::Client::
|
426
|
+
# @return [WebkitRemote::Client::JsObject, Boolean, Number, String, nil]
|
417
427
|
# a Ruby wrapper for the property's value; primitives get wrapped by
|
418
|
-
# standard Ruby classes, and objects get wrapped by
|
428
|
+
# standard Ruby classes, and objects get wrapped by JsObject
|
419
429
|
# instances
|
420
430
|
attr_reader :value
|
421
431
|
|
@@ -431,14 +441,14 @@ class RemoteProperty
|
|
431
441
|
attr_reader :writable
|
432
442
|
alias_method :writable?, :writable
|
433
443
|
|
434
|
-
# @return [WebkitRemote::
|
444
|
+
# @return [WebkitRemote::JsObject] the object that this property belongs
|
435
445
|
# to
|
436
446
|
attr_reader :owner
|
437
447
|
|
438
448
|
# @param [Hash<String, Object>] raw_property a PropertyDescriptor instance,
|
439
449
|
# according to the Webkit remote debugging protocol; this is an item in
|
440
450
|
# the array returned by the 'Runtime.getProperties' RPC call
|
441
|
-
# @param [WebkitRemote::Client::
|
451
|
+
# @param [WebkitRemote::Client::JsObject] owner the object that this
|
442
452
|
# property belongs to
|
443
453
|
def initialize(raw_property, owner)
|
444
454
|
# NOTE: these are only used at construction time
|
@@ -446,18 +456,27 @@ class RemoteProperty
|
|
446
456
|
group_name = owner.group.name
|
447
457
|
|
448
458
|
@owner = owner
|
449
|
-
@name = raw_property['name']
|
459
|
+
@name = raw_property['name']
|
450
460
|
@configurable = !!raw_property['configurable']
|
451
461
|
@enumerable = !!raw_property['enumerable']
|
452
462
|
@writable = !!raw_property['writable']
|
453
|
-
@js_getter = raw_property['get'] && WebkitRemote::Client::
|
463
|
+
@js_getter = raw_property['get'] && WebkitRemote::Client::JsObject.for(
|
454
464
|
raw_property['get'], client, group_name)
|
455
|
-
@js_setter = raw_property['set'] && WebkitRemote::Client::
|
465
|
+
@js_setter = raw_property['set'] && WebkitRemote::Client::JsObject.for(
|
456
466
|
raw_property['set'], client, group_name)
|
457
|
-
@value = raw_property['value'] && WebkitRemote::Client::
|
467
|
+
@value = raw_property['value'] && WebkitRemote::Client::JsObject.for(
|
458
468
|
raw_property['value'], client, group_name)
|
459
469
|
end
|
460
|
-
|
470
|
+
|
471
|
+
# Debugging output.
|
472
|
+
def inspect
|
473
|
+
result = self.to_s
|
474
|
+
result[-1, 0] =
|
475
|
+
" name=#{@name.inspect} configurable=#{@configurable} " +
|
476
|
+
"enumerable=#{@enumerable} writable=#{@writable}"
|
477
|
+
result
|
478
|
+
end
|
479
|
+
end # class WebkitRemote::Client::JsProperty
|
461
480
|
|
462
481
|
end # namespace WebkitRemote::Client
|
463
482
|
|