1<?php
2
3namespace Facebook\WebDriver\Support\Events;
4
5use Facebook\WebDriver\Exception\WebDriverException;
6use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
7use Facebook\WebDriver\Internal\WebDriverLocatable;
8use Facebook\WebDriver\WebDriverBy;
9use Facebook\WebDriver\WebDriverDimension;
10use Facebook\WebDriver\WebDriverDispatcher;
11use Facebook\WebDriver\WebDriverElement;
12use Facebook\WebDriver\WebDriverPoint;
13
14class EventFiringWebElement implements WebDriverElement, WebDriverLocatable
15{
16    /**
17     * @var WebDriverElement
18     */
19    protected $element;
20    /**
21     * @var WebDriverDispatcher
22     */
23    protected $dispatcher;
24
25    /**
26     * @param WebDriverElement $element
27     * @param WebDriverDispatcher $dispatcher
28     */
29    public function __construct(WebDriverElement $element, WebDriverDispatcher $dispatcher)
30    {
31        $this->element = $element;
32        $this->dispatcher = $dispatcher;
33    }
34
35    /**
36     * @return WebDriverDispatcher
37     */
38    public function getDispatcher()
39    {
40        return $this->dispatcher;
41    }
42
43    /**
44     * @return WebDriverElement
45     */
46    public function getElement()
47    {
48        return $this->element;
49    }
50
51    /**
52     * @param mixed $value
53     * @throws WebDriverException
54     * @return $this
55     */
56    public function sendKeys($value)
57    {
58        $this->dispatch('beforeChangeValueOf', $this);
59
60        try {
61            $this->element->sendKeys($value);
62        } catch (WebDriverException $exception) {
63            $this->dispatchOnException($exception);
64            throw $exception;
65        }
66        $this->dispatch('afterChangeValueOf', $this);
67
68        return $this;
69    }
70
71    /**
72     * @throws WebDriverException
73     * @return $this
74     */
75    public function click()
76    {
77        $this->dispatch('beforeClickOn', $this);
78
79        try {
80            $this->element->click();
81        } catch (WebDriverException $exception) {
82            $this->dispatchOnException($exception);
83            throw $exception;
84        }
85        $this->dispatch('afterClickOn', $this);
86
87        return $this;
88    }
89
90    /**
91     * @param WebDriverBy $by
92     * @throws WebDriverException
93     * @return EventFiringWebElement
94     */
95    public function findElement(WebDriverBy $by)
96    {
97        $this->dispatch(
98            'beforeFindBy',
99            $by,
100            $this,
101            $this->dispatcher->getDefaultDriver()
102        );
103
104        try {
105            $element = $this->newElement($this->element->findElement($by));
106        } catch (WebDriverException $exception) {
107            $this->dispatchOnException($exception);
108            throw $exception;
109        }
110
111        $this->dispatch(
112            'afterFindBy',
113            $by,
114            $this,
115            $this->dispatcher->getDefaultDriver()
116        );
117
118        return $element;
119    }
120
121    /**
122     * @param WebDriverBy $by
123     * @throws WebDriverException
124     * @return array
125     */
126    public function findElements(WebDriverBy $by)
127    {
128        $this->dispatch(
129            'beforeFindBy',
130            $by,
131            $this,
132            $this->dispatcher->getDefaultDriver()
133        );
134
135        try {
136            $elements = [];
137            foreach ($this->element->findElements($by) as $element) {
138                $elements[] = $this->newElement($element);
139            }
140        } catch (WebDriverException $exception) {
141            $this->dispatchOnException($exception);
142            throw $exception;
143        }
144        $this->dispatch(
145            'afterFindBy',
146            $by,
147            $this,
148            $this->dispatcher->getDefaultDriver()
149        );
150
151        return $elements;
152    }
153
154    /**
155     * @throws WebDriverException
156     * @return $this
157     */
158    public function clear()
159    {
160        try {
161            $this->element->clear();
162
163            return $this;
164        } catch (WebDriverException $exception) {
165            $this->dispatchOnException($exception);
166            throw $exception;
167        }
168    }
169
170    /**
171     * @param string $attribute_name
172     * @throws WebDriverException
173     * @return string
174     */
175    public function getAttribute($attribute_name)
176    {
177        try {
178            return $this->element->getAttribute($attribute_name);
179        } catch (WebDriverException $exception) {
180            $this->dispatchOnException($exception);
181            throw $exception;
182        }
183    }
184
185    /**
186     * @param string $css_property_name
187     * @throws WebDriverException
188     * @return string
189     */
190    public function getCSSValue($css_property_name)
191    {
192        try {
193            return $this->element->getCSSValue($css_property_name);
194        } catch (WebDriverException $exception) {
195            $this->dispatchOnException($exception);
196            throw $exception;
197        }
198    }
199
200    /**
201     * @throws WebDriverException
202     * @return WebDriverPoint
203     */
204    public function getLocation()
205    {
206        try {
207            return $this->element->getLocation();
208        } catch (WebDriverException $exception) {
209            $this->dispatchOnException($exception);
210            throw $exception;
211        }
212    }
213
214    /**
215     * @throws WebDriverException
216     * @return WebDriverPoint
217     */
218    public function getLocationOnScreenOnceScrolledIntoView()
219    {
220        try {
221            return $this->element->getLocationOnScreenOnceScrolledIntoView();
222        } catch (WebDriverException $exception) {
223            $this->dispatchOnException($exception);
224            throw $exception;
225        }
226    }
227
228    /**
229     * @return WebDriverCoordinates
230     */
231    public function getCoordinates()
232    {
233        try {
234            return $this->element->getCoordinates();
235        } catch (WebDriverException $exception) {
236            $this->dispatchOnException($exception);
237            throw $exception;
238        }
239    }
240
241    /**
242     * @throws WebDriverException
243     * @return WebDriverDimension
244     */
245    public function getSize()
246    {
247        try {
248            return $this->element->getSize();
249        } catch (WebDriverException $exception) {
250            $this->dispatchOnException($exception);
251            throw $exception;
252        }
253    }
254
255    /**
256     * @throws WebDriverException
257     * @return string
258     */
259    public function getTagName()
260    {
261        try {
262            return $this->element->getTagName();
263        } catch (WebDriverException $exception) {
264            $this->dispatchOnException($exception);
265            throw $exception;
266        }
267    }
268
269    /**
270     * @throws WebDriverException
271     * @return string
272     */
273    public function getText()
274    {
275        try {
276            return $this->element->getText();
277        } catch (WebDriverException $exception) {
278            $this->dispatchOnException($exception);
279            throw $exception;
280        }
281    }
282
283    /**
284     * @throws WebDriverException
285     * @return bool
286     */
287    public function isDisplayed()
288    {
289        try {
290            return $this->element->isDisplayed();
291        } catch (WebDriverException $exception) {
292            $this->dispatchOnException($exception);
293            throw $exception;
294        }
295    }
296
297    /**
298     * @throws WebDriverException
299     * @return bool
300     */
301    public function isEnabled()
302    {
303        try {
304            return $this->element->isEnabled();
305        } catch (WebDriverException $exception) {
306            $this->dispatchOnException($exception);
307            throw $exception;
308        }
309    }
310
311    /**
312     * @throws WebDriverException
313     * @return bool
314     */
315    public function isSelected()
316    {
317        try {
318            return $this->element->isSelected();
319        } catch (WebDriverException $exception) {
320            $this->dispatchOnException($exception);
321            throw $exception;
322        }
323    }
324
325    /**
326     * @throws WebDriverException
327     * @return $this
328     */
329    public function submit()
330    {
331        try {
332            $this->element->submit();
333
334            return $this;
335        } catch (WebDriverException $exception) {
336            $this->dispatchOnException($exception);
337            throw $exception;
338        }
339    }
340
341    /**
342     * @throws WebDriverException
343     * @return string
344     */
345    public function getID()
346    {
347        try {
348            return $this->element->getID();
349        } catch (WebDriverException $exception) {
350            $this->dispatchOnException($exception);
351            throw $exception;
352        }
353    }
354
355    /**
356     * Test if two element IDs refer to the same DOM element.
357     *
358     * @param WebDriverElement $other
359     * @return bool
360     */
361    public function equals(WebDriverElement $other)
362    {
363        try {
364            return $this->element->equals($other);
365        } catch (WebDriverException $exception) {
366            $this->dispatchOnException($exception);
367            throw $exception;
368        }
369    }
370
371    /**
372     * @param WebDriverException $exception
373     */
374    protected function dispatchOnException(WebDriverException $exception)
375    {
376        $this->dispatch(
377            'onException',
378            $exception,
379            $this->dispatcher->getDefaultDriver()
380        );
381    }
382
383    /**
384     * @param mixed $method
385     * @param mixed ...$arguments
386     */
387    protected function dispatch($method, ...$arguments)
388    {
389        if (!$this->dispatcher) {
390            return;
391        }
392
393        $this->dispatcher->dispatch($method, $arguments);
394    }
395
396    /**
397     * @param WebDriverElement $element
398     * @return static
399     */
400    protected function newElement(WebDriverElement $element)
401    {
402        return new static($element, $this->getDispatcher());
403    }
404}
405