module Ferrum::Page::Frames
def frame_by(id: nil, name: nil, execution_id: nil)
-
(Frame, nil)
-
Parameters:
-
execution_id
(String
) -- -
name
(String
) -- -
id
(String
) --
def frame_by(id: nil, name: nil, execution_id: nil) if id @frames[id] elsif name frames.find { |f| f.name == name } elsif execution_id frames.find { |f| f.execution_id == execution_id } else raise ArgumentError end end
def frames
-
(Array)
-
def frames @frames.values end
def frames_subscribe
def frames_subscribe subscribe_frame_attached subscribe_frame_detached subscribe_frame_started_loading subscribe_frame_navigated subscribe_frame_stopped_loading subscribe_navigated_within_document subscribe_request_will_be_sent subscribe_execution_context_created subscribe_execution_context_destroyed subscribe_execution_contexts_cleared end
def idling?
def idling? @frames.values.all? { |f| f.state == :stopped_loading } end
def subscribe_execution_context_created
def subscribe_execution_context_created on("Runtime.executionContextCreated") do |params| context_id = params.dig("context", "id") frame_id = params.dig("context", "auxData", "frameId") unless @main_frame.id root_frame = command("Page.getFrameTree").dig("frameTree", "frame", "id") if frame_id == root_frame @main_frame.id = frame_id @frames.put_if_absent(frame_id, @main_frame) end end frame = @frames.fetch_or_store(frame_id, Frame.new(frame_id, self)) frame.execution_id = context_id end end
def subscribe_execution_context_destroyed
def subscribe_execution_context_destroyed on("Runtime.executionContextDestroyed") do |params| execution_id = params["executionContextId"] frame = frame_by(execution_id: execution_id) frame&.execution_id = nil end end
def subscribe_execution_contexts_cleared
def subscribe_execution_contexts_cleared on("Runtime.executionContextsCleared") do @frames.each_value { |f| f.execution_id = nil } end end
def subscribe_frame_attached
def subscribe_frame_attached on("Page.frameAttached") do |params| parent_frame_id, frame_id = params.values_at("parentFrameId", "frameId") @frames.put_if_absent(frame_id, Frame.new(frame_id, self, parent_frame_id)) end end
def subscribe_frame_detached
def subscribe_frame_detached on("Page.frameDetached") do |params| frame = @frames[params["frameId"]] if frame&.main? frame.execution_id = nil else @frames.delete(params["frameId"]) end end end
def subscribe_frame_navigated
def subscribe_frame_navigated on("Page.frameNavigated") do |params| frame_id, name = params["frame"]&.values_at("id", "name") frame = @frames[frame_id] if frame frame.state = :navigated frame.name = name end end end
def subscribe_frame_started_loading
def subscribe_frame_started_loading on("Page.frameStartedLoading") do |params| frame = @frames[params["frameId"]] frame.state = :started_loading if frame @event.reset end end
def subscribe_frame_stopped_loading
def subscribe_frame_stopped_loading on("Page.frameStoppedLoading") do |params| # `DOM.performSearch` doesn't work without getting #document node first. # It returns node with nodeId 1 and nodeType 9 from which descend the # tree and we save it in a variable because if we call that again root # node will change the id and all subsequent nodes have to change id too. if @main_frame.id == params["frameId"] @event.set if idling? document_node_id end frame = @frames[params["frameId"]] frame&.state = :stopped_loading @event.set if idling? end end
def subscribe_navigated_within_document
def subscribe_navigated_within_document on("Page.navigatedWithinDocument") do @event.set if idling? end end
def subscribe_request_will_be_sent
def subscribe_request_will_be_sent on("Network.requestWillBeSent") do |params| # Possible types: # Document, Stylesheet, Image, Media, Font, Script, TextTrack, XHR, # Fetch, EventSource, WebSocket, Manifest, SignedExchange, Ping, # CSPViolationReport, Other @event.reset if params["frameId"] == @main_frame.id && params["type"] == "Document" end end