Commit ab4e4c62 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'master' into FE_Label-text-align_right

parents ee185670 4899392a
Pipeline #1336 passed with stage
in 2 minutes and 1 second
......@@ -2892,6 +2892,8 @@ See also at specific *FormElement* definitions.
| expectRecords | int | |
+------------------------+--------+ |
| messageFail | string | |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| dataSelenium | string | Optional. See `seleniumTest`_ |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
......@@ -5470,6 +5472,8 @@ Column: _link
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Class |c:[n|<text>] |c:text-muted |CSS class for link. n:no class attribute, <text>: explicit named |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Attribute |A:<key>="<value"> |A:data-selenium="person" |Custom attributes and a corresponding value. Might be used by Selenium tests. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Target |g:<text> |g:_blank |target=_blank,_self,_parent,<custom>. Default: no target |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Question |q:<text> |q:please confirm |See: `question`_. Link will be executed only if user clicks ok/cancel, default: 'Please confirm' |
......@@ -7522,20 +7526,43 @@ AutoCron / website: HTTPS protocol
* All certificates are accepted, even self signed without a correct chain or hostnames, not listed in the certificate.
This is useful if there is a general 'HTTP >> HTTPS' redirection configured and the website is accessed via `https://localhost/...`
.. _seleniumTest:
Selenium Test
=============
With https://www.seleniumhq.org/ it's possible to play and verify automate test cases. To simplify the process of automatically
identifying HTML elements, a tag might be assigned to elements which have to interact with the test framework.
Form
----
By default every FormElement contains an attribute 'data-selenium=<value>', whereas the '<value>' is either the name
of the FormElement or a custom value, defined via 'FormElement.parameter.dataSelenium=<value>'.
Report
------
Any HTML output can be extended by a tag. For QFQ generated links, an attribute like 'data-selenium' might be injected
via token 'A' (attribute). ::
SELECT 'p:personedit&form=person&r=1|b|s|A:data-selenium="person-edit"|t:Edit person' AS _link
.. _help:
General Tips
============
* Does the error happens on every *page* or only on specific one?
* Does the error happens on every *form* or only on specific one?
* Does the error happens on every *page* or only on a specific one?
* Does the error happens on every *form* or only on a specific one?
Tips:
* On general errors:
* Always check the Javascript console of your browser, see `javascriptProblem`_.
* Always check the Webserver logfiles.
* Always check the Webserver log files.
QFQ specific
------------
......
......@@ -1240,7 +1240,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]);
$attribute .= Support::doAttribute('name', $htmlFormElementName);
$attribute .= Support::doAttribute('class', $class);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
if (isset($formElement[FE_RETYPE_SOURCE_NAME])) {
$htmlFormElementNamePrimary = str_replace(RETYPE_FE_NAME_EXTENSION, '', $htmlFormElementName);
......@@ -1739,7 +1739,7 @@ abstract class AbstractBuildForm {
*
* @param array $formElement
* @param string $htmlFormElementName
* @param $attribute
* @param string $attribute
* @param string $value
* @param array $json
* @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
......@@ -1796,6 +1796,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('value', $formElement[FE_CHECKBOX_CHECKED], false);
$attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
$attribute .= Support::doAttribute(FE_INPUT_AUTOCOMPLETE, 'off');
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
$classActive = '';
if ($formElement[FE_CHECKBOX_CHECKED] === $value) {
......@@ -1855,6 +1856,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('name', $htmlFormElementName);
$attribute .= Support::doAttribute('value', $formElement[FE_CHECKBOX_CHECKED], false);
$attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
if ($formElement[FE_CHECKBOX_CHECKED] === $value) {
$attribute .= Support::doAttribute('checked', 'checked');
......@@ -1979,6 +1981,8 @@ abstract class AbstractBuildForm {
$htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, $ii);
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID] . '-' . $ii);
$attribute .= Support::doAttribute('name', $htmlFormElementNameUniq);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM] . '-' . $ii);
$attribute .= Support::doAttribute('value', $itemKey[$ii]);
......@@ -2053,6 +2057,7 @@ abstract class AbstractBuildForm {
$htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, $ii);
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID] . '-' . $ii);
$attribute .= Support::doAttribute('name', $htmlFormElementNameUniq);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM] . '-' . $ii);
// Do this only the first round.
if ($flagFirst) {
......@@ -2221,6 +2226,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID] . '-' . $ii);
$attribute .= Support::doAttribute('value', $itemKey[$ii], false); // Always set value, even to '' - #3832
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM] . '-' . $ii);
if ($itemKey[$ii] == $value) {
$attribute .= Support::doAttribute('checked', 'checked');
......@@ -2314,6 +2320,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID] . '-' . $ii);
$attribute .= Support::doAttribute('value', $itemKey[$ii], false); // Always set value, even to '' - #3832
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM] . '-' . $ii);
if ($itemKey[$ii] == $value) {
$attribute .= Support::doAttribute('checked', 'checked');
......@@ -2389,6 +2396,7 @@ abstract class AbstractBuildForm {
$attribute .= $this->getAttributeList($formElement, ['autofocus']);
$attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
$attribute .= $this->getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
if (isset($formElement[FE_SIZE]) && $formElement[FE_SIZE] > 1) {
$attribute .= Support::doAttribute('size', $formElement[FE_SIZE]);
......@@ -3045,6 +3053,7 @@ abstract class AbstractBuildForm {
$attribute .= $this->getAttributeList($formElement, [FE_AUTOFOCUS, FE_FILE_MIME_TYPE_ACCEPT]);
$attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
$attribute .= Support::doAttribute('data-sip', $sipUpload);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
$json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement); // Below, $formElement[FE_MODE]=FE_MODE_REQUIRED will be changed. Get the JSON unchanged
......@@ -3151,6 +3160,7 @@ abstract class AbstractBuildForm {
$attributeInput .= Support::doAttribute('name', $htmlFormElementName);
$attributeInput .= Support::doAttribute('type', 'hidden');
$attributeInput .= Support::doAttribute('value', htmlentities($value), false);
$attributeInput .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
$htmlInput = Support::wrapTag('<input ' . $attributeInput . ' >', '', false);
......@@ -3218,6 +3228,8 @@ abstract class AbstractBuildForm {
$attributeInput = Support::doAttribute('id', $htmlFabricId);
$attributeInput .= Support::doAttribute('name', $htmlFormElementName);
$attributeInput .= Support::doAttribute('type', 'hidden');
$attributeInput .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
$htmlInput = Support::wrapTag('<input ' . $attributeInput . ' >', '', false);
// <img id="target-png"> - this element is for future use. It's not necessary for the function and is not used yet.
......@@ -3275,6 +3287,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]);
$attribute .= Support::doAttribute('name', $htmlFormElementName);
$attribute .= Support::doAttribute('class', 'form-control');
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
$showTime = ($formElement[FE_TYPE] == 'time' || $formElement[FE_TYPE] == 'datetime') ? 1 : 0;
if ($value == 'CURRENT_TIMESTAMP') {
......@@ -3477,6 +3490,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]);
$attribute .= Support::doAttribute('name', $htmlFormElementName);
// $attribute .= Support::doAttribute('id', $htmlFormElementName);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
$attribute .= Support::doAttribute('class', 'qfq-tinymce');
$attribute .= Support::doAttribute('data-control-name', "$htmlFormElementName");
......@@ -3626,6 +3640,7 @@ abstract class AbstractBuildForm {
$json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement);
$attribute = Support::doAttribute('id', $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_INPUT);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
return Support::wrapTag("<div $attribute class='" . CLASS_NOTE . "'>", $value);
}
......@@ -3672,6 +3687,7 @@ abstract class AbstractBuildForm {
$attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]);
$attribute .= Support::doAttribute('name', $htmlFormElementName);
$attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
// <fieldset>
$html = '<fieldset ' . $attribute . '>';
......@@ -3803,6 +3819,7 @@ EOT;
$attribute .= Support::doAttribute('id', $targetName);
$attribute .= Support::doAttribute('data-qfq-line-template', '#' . $templateName);
$attribute .= Support::doAttribute('data-qfq-line-add-button', '#' . $addButtonId);
$attribute .= Support::doAttribute(SELENIUM_ATTRIBUTE_DATA, $formElement[FE_DATA_SELENIUM]);
// Element where the effective FormElements will be copied to. The BS 'col-md-* Classes are inside the template, not here. This here should be pure data without wrapping.
$html = Support::wrapTag("<div $attribute>", $html, false);
......
......@@ -987,6 +987,7 @@ const FE_SIZE = 'size';
const FE_SUBRECORD_OPTION = 'subrecordOption';
const FE_SQL1 = 'sql1';
const FE_PLACEHOLDER = 'placeholder';
const FE_DATA_SELENIUM = 'dataSelenium';
// FormElement columns: via parameter field
const FE_DATE_FORMAT = 'dateFormat'; // value: FORMAT_DATE_INTERNATIONAL | FORMAT_DATE_GERMAN
......@@ -1526,6 +1527,7 @@ const TOKEN_RIGHT = 'R';
const TOKEN_FILE = 'F';
const TOKEN_FILE_DEPRECATED = 'f'; // since 5.12.17
const TOKEN_DOWNLOAD_MODE = 'M';
const TOKEN_ATTRIBUTE = 'A';
const TOKEN_THUMBNAIL = 'T';
const TOKEN_THUMBNAIL_DIMENSION = 'W';
......@@ -1675,3 +1677,5 @@ const DND_SUBRECORD_ID = 'dnd-subrecord-id'; // Internal qualifier used to commu
const DND_SUBRECORD_FORM_ID = 'dnd-subrecord-form-id';
const DND_ORD_HTML_ID_PREFIX = 'qfq-dnd-ord-id-';
// SELENIUM
const SELENIUM_ATTRIBUTE_DATA = 'data-selenium';
\ No newline at end of file
......@@ -798,6 +798,8 @@ class Support {
self::setIfNotSet($formElement, FE_HTML_BEFORE);
self::setIfNotSet($formElement, FE_HTML_AFTER);
self::setIfNotSet($formElement, FE_DATA_SELENIUM, ($formElement[FE_NAME]=='' ? $formElement[FE_ID] : $formElement[FE_NAME]) );
self::setIfNotSet($formElement, FE_SUBRECORD_TABLE_CLASS, SUBRECORD_TABLE_CLASS_DEFAULT);
if (isset($formSpec[F_BS_LABEL_COLUMNS])) {
......
......@@ -34,6 +34,7 @@ require_once(__DIR__ . '/Thumbnail.php');
/*
* a:AltText
* A:Attribute
* b:bootstrap [0|1|<button>]
* B:bullet
* c:class [n|i|e|<class>]
......@@ -103,6 +104,7 @@ const NAME_THUMBNAIL = 'thumbnail';
const NAME_THUMBNAIL_DIMENSION = 'thumbnailDimension';
const NAME_COPY_TO_CLIPBOARD = 'copyToClipBoard';
const NAME_MONITOR = 'monitor';
const NAME_ATTRIBUTE = 'attribute';
const FINAL_HREF = 'finalHref';
const FINAL_ANCHOR = 'finalAnchor';
......@@ -221,6 +223,7 @@ class Link {
TOKEN_THUMBNAIL => NAME_THUMBNAIL,
TOKEN_THUMBNAIL_DIMENSION => NAME_THUMBNAIL_DIMENSION,
TOKEN_COPY_TO_CLIPBOARD => NAME_COPY_TO_CLIPBOARD,
TOKEN_ATTRIBUTE => NAME_ATTRIBUTE,
TOKEN_MONITOR => NAME_MONITOR,
// The following don't need a renaming: already 'long'
......@@ -351,11 +354,14 @@ class Link {
private function wrapLinkTextOnly(array $vars, $keyName) {
$text = $vars[$keyName];
if ($vars[NAME_BOOTSTRAP_BUTTON] == '' && $vars[FINAL_TOOL_TIP] == '') {
if ($vars[NAME_BOOTSTRAP_BUTTON] == '' && $vars[FINAL_TOOL_TIP] == '' && $vars[NAME_ATTRIBUTE] == '') {
return $text;
}
$attributes = Support::doAttribute('title', $vars[FINAL_TOOL_TIP]);
if ($vars[NAME_ATTRIBUTE] != '') {
$attributes .= $vars[NAME_ATTRIBUTE] . ' ';
}
if ($vars[NAME_BOOTSTRAP_BUTTON] != '') {
$attributes .= Support::doAttribute('class', [$vars[NAME_BOOTSTRAP_BUTTON], 'disabled']);
......@@ -1128,6 +1134,9 @@ EOF;
$attributes .= Support::doAttribute('class', $vars[FINAL_CLASS]);
$attributes .= Support::doAttribute('target', $vars[NAME_TARGET]);
$attributes .= Support::doAttribute('title', $vars[FINAL_TOOL_TIP]);
if ($vars[NAME_ATTRIBUTE] != '') {
$attributes .= $vars[NAME_ATTRIBUTE] . ' ';
}
$attributes .= $vars[FINAL_QUESTION];
$anchor = '<a ' . $attributes . '>';
......@@ -1460,7 +1469,7 @@ EOF;
if ($vars[NAME_COPY_TO_CLIPBOARD] !== '') {
$jsAction = 'onClick';
// Take care that ' and " are properly escaped
$source = json_encode(["text" => $vars[NAME_COPY_TO_CLIPBOARD]], JSON_HEX_QUOT|JSON_HEX_APOS);
$source = json_encode(["text" => $vars[NAME_COPY_TO_CLIPBOARD]], JSON_HEX_QUOT | JSON_HEX_APOS);
} elseif (isset($vars[NAME_COLLECT_ELEMENTS][0])) {
$jsAction = 'onmousedown';
......@@ -1476,7 +1485,7 @@ EOF;
$vars[NAME_TOOL_TIP] .= PHP_EOL . PHP_EOL . $this->sip->debugSip($paramArray);
}
$source = json_encode(['uri' => API_DIR . '/' . API_DOWNLOAD_PHP . '?s=' . $paramArray[SIP_SIP] ]);
$source = json_encode(['uri' => API_DIR . '/' . API_DOWNLOAD_PHP . '?s=' . $paramArray[SIP_SIP]]);
} else {
throw new UserReportException("Missing content for 'copy to clipboard'", ERROR_MISSING_CONTENT);
}
......
......@@ -983,7 +983,6 @@ class LinkTest extends TestCase {
}
/**
*
* @throws CodeException
* @throws UserFormException
* @throws UserReportException
......@@ -1006,6 +1005,28 @@ class LinkTest extends TestCase {
}
/**
* @throws CodeException
* @throws UserFormException
* @throws UserReportException
*/
public function testAttribute() {
$link = new Link($this->sip, DB_INDEX_DEFAULT, true);
// Standard
$result = $link->renderLink('p:editperson|A:data-selenium="editperson"');
$this->assertEquals('<a href="?id=editperson" data-selenium="editperson" >?id=editperson</a>', $result);
// BS Button & SIP
$result = $link->renderLink('p:editperson|A:data-selenium="editperson"|b|s');
$this->assertEquals('<a href="index.php?id=editperson&s=badcaffee1234" class="btn btn-default" data-selenium="editperson" >index.php?id=editperson&s=badcaffee1234</a>', $result);
// Render mode 3 (disabled)
$result = $link->renderLink('p:editperson|A:data-selenium="editperson"|r:3');
$this->assertEquals('<span data-selenium="editperson" >?id=editperson</span>', $result);
}
/**
*
* @throws CodeException
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment