Path: blob/trunk/rb/lib/selenium/webdriver/common/interactions/pointer_actions.rb
1990 views
# frozen_string_literal: true12# Licensed to the Software Freedom Conservancy (SFC) under one3# or more contributor license agreements. See the NOTICE file4# distributed with this work for additional information5# regarding copyright ownership. The SFC licenses this file6# to you under the Apache License, Version 2.0 (the7# "License"); you may not use this file except in compliance8# with the License. You may obtain a copy of the License at9#10# http://www.apache.org/licenses/LICENSE-2.011#12# Unless required by applicable law or agreed to in writing,13# software distributed under the License is distributed on an14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY15# KIND, either express or implied. See the License for the16# specific language governing permissions and limitations17# under the License.1819module Selenium20module WebDriver21module PointerActions22attr_writer :default_move_duration2324#25# By default this is set to 250ms in the ActionBuilder constructor26# It can be overridden with default_move_duration=27#2829def default_move_duration30@default_move_duration ||= @duration / 1000.0 # convert ms to seconds31end3233#34# Presses (without releasing) at the current location of the PointerInput device. This is equivalent to:35#36# driver.action.click_and_hold(nil)37#38# @example Clicking and holding at the current location39#40# driver.action.pointer_down(:left).perform41#42# @param [Selenium::WebDriver::Interactions::PointerPress::BUTTONS] button the button to press.43# @param [Symbol || String] device optional name of the PointerInput device with the button44# that will be pressed45# @return [ActionBuilder] A self reference.46#4748def pointer_down(button = :left, device: nil, **)49button_action(button, :create_pointer_down, device: device, **)50end5152#53# Releases the pressed mouse button at the current mouse location of the PointerInput device.54#55# @example Releasing a button after clicking and holding56#57# driver.action.pointer_down(:left).pointer_up(:left).perform58#59# @param [Selenium::WebDriver::Interactions::PointerPress::BUTTONS] button the button to release.60# @param [Symbol || String] device optional name of the PointerInput device with the button that will61# be released62# @return [ActionBuilder] A self reference.63#6465def pointer_up(button = :left, device: nil, **)66button_action(button, :create_pointer_up, device: device, **)67end6869#70# Moves the pointer to the in-view center point of the given element.71# Then the pointer is moved to optional offset coordinates.72#73# The element is not scrolled into view.74# MoveTargetOutOfBoundsError will be raised if element with offset is outside the viewport75#76# When using offsets, both coordinates need to be passed.77#78# @example Move the pointer to element79#80# el = driver.find_element(id: "some_id")81# driver.action.move_to(el).perform82#83# @example84#85# el = driver.find_element(id: "some_id")86# driver.action.move_to(el, 100, 100).perform87#88# @param [Selenium::WebDriver::Element] element to move to.89# @param [Integer] right_by Optional offset from the in-view center of the90# element. A negative value means coordinates to the left of the center.91# @param [Integer] down_by Optional offset from the in-view center of the92# element. A negative value means coordinates to the top of the center.93# @return [ActionBuilder] A self reference.94#9596def move_to(element, right_by = nil, down_by = nil, **opts)97pointer = pointer_input(opts.delete(:device))98pointer.create_pointer_move(duration: opts.delete(:duration) || default_move_duration,99x: right_by || 0,100y: down_by || 0,101origin: element,102**opts)103tick(pointer)104self105end106107#108# Moves the pointer from its current position by the given offset.109#110# The viewport is not scrolled if the coordinates provided are outside the viewport.111# MoveTargetOutOfBoundsError will be raised if the offsets are outside the viewport112#113# @example Move the pointer to a certain offset from its current position114#115# driver.action.move_by(100, 100).perform116#117# @param [Integer] right_by horizontal offset. A negative value means moving the pointer left.118# @param [Integer] down_by vertical offset. A negative value means moving the pointer up.119# @param [Symbol || String] device optional name of the PointerInput device to move120# @return [ActionBuilder] A self reference.121# @raise [MoveTargetOutOfBoundsError] if the provided offset is outside the document's boundaries.122#123124def move_by(right_by, down_by, device: nil, duration: default_move_duration, **)125pointer = pointer_input(device)126pointer.create_pointer_move(duration: duration,127x: Integer(right_by),128y: Integer(down_by),129origin: Interactions::PointerMove::POINTER,130**)131tick(pointer)132self133end134135#136# Moves the pointer to a given location in the viewport.137#138# The viewport is not scrolled if the coordinates provided are outside the viewport.139# MoveTargetOutOfBoundsError will be raised if the offsets are outside the viewport140#141# @example Move the pointer to a certain position in the viewport142#143# driver.action.move_to_location(100, 100).perform144#145# @param [Integer] x horizontal position. Equivalent to a css 'left' value.146# @param [Integer] y vertical position. Equivalent to a css 'top' value.147# @param [Symbol || String] device optional name of the PointerInput device to move148# @return [ActionBuilder] A self reference.149# @raise [MoveTargetOutOfBoundsError] if the provided x or y value is outside the document's boundaries.150#151152def move_to_location(x, y, device: nil, duration: default_move_duration, **)153pointer = pointer_input(device)154pointer.create_pointer_move(duration: duration,155x: Integer(x),156y: Integer(y),157origin: Interactions::PointerMove::VIEWPORT,158**)159tick(pointer)160self161end162163#164# Clicks (without releasing) in the middle of the given element. This is165# equivalent to:166#167# driver.action.move_to(element).click_and_hold168#169# @example Clicking and holding on some element170#171# el = driver.find_element(id: "some_id")172# driver.action.click_and_hold(el).perform173#174# @param [Selenium::WebDriver::Element] element the element to move to and click.175# @param [Symbol || String] device optional name of the PointerInput device to click with176# @return [ActionBuilder] A self reference.177#178179def click_and_hold(element = nil, button: nil, device: nil)180move_to(element, device: device) if element181pointer_down(button || :left, device: device)182self183end184185#186# Releases the depressed left mouse button at the current mouse location.187#188# @example Releasing an element after clicking and holding it189#190# el = driver.find_element(id: "some_id")191# driver.action.click_and_hold(el).release.perform192#193# @param [Symbol || String] device optional name of the PointerInput device with the button194# that will be released195# @return [ActionBuilder] A self reference.196#197198def release(button: nil, device: nil)199pointer_up(button || :left, device: device)200self201end202203#204# Clicks in the middle of the given element. Equivalent to:205#206# driver.action.move_to(element).click207#208# When no element is passed, the current mouse position will be clicked.209#210# @example Clicking on an element211#212# el = driver.find_element(id: "some_id")213# driver.action.click(el).perform214#215# @example Clicking at the current mouse position216#217# driver.action.click.perform218#219# @param [Selenium::WebDriver::Element] element An optional element to click.220# @param [Symbol || String] device optional name of the PointerInput device with the button221# that will be clicked222# @return [ActionBuilder] A self reference.223#224225def click(element = nil, button: nil, device: nil)226move_to(element, device: device) if element227pointer_down(button || :left, device: device)228pointer_up(button || :left, device: device)229self230end231232#233# Performs a double-click at middle of the given element. Equivalent to:234#235# driver.action.move_to(element).double_click236#237# When no element is passed, the current mouse position will be double-clicked.238#239# @example Double-click an element240#241# el = driver.find_element(id: "some_id")242# driver.action.double_click(el).perform243#244# @example Double-clicking at the current mouse position245#246# driver.action.double_click.perform247#248# @param [Selenium::WebDriver::Element] element An optional element to move to.249# @param [Symbol || String] device optional name of the PointerInput device with the button250# that will be double-clicked251# @return [ActionBuilder] A self reference.252#253254def double_click(element = nil, device: nil)255move_to(element, device: device) if element256click(device: device)257click(device: device)258self259end260261#262# Performs a context-click at middle of the given element. First performs263# a move_to to the location of the element.264#265# When no element is passed, the current mouse position will be context-clicked.266#267# @example Context-click at middle of given element268#269# el = driver.find_element(id: "some_id")270# driver.action.context_click(el).perform271#272# @example Context-clicking at the current mouse position273#274# driver.action.context_click.perform275#276# @param [Selenium::WebDriver::Element] element An element to context click.277# @param [Symbol || String] device optional name of the PointerInput device with the button278# that will be context-clicked279# @return [ActionBuilder] A self reference.280#281282def context_click(element = nil, device: nil)283click(element, button: :right, device: device)284end285286#287# A convenience method that performs click-and-hold at the location of the288# source element, moves to the location of the target element, then289# releases the mouse.290#291# @example Drag and drop one element onto another292#293# el1 = driver.find_element(id: "some_id1")294# el2 = driver.find_element(id: "some_id2")295# driver.action.drag_and_drop(el1, el2).perform296#297# @param [Selenium::WebDriver::Element] source element to emulate button down at.298# @param [Selenium::WebDriver::Element] target element to move to and release the299# mouse at.300# @param [Symbol || String] device optional name of the PointerInput device with the button301# that will perform the drag and drop302# @return [ActionBuilder] A self reference.303#304305def drag_and_drop(source, target, device: nil)306click_and_hold(source, device: device)307move_to(target, device: device)308release(device: device)309self310end311312#313# A convenience method that performs click-and-hold at the location of314# the source element, moves by a given offset, then releases the mouse.315#316# @example Drag and drop an element by offset317#318# el = driver.find_element(id: "some_id1")319# driver.action.drag_and_drop_by(el, 100, 100).perform320#321# @param [Selenium::WebDriver::Element] source Element to emulate button down at.322# @param [Integer] right_by horizontal move offset.323# @param [Integer] down_by vertical move offset.324# @param [Symbol || String] device optional name of the PointerInput device with the button325# that will perform the drag and drop326# @return [ActionBuilder] A self reference.327#328329def drag_and_drop_by(source, right_by, down_by, device: nil)330click_and_hold(source, device: device)331move_by(right_by, down_by, device: device)332release(device: device)333self334end335336private337338def button_action(button, action, device: nil, **)339pointer = pointer_input(device)340pointer.send(action, button, **)341tick(pointer)342self343end344345def pointer_input(name = nil)346device(name: name, type: Interactions::POINTER) || add_pointer_input(:mouse, 'mouse')347end348end # PointerActions349end # WebDriver350end # Selenium351352353