1<?php
2
3namespace Facebook\WebDriver\Interactions;
4
5use Facebook\WebDriver\Interactions\Internal\WebDriverButtonReleaseAction;
6use Facebook\WebDriver\Interactions\Internal\WebDriverClickAction;
7use Facebook\WebDriver\Interactions\Internal\WebDriverClickAndHoldAction;
8use Facebook\WebDriver\Interactions\Internal\WebDriverContextClickAction;
9use Facebook\WebDriver\Interactions\Internal\WebDriverDoubleClickAction;
10use Facebook\WebDriver\Interactions\Internal\WebDriverKeyDownAction;
11use Facebook\WebDriver\Interactions\Internal\WebDriverKeyUpAction;
12use Facebook\WebDriver\Interactions\Internal\WebDriverMouseMoveAction;
13use Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction;
14use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction;
15use Facebook\WebDriver\WebDriverElement;
16use Facebook\WebDriver\WebDriverHasInputDevices;
17
18/**
19 * WebDriver action builder. It implements the builder pattern.
20 */
21class WebDriverActions
22{
23    protected $driver;
24    protected $keyboard;
25    protected $mouse;
26    protected $action;
27
28    /**
29     * @param WebDriverHasInputDevices $driver
30     */
31    public function __construct(WebDriverHasInputDevices $driver)
32    {
33        $this->driver = $driver;
34        $this->keyboard = $driver->getKeyboard();
35        $this->mouse = $driver->getMouse();
36        $this->action = new WebDriverCompositeAction();
37    }
38
39    /**
40     * A convenience method for performing the actions without calling build().
41     */
42    public function perform()
43    {
44        $this->action->perform();
45    }
46
47    /**
48     * Mouse click.
49     * If $element is provided, move to the middle of the element first.
50     *
51     * @param WebDriverElement $element
52     * @return WebDriverActions
53     */
54    public function click(WebDriverElement $element = null)
55    {
56        $this->action->addAction(
57            new WebDriverClickAction($this->mouse, $element)
58        );
59
60        return $this;
61    }
62
63    /**
64     * Mouse click and hold.
65     * If $element is provided, move to the middle of the element first.
66     *
67     * @param WebDriverElement $element
68     * @return WebDriverActions
69     */
70    public function clickAndHold(WebDriverElement $element = null)
71    {
72        $this->action->addAction(
73            new WebDriverClickAndHoldAction($this->mouse, $element)
74        );
75
76        return $this;
77    }
78
79    /**
80     * Context-click (right click).
81     * If $element is provided, move to the middle of the element first.
82     *
83     * @param WebDriverElement $element
84     * @return WebDriverActions
85     */
86    public function contextClick(WebDriverElement $element = null)
87    {
88        $this->action->addAction(
89            new WebDriverContextClickAction($this->mouse, $element)
90        );
91
92        return $this;
93    }
94
95    /**
96     * Double click.
97     * If $element is provided, move to the middle of the element first.
98     *
99     * @param WebDriverElement $element
100     * @return WebDriverActions
101     */
102    public function doubleClick(WebDriverElement $element = null)
103    {
104        $this->action->addAction(
105            new WebDriverDoubleClickAction($this->mouse, $element)
106        );
107
108        return $this;
109    }
110
111    /**
112     * Drag and drop from $source to $target.
113     *
114     * @param WebDriverElement $source
115     * @param WebDriverElement $target
116     * @return WebDriverActions
117     */
118    public function dragAndDrop(WebDriverElement $source, WebDriverElement $target)
119    {
120        $this->action->addAction(
121            new WebDriverClickAndHoldAction($this->mouse, $source)
122        );
123        $this->action->addAction(
124            new WebDriverMouseMoveAction($this->mouse, $target)
125        );
126        $this->action->addAction(
127            new WebDriverButtonReleaseAction($this->mouse, $target)
128        );
129
130        return $this;
131    }
132
133    /**
134     * Drag $source and drop by offset ($x_offset, $y_offset).
135     *
136     * @param WebDriverElement $source
137     * @param int $x_offset
138     * @param int $y_offset
139     * @return WebDriverActions
140     */
141    public function dragAndDropBy(WebDriverElement $source, $x_offset, $y_offset)
142    {
143        $this->action->addAction(
144            new WebDriverClickAndHoldAction($this->mouse, $source)
145        );
146        $this->action->addAction(
147            new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset)
148        );
149        $this->action->addAction(
150            new WebDriverButtonReleaseAction($this->mouse, null)
151        );
152
153        return $this;
154    }
155
156    /**
157     * Mouse move by offset.
158     *
159     * @param int $x_offset
160     * @param int $y_offset
161     * @return WebDriverActions
162     */
163    public function moveByOffset($x_offset, $y_offset)
164    {
165        $this->action->addAction(
166            new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset)
167        );
168
169        return $this;
170    }
171
172    /**
173     * Move to the middle of the given WebDriverElement.
174     * Extra shift, calculated from the top-left corner of the element, can be set by passing $x_offset and $y_offset
175     * parameters.
176     *
177     * @param WebDriverElement $element
178     * @param int $x_offset
179     * @param int $y_offset
180     * @return WebDriverActions
181     */
182    public function moveToElement(WebDriverElement $element, $x_offset = null, $y_offset = null)
183    {
184        $this->action->addAction(new WebDriverMoveToOffsetAction(
185            $this->mouse,
186            $element,
187            $x_offset,
188            $y_offset
189        ));
190
191        return $this;
192    }
193
194    /**
195     * Release the mouse button.
196     * If $element is provided, move to the middle of the element first.
197     *
198     * @param WebDriverElement $element
199     * @return WebDriverActions
200     */
201    public function release(WebDriverElement $element = null)
202    {
203        $this->action->addAction(
204            new WebDriverButtonReleaseAction($this->mouse, $element)
205        );
206
207        return $this;
208    }
209
210    /**
211     * Press a key on keyboard.
212     * If $element is provided, focus on that element first.
213     *
214     * @see WebDriverKeys for special keys like CONTROL, ALT, etc.
215     * @param WebDriverElement $element
216     * @param string $key
217     * @return WebDriverActions
218     */
219    public function keyDown(WebDriverElement $element = null, $key = null)
220    {
221        $this->action->addAction(
222            new WebDriverKeyDownAction($this->keyboard, $this->mouse, $element, $key)
223        );
224
225        return $this;
226    }
227
228    /**
229     * Release a key on keyboard.
230     * If $element is provided, focus on that element first.
231     *
232     * @see WebDriverKeys for special keys like CONTROL, ALT, etc.
233     * @param WebDriverElement $element
234     * @param string $key
235     * @return WebDriverActions
236     */
237    public function keyUp(WebDriverElement $element = null, $key = null)
238    {
239        $this->action->addAction(
240            new WebDriverKeyUpAction($this->keyboard, $this->mouse, $element, $key)
241        );
242
243        return $this;
244    }
245
246    /**
247     * Send keys by keyboard.
248     * If $element is provided, focus on that element first (using single mouse click).
249     *
250     * @see WebDriverKeys for special keys like CONTROL, ALT, etc.
251     * @param WebDriverElement $element
252     * @param string $keys
253     * @return WebDriverActions
254     */
255    public function sendKeys(WebDriverElement $element = null, $keys = null)
256    {
257        $this->action->addAction(
258            new WebDriverSendKeysAction(
259                $this->keyboard,
260                $this->mouse,
261                $element,
262                $keys
263            )
264        );
265
266        return $this;
267    }
268}
269