Class: Puppeteer::ElementHandle
Defined Under Namespace
Classes: ElementNotFoundError, ElementNotVisibleError, Point, ScrollIntoViewError
Instance Attribute Summary
Attributes inherited from JSHandle
#context, #remote_object
Instance Method Summary
collapse
-
#as_element ⇒ Object
-
#async_press ⇒ Future
-
#async_Seval ⇒ Object
-
#async_SSeval ⇒ Object
`$$eval()` in JavaScript.
-
#async_type_text ⇒ Future
-
#click(delay: nil, button: nil, click_count: nil) ⇒ Object
-
#clickable_point ⇒ Object
-
#content_frame ⇒ Object
-
#focus ⇒ Object
-
#initialize(context:, client:, remote_object:, page:, frame_manager:) ⇒ ElementHandle
constructor
A new instance of ElementHandle.
-
#press(key, delay: nil) ⇒ Object
-
#S(selector) ⇒ Object
-
#scroll_into_view_if_needed ⇒ Object
-
#select(*values) ⇒ Array<String>
-
#Seval(selector, page_function, *args) ⇒ Object
-
#SS(selector) ⇒ Object
-
#SSeval(selector, page_function, *args) ⇒ Object
`$$eval()` in JavaScript.
-
#Sx(expression) ⇒ Array<ElementHandle>
-
#tap(&block) ⇒ Object
-
#type_text(text, delay: nil) ⇒ Object
-
#upload_file(*file_paths) ⇒ Object
Methods included from IfPresent
#if_present
Methods inherited from JSHandle
#async_evaluate, #async_evaluate_handle, create, #dispose, #disposed?, #evaluate, #evaluate_handle, #execution_context, #json_value, #properties
Constructor Details
#initialize(context:, client:, remote_object:, page:, frame_manager:) ⇒ ElementHandle
Returns a new instance of ElementHandle.
12
13
14
15
16
17
|
# File 'lib/puppeteer/element_handle.rb', line 12
def initialize(context:, client:, remote_object:, page:, frame_manager:)
super(context: context, client: client, remote_object: remote_object)
@page = page
@frame_manager = frame_manager
@disposed = false
end
|
Instance Method Details
#as_element ⇒ Object
19
20
21
|
# File 'lib/puppeteer/element_handle.rb', line 19
def as_element
self
end
|
#async_press ⇒ Future
264
265
266
|
# File 'lib/puppeteer/element_handle.rb', line 264
async def async_press(key, delay: nil)
press(key, delay: delay)
end
|
#async_Seval ⇒ Object
`$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
405
406
407
|
# File 'lib/puppeteer/element_handle.rb', line 405
async def async_Seval(selector, page_function, *args)
Seval(selector, page_function, *args)
end
|
#async_SSeval ⇒ Object
`$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
428
429
430
|
# File 'lib/puppeteer/element_handle.rb', line 428
async def async_SSeval(selector, page_function, *args)
SSeval(selector, page_function, *args)
end
|
#async_type_text ⇒ Future
250
251
252
|
# File 'lib/puppeteer/element_handle.rb', line 250
async def async_type_text(text, delay: nil)
type_text(text, delay: delay)
end
|
#click(delay: nil, button: nil, click_count: nil) ⇒ Object
147
148
149
150
151
|
# File 'lib/puppeteer/element_handle.rb', line 147
def click(delay: nil, button: nil, click_count: nil)
scroll_into_view_if_needed
point = clickable_point
@page.mouse.click(point.x, point.y, delay: delay, button: button, click_count: click_count)
end
|
#clickable_point ⇒ Object
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# File 'lib/puppeteer/element_handle.rb', line 85
def clickable_point
result = @remote_object.content_quads(@client)
if !result || result["quads"].empty?
raise ElementNotVisibleError.new
end
layout_metrics = @client.send_message('Page.getLayoutMetrics')
client_width = layout_metrics["layoutViewport"]["clientWidth"]
client_height = layout_metrics["layoutViewport"]["clientHeight"]
quads = result["quads"].
map { |quad| from_protocol_quad(quad) }.
map { |quad| intersect_quad_with_viewport(quad, client_width, client_height) }.
select { |quad| compute_quad_area(quad) > 1 }
if quads.empty?
raise ElementNotVisibleError.new
end
quads.first.reduce(:+) / 4
end
|
#content_frame ⇒ Object
23
24
25
26
27
28
29
30
31
|
# File 'lib/puppeteer/element_handle.rb', line 23
def content_frame
node_info = @remote_object.node_info
frame_id = node_info['node']['frameId']
if frame_id.is_a?(String)
@frame_manager.frame(frame_id)
else
nil
end
end
|
#focus ⇒ Object
232
233
234
|
# File 'lib/puppeteer/element_handle.rb', line 232
def focus
evaluate('element => element.focus()')
end
|
#press(key, delay: nil) ⇒ Object
256
257
258
259
|
# File 'lib/puppeteer/element_handle.rb', line 256
def press(key, delay: nil)
focus
@page.keyboard.press(key, delay: delay)
end
|
#S(selector) ⇒ Object
`$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
354
355
356
357
358
359
360
361
362
363
364
365
366
|
# File 'lib/puppeteer/element_handle.rb', line 354
def S(selector)
handle = evaluate_handle(
'(element, selector) => element.querySelector(selector)',
selector,
)
element = handle.as_element
if element
return element
end
handle.dispose
nil
end
|
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
# File 'lib/puppeteer/element_handle.rb', line 35
def scroll_into_view_if_needed
js = <<~JAVASCRIPT
async(element, pageJavascriptEnabled) => {
if (!element.isConnected)
return 'Node is detached from document';
if (element.nodeType !== Node.ELEMENT_NODE)
return 'Node is not of type HTMLElement';
element.scrollIntoViewIfNeeded({block: 'center', inline: 'center', behavior: 'instant'});
return false;
}
JAVASCRIPT
error = evaluate(js, @page.javascript_enabled) if error
raise ScrollIntoViewError.new(error)
end
sleep 0.16
end
|
#select(*values) ⇒ Array<String>
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
# File 'lib/puppeteer/element_handle.rb', line 161
def select(*values)
if nonstring = values.find { |value| !value.is_a?(String) }
raise ArgumentError.new("Values must be strings. Found value \"#{nonstring}\" of type \"#{nonstring.class}\"")
end
fn = <<~JAVASCRIPT
(element, values) => {
if (element.nodeName.toLowerCase() !== 'select') {
throw new Error('Element is not a <select> element.');
}
const options = Array.from(element.options);
element.value = undefined;
for (const option of options) {
option.selected = values.includes(option.value);
if (option.selected && !element.multiple) {
break;
}
}
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
return options.filter(option => option.selected).map(option => option.value);
}
JAVASCRIPT
evaluate(fn, values)
end
|
#Seval(selector, page_function, *args) ⇒ Object
`$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
390
391
392
393
394
395
396
397
398
399
|
# File 'lib/puppeteer/element_handle.rb', line 390
def Seval(selector, page_function, *args)
element_handle = S(selector)
unless element_handle
raise ElementNotFoundError.new(selector)
end
result = element_handle.evaluate(page_function, *args)
element_handle.dispose
result
end
|
#SS(selector) ⇒ Object
`$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
370
371
372
373
374
375
376
377
378
|
# File 'lib/puppeteer/element_handle.rb', line 370
def SS(selector)
handles = evaluate_handle(
'(element, selector) => element.querySelectorAll(selector)',
selector,
)
properties = handles.properties
handles.dispose
properties.values.map(&:as_element).compact
end
|
#SSeval(selector, page_function, *args) ⇒ Object
`$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
413
414
415
416
417
418
419
420
421
422
|
# File 'lib/puppeteer/element_handle.rb', line 413
def SSeval(selector, page_function, *args)
handles = evaluate_handle(
'(element, selector) => Array.from(element.querySelectorAll(selector))',
selector,
)
result = handles.evaluate(page_function, *args)
handles.dispose
result
end
|
`$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
|
# File 'lib/puppeteer/element_handle.rb', line 435
def Sx(expression)
fn = <<~JAVASCRIPT
(element, expression) => {
const document = element.ownerDocument || element;
const iterator = document.evaluate(expression, element, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
const array = [];
let item;
while ((item = iterator.iterateNext()))
array.push(item);
return array;
}
JAVASCRIPT
handles = evaluate_handle(fn, expression)
properties = handles.properties
handles.dispose
properties.values.map(&:as_element).compact
end
|
#tap(&block) ⇒ Object
220
221
222
223
224
225
226
|
# File 'lib/puppeteer/element_handle.rb', line 220
def tap(&block)
return super(&block) if block
scroll_into_view_if_needed
point = clickable_point
@page.touchscreen.tap(point.x, point.y)
end
|
#type_text(text, delay: nil) ⇒ Object
242
243
244
245
|
# File 'lib/puppeteer/element_handle.rb', line 242
def type_text(text, delay: nil)
focus
@page.keyboard.type_text(text, delay: delay)
end
|
#upload_file(*file_paths) ⇒ Object
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
# File 'lib/puppeteer/element_handle.rb', line 189
def upload_file(*file_paths)
is_multiple = evaluate("el => el.multiple")
if !is_multiple && file_paths.length >= 2
raise ArgumentError.new('Multiple file uploads only work with <input type=file multiple>')
end
if error_path = file_paths.find { |file_path| !File.exist?(file_path) }
raise ArgmentError.new("#{error_path} does not exist or is not readable")
end
backend_node_id = @remote_object.node_info(@client)["node"]["backendNodeId"]
if file_paths.empty?
fn = <<~JAVASCRIPT
(element) => {
element.files = new DataTransfer().files;
// Dispatch events for this case because it should behave akin to a user action.
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
}
JAVASCRIPT
await this.evaluate(fn)
else
@remote_object.set_file_input_files(@client, file_paths, backend_node_id)
end
end
|