1<?php
2
3namespace Facebook\WebDriver\Remote;
4
5use Facebook\WebDriver\Exception\UnsupportedOperationException;
6use Facebook\WebDriver\WebDriverAlert;
7use Facebook\WebDriver\WebDriverElement;
8use Facebook\WebDriver\WebDriverTargetLocator;
9
10/**
11 * Used to locate a given frame or window for RemoteWebDriver.
12 */
13class RemoteTargetLocator implements WebDriverTargetLocator
14{
15    /** @var RemoteExecuteMethod */
16    protected $executor;
17    /** @var RemoteWebDriver */
18    protected $driver;
19    /** @var bool */
20    protected $isW3cCompliant;
21
22    public function __construct(RemoteExecuteMethod $executor, RemoteWebDriver $driver, $isW3cCompliant = false)
23    {
24        $this->executor = $executor;
25        $this->driver = $driver;
26        $this->isW3cCompliant = $isW3cCompliant;
27    }
28
29    /**
30     * @return RemoteWebDriver
31     */
32    public function defaultContent()
33    {
34        $params = ['id' => null];
35        $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);
36
37        return $this->driver;
38    }
39
40    /**
41     * @param WebDriverElement|null|int|string $frame The WebDriverElement, the id or the name of the frame.
42     * When null, switch to the current top-level browsing context When int, switch to the WindowProxy identified
43     * by the value. When an Element, switch to that Element.
44     * @return RemoteWebDriver
45     */
46    public function frame($frame)
47    {
48        if ($this->isW3cCompliant) {
49            if ($frame instanceof WebDriverElement) {
50                $id = [JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $frame->getID()];
51            } elseif ($frame === null) {
52                $id = null;
53            } elseif (is_int($frame)) {
54                $id = $frame;
55            } else {
56                throw new \InvalidArgumentException(
57                    'In W3C compliance mode frame must be either instance of WebDriverElement, integer or null'
58                );
59            }
60        } else {
61            if ($frame instanceof WebDriverElement) {
62                $id = ['ELEMENT' => $frame->getID()];
63            } elseif ($frame === null) {
64                $id = null;
65            } elseif (is_int($frame)) {
66                $id = $frame;
67            } else {
68                $id = (string) $frame;
69            }
70        }
71
72        $params = ['id' => $id];
73        $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);
74
75        return $this->driver;
76    }
77
78    /**
79     * Switch to the parent iframe.
80     *
81     * @return RemoteWebDriver This driver focused on the parent frame
82     */
83    public function parent()
84    {
85        $this->executor->execute(DriverCommand::SWITCH_TO_PARENT_FRAME, []);
86
87        return $this->driver;
88    }
89
90    /**
91     * @param string $handle The handle of the window to be focused on.
92     * @return RemoteWebDriver
93     */
94    public function window($handle)
95    {
96        if ($this->isW3cCompliant) {
97            $params = ['handle' => (string) $handle];
98        } else {
99            $params = ['name' => (string) $handle];
100        }
101
102        $this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params);
103
104        return $this->driver;
105    }
106
107    /**
108     * Creates a new browser window and switches the focus for future commands of this driver to the new window.
109     *
110     * @see https://w3c.github.io/webdriver/#new-window
111     * @param string $windowType The type of a new browser window that should be created. One of [tab, window].
112     * The created window is not guaranteed to be of the requested type; if the driver does not support the requested
113     * type, a new browser window will be created of whatever type the driver does support.
114     * @throws UnsupportedOperationException
115     * @return RemoteWebDriver This driver focused on the given window
116     */
117    public function newWindow($windowType = self::WINDOW_TYPE_TAB)
118    {
119        if ($windowType !== self::WINDOW_TYPE_TAB && $windowType !== self::WINDOW_TYPE_WINDOW) {
120            throw new \InvalidArgumentException('Window type must by either "tab" or "window"');
121        }
122
123        if (!$this->isW3cCompliant) {
124            throw new UnsupportedOperationException('New window is only supported in W3C mode');
125        }
126
127        $response = $this->executor->execute(DriverCommand::NEW_WINDOW, ['type' => $windowType]);
128
129        $this->window($response['handle']);
130
131        return $this->driver;
132    }
133
134    public function alert()
135    {
136        return new WebDriverAlert($this->executor);
137    }
138
139    /**
140     * @return RemoteWebElement
141     */
142    public function activeElement()
143    {
144        $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT, []);
145        $method = new RemoteExecuteMethod($this->driver);
146
147        return new RemoteWebElement($method, JsonWireCompat::getElement($response), $this->isW3cCompliant);
148    }
149}
150