Commit 47fa3b4a authored by Carsten  Rose's avatar Carsten Rose
Browse files

[NOTE] Feature #4431 / FE.type=note: QFQ Report Syntax in 'FE.value' and 'FE.note'

Manual.rst: describe how to activate 'report' syntax.
Support.php: implement 'unWrapTag()'
Report: Code reformat
FillStoreForm.php: remove unwanted '<p>' tag around content if TinyMCE is used, before saving the content
AbstractBuildForm.php: new processReportSyntax().
formEditor.sql: Change FormElement Editor column 'note' from Editor (TinyMCE) to ordinary TextArea. This was necessary cause TinyMCE is based on HTML and linebreaks are completely replaced by <br>. It's difficult to support both, HTML and plain text at the same time.
parent 3f7d0b5b
...@@ -2185,6 +2185,20 @@ to edit, on the same form, a corresponding person email address (which is in a s ...@@ -2185,6 +2185,20 @@ to edit, on the same form, a corresponding person email address (which is in a s
{{SELECT a.email FROM Address AS a WHERE a.pId={{id:R0}} ORDER BY a.id LIMIT 1}} {{SELECT a.email FROM Address AS a WHERE a.pId={{id:R0}} ORDER BY a.id LIMIT 1}}
FE: 'Report' notation
^^^^^^^^^^^^^^^^^^^^^
The FE fields 'value' and 'note' understand the `Report`_ syntax. Nested SQL queries as well as links with SIP encoding
are possible. To distinguish between 'Form' and 'Report' syntax, the first line has to be `#!report` ::
#!report
10.sql = SELECT ...
20 {
sql = SELECT ...
5.sql = SELECT ...
}
.. _fe-parameter-attributes: .. _fe-parameter-attributes:
......
...@@ -16,6 +16,8 @@ use qfq; ...@@ -16,6 +16,8 @@ use qfq;
require_once(__DIR__ . '/store/Store.php'); require_once(__DIR__ . '/store/Store.php');
require_once(__DIR__ . '/Constants.php'); require_once(__DIR__ . '/Constants.php');
require_once(__DIR__ . '/Evaluate.php');
require_once(__DIR__ . '/BodytextParser.php');
require_once(__DIR__ . '/exceptions/DbException.php'); require_once(__DIR__ . '/exceptions/DbException.php');
require_once(__DIR__ . '/exceptions/UserFormException.php'); require_once(__DIR__ . '/exceptions/UserFormException.php');
require_once(__DIR__ . '/database/Database.php'); require_once(__DIR__ . '/database/Database.php');
...@@ -24,6 +26,7 @@ require_once(__DIR__ . '/helper/Support.php'); ...@@ -24,6 +26,7 @@ require_once(__DIR__ . '/helper/Support.php');
require_once(__DIR__ . '/helper/OnArray.php'); require_once(__DIR__ . '/helper/OnArray.php');
require_once(__DIR__ . '/helper/Ldap.php'); require_once(__DIR__ . '/helper/Ldap.php');
require_once(__DIR__ . '/report/Link.php'); require_once(__DIR__ . '/report/Link.php');
require_once(__DIR__ . '/report/Report.php');
/** /**
* Class AbstractBuildForm * Class AbstractBuildForm
...@@ -58,6 +61,14 @@ abstract class AbstractBuildForm { ...@@ -58,6 +61,14 @@ abstract class AbstractBuildForm {
* @var Sip * @var Sip
*/ */
private $sip = null; private $sip = null;
/**
* @var Report
*/
private $report = null;
/**
* @var BodytextParser
*/
private $bodytextParser = null;
/** /**
* AbstractBuildForm constructor. * AbstractBuildForm constructor.
...@@ -434,6 +445,25 @@ abstract class AbstractBuildForm { ...@@ -434,6 +445,25 @@ abstract class AbstractBuildForm {
abstract public function getProcessFilter(); abstract public function getProcessFilter();
private function processReportSyntax($value) {
if (substr($value, 0, 8) == SHEBANG_REPORT) {
if ($this->report === null) {
$this->report = new Report(array(), $this->evaluate, false);
}
if ($this->bodytextParser === null) {
$this->bodytextParser = new BodytextParser();
}
$value = $this->report->process($this->bodytextParser->process($value));
}
return $value;
}
/** /**
* Process all FormElements in $this->feSpecNative: Collect and return all HTML code & JSON. * Process all FormElements in $this->feSpecNative: Collect and return all HTML code & JSON.
* *
...@@ -502,6 +532,9 @@ abstract class AbstractBuildForm { ...@@ -502,6 +532,9 @@ abstract class AbstractBuildForm {
$this->store->setVar(VAR_SLAVE_ID, $slaveId, STORE_VAR); $this->store->setVar(VAR_SLAVE_ID, $slaveId, STORE_VAR);
} }
$fe[FE_VALUE] = $this->processReportSyntax($fe[FE_VALUE]);
$fe[FE_NOTE] = $this->processReportSyntax($fe[FE_NOTE]);
// ** evaluate current FormElement ** // ** evaluate current FormElement **
$formElement = $this->evaluate->parseArray($fe, $skip, $debugStack); $formElement = $this->evaluate->parseArray($fe, $skip, $debugStack);
$formElement = HelperFormElement::setLanguage($formElement, $parameterLanguageFieldName); $formElement = HelperFormElement::setLanguage($formElement, $parameterLanguageFieldName);
...@@ -515,7 +548,6 @@ abstract class AbstractBuildForm { ...@@ -515,7 +548,6 @@ abstract class AbstractBuildForm {
// $fe[FE_MODE_SQL] = ''; // $fe[FE_MODE_SQL] = '';
// } // }
if ($flagOutput === true) { if ($flagOutput === true) {
$this->fillWrapLabelInputNote($formElement[FE_BS_LABEL_COLUMNS], $formElement[FE_BS_INPUT_COLUMNS], $formElement[FE_BS_NOTE_COLUMNS]); $this->fillWrapLabelInputNote($formElement[FE_BS_LABEL_COLUMNS], $formElement[FE_BS_INPUT_COLUMNS], $formElement[FE_BS_NOTE_COLUMNS]);
} }
......
...@@ -953,6 +953,8 @@ const FE_TYPE_PASTE = 'paste'; ...@@ -953,6 +953,8 @@ const FE_TYPE_PASTE = 'paste';
const FE_TYPE_TEMPLATE_GROUP = 'templateGroup'; const FE_TYPE_TEMPLATE_GROUP = 'templateGroup';
const SHEBANG_REPORT = '#!report';
// SUPPORT // SUPPORT
const PARAM_T3_ALL = 't3 all'; const PARAM_T3_ALL = 't3 all';
const PARAM_T3_NO_ID = "t3 no id"; const PARAM_T3_NO_ID = "t3 no id";
......
...@@ -98,6 +98,37 @@ class Support { ...@@ -98,6 +98,37 @@ class Support {
return $tag . $value . $closing; return $tag . $value . $closing;
} }
/**
* Removes '$tag' and closing $tag from $value, if they are the outermost.
* E.g. unWrapTag('<p>', '<p>Hello World</p>') returns 'Hello World'
*
* @param string $tag
* @param string $value
*
* @return string
*/
public static function unWrapTag($tag, $value) {
if ($tag == '' || $value == '') {
return $value;
}
$lenTag = strlen($tag);
$lenValue = strlen($value);
if ($lenValue < $lenTag + $lenTag + 1) {
return $value;
}
$closeTag = $tag[0] . '/' . substr($tag, 1);
if (substr($value, 0, $lenTag) == $tag && substr($value, $lenValue - $lenTag - 1) == $closeTag) {
$value = substr($value, $lenTag, $lenValue - $lenTag - $lenTag - 1);
}
return $value;
}
/** /**
* Wraps some $inner fragment with a CSS styled $tooltipText . CSS is configured in 'Resources/Public/qfq-jqw.css'. * Wraps some $inner fragment with a CSS styled $tooltipText . CSS is configured in 'Resources/Public/qfq-jqw.css'.
* *
......
...@@ -199,15 +199,17 @@ class Report { ...@@ -199,15 +199,17 @@ class Report {
$arr = explode("=", trim($ttLine), 2); $arr = explode("=", trim($ttLine), 2);
// no elements or only one: do nothing // no elements or only one: do nothing
if (count($arr) < 2) if (count($arr) < 2) {
return; return;
}
// 10.50.5.sql // 10.50.5.sql
$key = strtolower(trim($arr[0])); $key = strtolower(trim($arr[0]));
// comment ? // comment ?
if (empty($key) || $key[0] === "#") if (empty($key) || $key[0] === "#") {
return; return;
}
// select ... // select ...
$value = trim($arr[1]); $value = trim($arr[1]);
...@@ -259,11 +261,12 @@ class Report { ...@@ -259,11 +261,12 @@ class Report {
if ($frCmd === TOKEN_SQL) { if ($frCmd === TOKEN_SQL) {
$arr = explode('|', TOKEN_VALID_LIST); $arr = explode('|', TOKEN_VALID_LIST);
foreach ($arr as $key) { foreach ($arr as $key) {
if (!isset($this->frArray[$level . "." . $key])) if (!isset($this->frArray[$level . "." . $key])) {
$this->frArray[$level . "." . $key] = ''; $this->frArray[$level . "." . $key] = '';
} }
} }
} }
}
/** /**
* Sorts the associative array. * Sorts the associative array.
...@@ -439,8 +442,9 @@ class Report { ...@@ -439,8 +442,9 @@ class Report {
} }
// HEAD: If there is at least one record, do 'head'. // HEAD: If there is at least one record, do 'head'.
if ($rowTotal > 0) if ($rowTotal > 0) {
$content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_HEAD]); $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_HEAD]);
}
// Prepare row alteration // Prepare row alteration
$arrRbgd = explode("|", $this->frArray[$full_level . "." . TOKEN_RBGD]); $arrRbgd = explode("|", $this->frArray[$full_level . "." . TOKEN_RBGD]);
...@@ -713,7 +717,9 @@ class Report { ...@@ -713,7 +717,9 @@ class Report {
$t1 = explode("@", $mailarr[0], 2); $t1 = explode("@", $mailarr[0], 2);
$content .= "<script language=javascript><!--" . chr(10); $content .= "<script language=javascript><!--" . chr(10);
if (empty($mailarr[1])) $mailarr[1] = $mailarr[0]; if (empty($mailarr[1])) {
$mailarr[1] = $mailarr[0];
}
$content .= 'var contact = "' . substr($mailarr[1], 0, 2) . '"' . chr(10); $content .= 'var contact = "' . substr($mailarr[1], 0, 2) . '"' . chr(10);
$content .= 'var contact1 = "' . substr($mailarr[1], 2) . '"' . chr(10); $content .= 'var contact1 = "' . substr($mailarr[1], 2) . '"' . chr(10);
...@@ -833,8 +839,9 @@ class Report { ...@@ -833,8 +839,9 @@ class Report {
exec($cmd, $arr, $rc); exec($cmd, $arr, $rc);
$output = implode('<BR>', $arr); $output = implode('<BR>', $arr);
if ($rc != 0) if ($rc != 0) {
$output = $rc . " - " . $output; $output = $rc . " - " . $output;
}
return ($output); return ($output);
} }
......
...@@ -216,15 +216,21 @@ class FillStoreForm { ...@@ -216,15 +216,21 @@ class FillStoreForm {
if (isset($clientValues[$clientFieldName])) { if (isset($clientValues[$clientFieldName])) {
if ($formElement[FE_DYNAMIC_UPDATE] === 'yes' || $formElement[FE_MODE] === FE_MODE_REQUIRED || $formElement[FE_MODE] === FE_MODE_SHOW) { if ($formElement[FE_DYNAMIC_UPDATE] === 'yes' || $formElement[FE_MODE] === FE_MODE_REQUIRED || $formElement[FE_MODE] === FE_MODE_SHOW) {
switch ($formElement[FE_TYPE]) { switch ($formElement[FE_TYPE]) {
case 'date': case FE_TYPE_DATE:
case 'datetime': case FE_TYPE_DATETIME:
case 'time': case FE_TYPE_TIME:
if ($clientValues[$clientFieldName] !== '') // do not check empty values if ($clientValues[$clientFieldName] !== '') // do not check empty values
$newValues[$formElement[FE_NAME]] = $this->doDateTime($formElement, $clientValues[$clientFieldName]); $newValues[$formElement[FE_NAME]] = $this->doDateTime($formElement, $clientValues[$clientFieldName]);
break; break;
default: default:
$val = $clientValues[$clientFieldName]; $val = $clientValues[$clientFieldName];
// Check only if their is something
if ($formElement[FE_TYPE] == FE_TYPE_EDITOR) {
// Tiny MCE always wrap a '<p>' around the content. Remove it before saving.
$val = Support::unWrapTag('<p>', $val);
}
// Check only if their is something.
if ($val !== '') { if ($val !== '') {
$val = Sanitize::sanitize($val, $formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN], SANITIZE_EXCEPTION); $val = Sanitize::sanitize($val, $formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN], SANITIZE_EXCEPTION);
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) { if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) {
......
...@@ -332,9 +332,7 @@ VALUES ...@@ -332,9 +332,7 @@ VALUES
(2, 'bsNoteColumns', 'BS Note Columns', 'show', 'text', 'all', 'native', 430, 0, 0, '', '', '', '', '', 102, '', 'no', '', '', '', '', '{{bsNoteColumns:Y}}', 'specialchar'), (2, 'bsNoteColumns', 'BS Note Columns', 'show', 'text', 'all', 'native', 430, 0, 0, '', '', '', '', '', 102, '', 'no', '', '', '', '', '{{bsNoteColumns:Y}}', 'specialchar'),
(2, 'rowLabelInputNote', 'Label / Input / Note', 'show', 'checkbox', 'alnumx', 'native', 440, 0, 10, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-rowLabelInputNote">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'specialchar'), (2, 'rowLabelInputNote', 'Label / Input / Note', 'show', 'checkbox', 'alnumx', 'native', 440, 0, 10, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-rowLabelInputNote">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'specialchar'),
(2, 'maxLength', 'Maxlength', 'show', 'text', 'all', 'native', 450, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-maxLength">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'specialchar'), (2, 'maxLength', 'Maxlength', 'show', 'text', 'all', 'native', 450, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-maxLength">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'specialchar'),
(2, 'note', 'Note', 'show', 'editor', 'all', 'native', 460, '', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-note">Info</a>', '', '', '', (2, 'note', 'Note', 'show', 'text', 'all', 'native', 460, '40,5', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-note">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'),
'editor-plugins=code link table textcolor textpattern\neditor-toolbar=code | styleselect link table | bullist numlist | forecolor backcolor bold italic\neditor-menubar=false\neditor-statusbar=false',
102, '', 'no', '', '', '', '', '', 'none'),
(2, 'tooltip', 'Tooltip', 'show', 'text', 'all', 'native', 470, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-tooltip">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'), (2, 'tooltip', 'Tooltip', 'show', 'text', 'all', 'native', 470, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-tooltip">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'),
(2, 'placeholder', 'Placeholder', 'show', 'text', 'all', 'native', 480, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-placeholder">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'), (2, 'placeholder', 'Placeholder', 'show', 'text', 'all', 'native', 480, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-placeholder">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'),
(2, 'value', 'value', 'show', 'text', 'all', 'native', 500, '40,2', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-value">Info</a>', '', '', '', '', 103, '', 'no', '', '', '', '', '', 'none'), (2, 'value', 'value', 'show', 'text', 'all', 'native', 500, '40,2', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-value">Info</a>', '', '', '', '', 103, '', 'no', '', '', '', '', '', 'none'),
...@@ -354,6 +352,8 @@ VALUES ...@@ -354,6 +352,8 @@ VALUES
(2, 'created', 'Created', 'readonly', 'text', 'all', 'native', 640, 0, 20, '', '', '', '', '', 104, '', 'no', '', (2, 'created', 'Created', 'readonly', 'text', 'all', 'native', 640, 0, 20, '', '', '', '', '', 104, '', 'no', '',
'', '', '', '', 'specialchar'); '', '', '', '', 'specialchar');
#(2, 'note', 'Note', 'show', 'editor', 'all', 'native', 460, '', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-note">Info</a>', '', '', '',
#'editor-plugins=code link table textcolor textpattern\neditor-toolbar=code | styleselect link table | bullist numlist | forecolor backcolor bold italic\neditor-menubar=false\neditor-statusbar=false',
# ---------------------------------------- # ----------------------------------------
# MailLog # MailLog
......
...@@ -559,6 +559,14 @@ class SupportTest extends \PHPUnit_Framework_TestCase { ...@@ -559,6 +559,14 @@ class SupportTest extends \PHPUnit_Framework_TestCase {
} }
public function testUnWrapTag() {
$this->assertEquals('', Support::unWrapTag('', ''));
$this->assertEquals('', Support::unWrapTag('<p>', ''));
$this->assertEquals('Hello World', Support::unWrapTag('<p>', 'Hello World'));
$this->assertEquals('Hello World', Support::unWrapTag('<p>', '<p>Hello World</p>'));
}
protected function setUp() { protected function setUp() {
parent::setUp(); parent::setUp();
......
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