class Ferrum::Node
Constants
- MOVING_WAIT_ATTEMPTS
- MOVING_WAIT_DELAY
Attributes
description[R]
node_id[R]
page[R]
tag_name[R]
target_id[R]
Public Class Methods
new(frame, target_id, node_id, description)
click to toggle source
# File lib/ferrum/node.rb, line 10 def initialize(frame, target_id, node_id, description) @page = frame.page @target_id = target_id @node_id, @description = node_id, description @tag_name = description["nodeName"].downcase end
Public Instance Methods
==(other)
click to toggle source
# File lib/ferrum/node.rb, line 134 def ==(other) return false unless other.is_a?(Node) # We compare backendNodeId because once nodeId is sent to frontend backend # never returns same nodeId sending 0. In other words frontend is # responsible for keeping track of node ids. target_id == other.target_id && description["backendNodeId"] == other.description["backendNodeId"] end
at_css(selector)
click to toggle source
# File lib/ferrum/node.rb, line 97 def at_css(selector) page.at_css(selector, within: self) end
at_xpath(selector)
click to toggle source
# File lib/ferrum/node.rb, line 93 def at_xpath(selector) page.at_xpath(selector, within: self) end
attribute(name)
click to toggle source
# File lib/ferrum/node.rb, line 126 def attribute(name) evaluate("this.getAttribute('#{name}')") end
blur()
click to toggle source
# File lib/ferrum/node.rb, line 53 def blur tap { evaluate("this.blur()") } end
click(mode: :left, keys: [], offset: {}, delay: 0)
click to toggle source
mode: (:left | :right | :double) keys: (:alt, (:ctrl | :control), (:meta | :command), :shift) offset: { :x, :y, :position (:top | :center) }
# File lib/ferrum/node.rb, line 64 def click(mode: :left, keys: [], offset: {}, delay: 0) x, y = find_position(**offset) modifiers = page.keyboard.modifiers(keys) case mode when :right page.mouse.move(x: x, y: y) page.mouse.down(button: :right, modifiers: modifiers) sleep(delay) page.mouse.up(button: :right, modifiers: modifiers) when :double page.mouse.move(x: x, y: y) page.mouse.down(modifiers: modifiers, count: 2) page.mouse.up(modifiers: modifiers, count: 2) when :left page.mouse.click(x: x, y: y, modifiers: modifiers, delay: delay) end self end
css(selector)
click to toggle source
# File lib/ferrum/node.rb, line 105 def css(selector) page.css(selector, within: self) end
evaluate(expression)
click to toggle source
# File lib/ferrum/node.rb, line 130 def evaluate(expression) page.evaluate_on(node: self, expression: expression) end
find_position(x: nil, y: nil, position: :top)
click to toggle source
# File lib/ferrum/node.rb, line 146 def find_position(x: nil, y: nil, position: :top) points = wait_for_stop_moving.map { |q| to_points(q) }.first get_position(points, x, y, position) rescue CoordinatesNotFoundError x, y = get_bounding_rect_coordinates raise if x == 0 && y == 0 [x, y] end
focus()
click to toggle source
# File lib/ferrum/node.rb, line 29 def focus tap { page.command("DOM.focus", slowmoable: true, nodeId: node_id) } end
focusable?()
click to toggle source
# File lib/ferrum/node.rb, line 33 def focusable? focus true rescue BrowserError => e e.message == "Element is not focusable" ? false : raise end
frame()
click to toggle source
# File lib/ferrum/node.rb, line 25 def frame page.frame_by(id: frame_id) end
frame_id()
click to toggle source
# File lib/ferrum/node.rb, line 21 def frame_id description["frameId"] end
hover()
click to toggle source
# File lib/ferrum/node.rb, line 85 def hover raise NotImplementedError end
inner_text()
click to toggle source
FIXME: clear API for text and inner_text
# File lib/ferrum/node.rb, line 114 def inner_text evaluate("this.innerText") end
inspect()
click to toggle source
# File lib/ferrum/node.rb, line 142 def inspect %(#<#{self.class} @target_id=#{@target_id.inspect} @node_id=#{@node_id} @description=#{@description.inspect}>) end
moving?(delay: MOVING_WAIT_DELAY)
click to toggle source
# File lib/ferrum/node.rb, line 48 def moving?(delay: MOVING_WAIT_DELAY) previous, current = get_content_quads_with(delay: delay) previous == current end
node?()
click to toggle source
# File lib/ferrum/node.rb, line 17 def node? description["nodeType"] == 1 # nodeType: 3, nodeName: "#text" e.g. end
property(name)
click to toggle source
# File lib/ferrum/node.rb, line 122 def property(name) evaluate("this['#{name}']") end
select_file(value)
click to toggle source
# File lib/ferrum/node.rb, line 89 def select_file(value) page.command("DOM.setFileInputFiles", slowmoable: true, nodeId: node_id, files: Array(value)) end
text()
click to toggle source
# File lib/ferrum/node.rb, line 109 def text evaluate("this.textContent") end
type(*keys)
click to toggle source
# File lib/ferrum/node.rb, line 57 def type(*keys) tap { page.keyboard.type(*keys) } end
value()
click to toggle source
# File lib/ferrum/node.rb, line 118 def value evaluate("this.value") end
wait_for_stop_moving(delay: MOVING_WAIT_DELAY, attempts: MOVING_WAIT_ATTEMPTS)
click to toggle source
# File lib/ferrum/node.rb, line 40 def wait_for_stop_moving(delay: MOVING_WAIT_DELAY, attempts: MOVING_WAIT_ATTEMPTS) Ferrum.with_attempts(errors: NodeMovingError, max: attempts, wait: 0) do previous, current = get_content_quads_with(delay: delay) raise NodeMovingError.new(self, previous, current) if previous != current current end end
xpath(selector)
click to toggle source
# File lib/ferrum/node.rb, line 101 def xpath(selector) page.xpath(selector, within: self) end
Private Instance Methods
get_bounding_rect_coordinates()
click to toggle source
# File lib/ferrum/node.rb, line 157 def get_bounding_rect_coordinates evaluate <<~JS [this.getBoundingClientRect().left + window.pageXOffset + (this.offsetWidth / 2), this.getBoundingClientRect().top + window.pageYOffset + (this.offsetHeight / 2)] JS end
get_content_quads()
click to toggle source
# File lib/ferrum/node.rb, line 164 def get_content_quads quads = page.command("DOM.getContentQuads", nodeId: node_id)["quads"] raise CoordinatesNotFoundError, "Node is either not visible or not an HTMLElement" if quads.size == 0 quads end
get_content_quads_with(delay: MOVING_WAIT_DELAY)
click to toggle source
# File lib/ferrum/node.rb, line 170 def get_content_quads_with(delay: MOVING_WAIT_DELAY) previous = get_content_quads sleep(delay) current = get_content_quads [previous, current] end
get_position(points, offset_x, offset_y, position)
click to toggle source
# File lib/ferrum/node.rb, line 177 def get_position(points, offset_x, offset_y, position) x = y = nil if offset_x && offset_y && position == :top point = points.first x = point[:x] + offset_x.to_i y = point[:y] + offset_y.to_i else x, y = points.inject([0, 0]) do |memo, point| [memo[0] + point[:x], memo[1] + point[:y]] end x = x / 4 y = y / 4 end if offset_x && offset_y && position == :center x = x + offset_x.to_i y = y + offset_y.to_i end [x, y] end
to_points(quad)
click to toggle source
# File lib/ferrum/node.rb, line 202 def to_points(quad) [{x: quad[0], y: quad[1]}, {x: quad[2], y: quad[3]}, {x: quad[4], y: quad[5]}, {x: quad[6], y: quad[7]}] end