You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
9.5 KiB
387 lines
9.5 KiB
<?php
|
|
/*
|
|
** Zabbix
|
|
** Copyright (C) 2001-2023 Zabbix SIA
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
**/
|
|
|
|
require_once 'vendor/autoload.php';
|
|
|
|
require_once dirname(__FILE__).'/../CElement.php';
|
|
|
|
use Facebook\WebDriver\Remote\RemoteWebElement;
|
|
use Facebook\WebDriver\Exception\StaleElementReferenceException;
|
|
use Facebook\WebDriver\Exception\TimeoutException;
|
|
|
|
/**
|
|
* Multiselect element.
|
|
*/
|
|
class CMultiselectElement extends CElement {
|
|
|
|
/**
|
|
* Multiselect fill modes.
|
|
*/
|
|
const MODE_SELECT = 0;
|
|
const MODE_SELECT_MULTIPLE = 1;
|
|
const MODE_TYPE = 2;
|
|
|
|
protected static $default_mode = self::MODE_TYPE;
|
|
protected $mode;
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public static function createInstance(RemoteWebElement $element, $options = []) {
|
|
$instance = parent::createInstance($element, $options);
|
|
|
|
if ($instance->mode === null) {
|
|
$instance->mode = self::$default_mode;
|
|
}
|
|
|
|
return $instance;
|
|
}
|
|
|
|
/**
|
|
* Set default fill mode.
|
|
*
|
|
* @param integer $mode MODE_SELECT, MODE_SELECT_MULTIPLE or MODE_TYPE
|
|
*/
|
|
public static function setDefaultFillMode($mode) {
|
|
self::$default_mode = $mode;
|
|
}
|
|
|
|
/**
|
|
* Set fill mode.
|
|
*
|
|
* @param integer $mode MODE_SELECT, MODE_SELECT_MULTIPLE or MODE_TYPE
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function setFillMode($mode) {
|
|
$this->mode = $mode;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Remove all elements from multiselect.
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function clear() {
|
|
$query = $this->query('xpath:.//span['.CXPathHelper::fromClass('zi-remove-smaller').']');
|
|
$query->all()->click();
|
|
$query->waitUntilNotPresent();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get labels of selected elements.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getSelected() {
|
|
return $this->query('xpath:.//span[@class="subfilter-enabled"]')->all()->asText();
|
|
}
|
|
|
|
/**
|
|
* Add selection by label.
|
|
*
|
|
* @param string $label label text
|
|
* @param mixed $context overlay dialog context (hostgroup / host)
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function select($label, $context = null) {
|
|
if (is_array($label)) {
|
|
throw new Exception('Select of multiple labels is not supported in single select mode.');
|
|
}
|
|
|
|
if ($label === '') {
|
|
return $this->clear();
|
|
}
|
|
|
|
$this->edit($context)->query('link:'.$label)->waitUntilVisible(3)->one()->click()->waitUntilNotPresent();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add selection by multiple labels.
|
|
*
|
|
* @param array $labels array of label texts
|
|
* @param mixed $context multiselect context (hostgroup / host)
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function selectMultiple($labels, $context = null) {
|
|
if ($labels) {
|
|
if (!is_array($labels)) {
|
|
$labels = [$labels];
|
|
}
|
|
|
|
$overlay = $this->edit($context);
|
|
$table = $overlay->getContent()->asTable();
|
|
|
|
foreach ($labels as $label) {
|
|
$row = $table->findRow('Name', $label);
|
|
if (!$row->isValid()) {
|
|
throw new Exception('Cannot select row with label "'.$label.'" in multiselect element.');
|
|
}
|
|
|
|
$row->select();
|
|
}
|
|
$overlay->getFooter()->query('button:Select')->one()->click();
|
|
$overlay->waitUntilNotPresent();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Select all possible options.
|
|
*
|
|
* @param mixed $context overlay dialog context (hostgroup / host)
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function selectAll($context = null) {
|
|
$overlay = $this->edit($context);
|
|
$overlay->query('xpath:.//input[@name="all_records"]')->one()->click();
|
|
$overlay->getFooter()->query('button:Select')->one()->click();
|
|
|
|
$overlay->waitUntilNotPresent();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Remove selected option.
|
|
*
|
|
* @param string $label label text
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function remove($label) {
|
|
$query = $this->query('xpath:.//span[@class="subfilter-enabled"][string()='.CXPathHelper::escapeQuotes($label).
|
|
']/span['.CXPathHelper::fromClass('zi-remove-smaller').']'
|
|
);
|
|
|
|
$query->one()->click();
|
|
$query->waitUntilNotPresent();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get collection of multiselect controls (buttons).
|
|
*
|
|
* @return CElement
|
|
*/
|
|
public function getControls() {
|
|
$buttons = [];
|
|
$xpath = 'xpath:.//button';
|
|
|
|
foreach ($this->query($xpath)->waitUntilVisible()->all() as $button) {
|
|
$buttons[$button->getText()] = $button;
|
|
}
|
|
|
|
return new CElementCollection($buttons);
|
|
}
|
|
|
|
/**
|
|
* Open selection overlay dialog.
|
|
*
|
|
* @param mixed $context overlay dialog context (hostgroup / host)
|
|
*
|
|
* @return COverlayDialogElement
|
|
*/
|
|
public function edit($context = null) {
|
|
/* TODO: extend the function for composite elements with two buttons,
|
|
* Example of such multiselect: [ Input field ] ( Select item ) ( Select prototype )
|
|
*/
|
|
$this->getControls()->first()->click();
|
|
|
|
return COverlayDialogElement::find()->waitUntilPresent()
|
|
->all()->last()->waitUntilReady()->setDataContext($context, $this->mode);
|
|
}
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function type($text) {
|
|
if (!is_array($text)) {
|
|
$text = [$text];
|
|
}
|
|
|
|
$input = $this->query('xpath:.//input[not(@type="hidden")]|textarea')->one();
|
|
$id = CXPathHelper::escapeQuotes($this->query('class:multiselect')->one()->getAttribute('id'));
|
|
foreach ($text as $value) {
|
|
$input->overwrite($value)->fireEvent('keyup');
|
|
|
|
if ($value === null || $value === '') {
|
|
continue;
|
|
}
|
|
|
|
$content = CXPathHelper::escapeQuotes($value);
|
|
$prefix = '//div[@data-opener='.$id.']/ul[@class="multiselect-suggest"]/li';
|
|
$query = $this->query('xpath', implode('|', [
|
|
$prefix.'[@data-label='.$content.']',
|
|
$prefix.'[contains(@data-label,'.$content.')]/span[contains(@class, "suggest-found") and text()='.$content.']',
|
|
$prefix.'[contains(@class, "suggest-new")]/span[text()='.$content.']'
|
|
]));
|
|
|
|
for ($i = 0; $i < 2; $i++) {
|
|
try {
|
|
$query->waitUntilPresent();
|
|
}
|
|
catch (TimeoutException $exception) {
|
|
if ($i === 0) {
|
|
$input->overwrite($value)->fireEvent('keyup');
|
|
}
|
|
else {
|
|
throw new Exception('Cannot find value with label "'.$value.'" in multiselect element.');
|
|
}
|
|
}
|
|
}
|
|
|
|
$query->one()->click();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function overwrite($text) {
|
|
return $this->clear()->type($text);
|
|
}
|
|
|
|
/**
|
|
* Alias for selectMultiple.
|
|
* @see self::selectMultiple
|
|
*
|
|
* @param array $labels array of label texts
|
|
* @param mixed $context overlay dialog context (hostgroup / host)
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function fill($labels, $context = null) {
|
|
if (!in_array($this->mode, [self::MODE_SELECT, self::MODE_SELECT_MULTIPLE, self::MODE_TYPE])) {
|
|
throw new Exception('Unknown fill mode is set for multiselect element.');
|
|
}
|
|
|
|
$this->clear();
|
|
|
|
// TODO: for loop and try/catch block should be removed after DEV-1535 is fixed.
|
|
for ($i = 0; $i < 2; $i++) {
|
|
try {
|
|
if ($context === null && is_array($labels)) {
|
|
if (array_key_exists('values', $labels)) {
|
|
if (array_key_exists('context', $labels)) {
|
|
$context = $labels['context'];
|
|
}
|
|
|
|
$labels = $labels['values'];
|
|
}
|
|
else {
|
|
foreach ($labels as $label) {
|
|
if (is_array($label) && array_key_exists('values', $label)) {
|
|
$context = (array_key_exists('context', $label)) ? $label['context'] : null;
|
|
$label = $label['values'];
|
|
}
|
|
|
|
if ($this->mode === self::MODE_SELECT) {
|
|
throw new Exception('Cannot select multiple items in single select mode.');
|
|
}
|
|
elseif ($this->mode === self::MODE_SELECT_MULTIPLE) {
|
|
$this->selectMultiple($label, $context);
|
|
}
|
|
else {
|
|
$this->type($label);
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
}
|
|
|
|
if ($this->mode === self::MODE_SELECT) {
|
|
return $this->select($labels, $context);
|
|
}
|
|
elseif ($this->mode === self::MODE_SELECT_MULTIPLE) {
|
|
return $this->selectMultiple($labels, $context);
|
|
}
|
|
|
|
return $this->type($labels);
|
|
}
|
|
catch (StaleElementReferenceException $exception) {
|
|
if ($i === 1) {
|
|
throw $exception;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function getValue() {
|
|
$selected = $this->getSelected();
|
|
if (is_array($selected) && count($selected) === 0) {
|
|
$selected = '';
|
|
}
|
|
|
|
return $selected;
|
|
}
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function isEnabled($enabled = true) {
|
|
$input = $this->query('xpath:.//input[not(@type="hidden")]|textarea')->one(false);
|
|
if (!$input->isEnabled($enabled)) {
|
|
return false;
|
|
}
|
|
|
|
$multiselect = $this->query('class:multiselect')->one(false);
|
|
if ($multiselect->isValid() && ($multiselect->getAttribute('aria-disabled') === 'true') === $enabled) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($this->getControls() as $control) {
|
|
if ($control->isEnabled() !== $enabled) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get list of suggested values.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getSuggestionsText() {
|
|
$id = CXPathHelper::escapeQuotes($this->query('class:multiselect')->one()->getAttribute('id'));
|
|
return $this->query('xpath://div[@data-opener='.$id.']/ul[@class="multiselect-suggest"]')->waitUntilVisible()
|
|
->query('xpath:./li[not(@class="suggest-hover")]')->all()->asText();
|
|
}
|
|
}
|