Commit d7d306d3 authored by Rafael Ostertag's avatar Rafael Ostertag
Browse files

Merge remote-tracking branch 'origin/crose_work' into raos_work

parents f47ccede 45987768
......@@ -6,13 +6,19 @@ Neue Versionsnummer
* extension/Documentation/_make/conf.py: release, version
* extension/Documentation/Settings.yml: version
* extension/ext_emconf.php: version
* extension/RELEASE.txt
2) Im Projektverzeichnis:
make t3sphinx (dadurch fallen Fehler in RESTdoc Syntax auf)
2) Im Projectverzeichnis:
make t3sphinx (nicht sicher ob das noetig ist)
3) Merge auf master Branch
git checkout master
git merge crose_work
4) Neuen Tag vergeben: git tag 0.8
4) Neuen Tag vergeben: git tag 0.10
5) Alle Files, inkl. Tags, in GIT einchecken.
......@@ -20,6 +26,7 @@ Neue Versionsnummer
7) In T3 Instanz Dokumentation rendern lassen.
T3 6.2: Admin Tools > Extension Manager > QFQ > Doku HTML: rechts oben 'Render Documentation'
T3 6.2: Admin Tools > Extension Manager > QFQ > Doku HTML: rechts oben 'Render Documentation'
Note
\ No newline at end of file
......@@ -6,8 +6,8 @@
conf.py:
copyright: 2017
project: QFQ Extension
version: 0.8
release: 0.8.0
version: 0.10
release: 0.10.0
latex_documents:
- - Index
- qfq.tex
......
......@@ -59,7 +59,7 @@ copyright = u'2017, Carsten Rose'
# The short X.Y version.
version = '0.8'
# The full version, including alpha/beta/rc tags.
release = '0.8.0'
release = '0.10.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
Version 0.10
============
Features
--------
* Implemented Parameter 'extraDeleteForm' for 'forms' and 'subrecords'. Update doc.
Bug fixes
---------
* Suppress rendering of form title during a 'delete' call. No one will see it and required parameters are not supplied.
* In case of broken SQL queries, print them in ajax error message.
* Remove parameter 'table' from Delete SIP URLs. ToolTip updated.
Version 0.9
===========
Features
--------
* FormEditor:
* design update - new default background color: grey.
* per form configureable background colors.
* Optional right align of all form element labels.
* Added config.qfq.ini values CSS_CLASS_QFQ_FORM_PILL, CSS_CLASS_QFQ_FORM_BODY, CSS_CLASS_QFQ_CONTAINER.
Bug fixes
---------
* BuildFormBootstrap.php: added new class name 'qfq-label' to form labels - needed to assign 'qfq-form-right' class. Changed wrapping of formelements from 'col-md-8' (wrong) to 'col-md-12'.
* QuickFormQuery.php: Set default for new F_CLASS_PILL & F_CLASS_BODY.
* formEditor.sql: New default background color for formElements is blue.
* qfq-bs.css.less: add classes qfq-form-pill, qfq-form-body, form-group (center), qfq-color-*, qfq-form-right.
* Index.rst: Add note to hierachy chars. Fixed uncomplete doc to a) bs*Columns, showButton. Add classPill, classBody. Rewrote form.paramter.class.
* QuickFormQuery.php: Button save/ close/ delete/ new - align to right border of form.
* UsersManual/index.rst: renamed chapter for formelements. Cleanup formelement types. Wrote chapter 'Detailed concept'.
* QuickFormQuery.php, FormAction.php: '#2931 / afterSave Hauptrecord xId nicht direkt verfügbar' - load master record again, after 'action'-elements has been processed.
* UsersManual/index.rst: Startet FAQ section.
* config.qfq.example.ini: Added comment where to save config.qfq.ini.
* UsersManual/index.rst: Rewrite of 'action'-FormElement definition.
* #2739: beforeDelete / afterDelete.
* PROTOCOL.md: update 'delete' description.
* delete.php: fixed unwanted loose of MSG_CONTENT.
* Report.php: Fixed double '&&' in building UrlParam.
* FormAction.php: In case of 'AFTER_DELETE', do not try to load primary record - that one is already deleted.
* Sip.php: Do not skip SIP_TARGET_URL as parameter for the SIP.
* #3001 Report: delete implementieren.
* Index.rst, Constants.php: reverted parameter '_table' in delete links back to 'table' - Reason: 'form' needs to be 'form' (instead of '_form') due to many used places already.
* Sip.php: move SIP_TARGET_URL back to stored inside SIP - it's necessary for 'delete'-links.
* Report.php, Constants.php: Remove code to handle unecessary 'p:' tag for delete links.
* Link.php: Check paged / Paged that the parameter r, table and form are given in the right combination.
* Link.php, Report.php: New '_link' token 'x'. '_paged' and '_Paged' are rendered via Link() class, Link() class now supports delete links.
* QuickFormQuery.php: for modeForm='Form Delete' the 'required param' are not respected - this makes sense, cause these parameters typically filled in newly created records.
* Fixed: #3076 Delete Button bei Subrecords erzeugt sporadisch Javascript Exceptions (Webkit: Chrome / Vivaldi) - kein loeschen moeglich.
\ No newline at end of file
......@@ -10,5 +10,5 @@ $EM_CONF[$_EXTKEY] = array(
'dependencies' => 'fluid,extbase',
'clearcacheonload' => true,
'state' => 'alpha',
'version' => '0.8'
'version' => '0.10'
);
\ No newline at end of file
......@@ -349,6 +349,9 @@ abstract class AbstractBuildForm {
$this->store->setVarArray($row, STORE_RECORD);
}
$this->checkAutoFocus();
// Iterate over all FormElements
foreach ($this->feSpecNative as $fe) {
......@@ -436,6 +439,55 @@ abstract class AbstractBuildForm {
return $html;
}
/**
* Check if there is an explicit 'autofocus' definition in at least one FE.
* Found: do nothing, it will be rendered at the correct position.
* Not found: set 'autofocus' on the first FE.
*
* Accepted misbehaviour on forms with pills: if there is at least one editable element on the first pill,
* the other pills are not checked - independent if there was a definition on the first pill or not.
* Reason: checks happens per pill - if there is no explizit definition on the first pill, take the first editable
* element of that pill.
*/
private function checkAutoFocus() {
static $found = false;
$idx = false;
if ($found) {
return;
}
// Search if there is an explicit autofocus definition.
for ($i = 0; $i < count($this->feSpecNative); ++$i) {
// Only check native elements which will be shown
if ($this->feSpecNative[$i][FE_CLASS] == FE_CLASS_NATIVE &&
($this->feSpecNative[$i][FE_MODE] == FE_MODE_SHOW || $this->feSpecNative[$i][FE_MODE] == FE_MODE_REQUIRED)
) {
// Check if there is an explicit definition.
if (isset($this->feSpecNative[$i][FE_AUTOFOCUS])) {
if ($this->feSpecNative[$i][FE_AUTOFOCUS] == '' || $this->feSpecNative[$i][FE_AUTOFOCUS] == '1') {
$this->feSpecNative[$i][FE_AUTOFOCUS] = '1'; // fix to '=1'
} else {
unset($this->feSpecNative[$i][FE_AUTOFOCUS]);
}
$found = true;
return;
}
if ($idx === false) {
$idx = $i;
}
}
}
// No explicit definition found: take the first found editable element.
if ($idx !== false) {
$found = true;
// No explicit definition found: set autofocus.
$this->feSpecNative[$idx][FE_AUTOFOCUS] = '1';
}
}
abstract public function fillWrapLabelInputNote($label, $input, $note);
abstract public function tail();
......@@ -1403,6 +1455,9 @@ abstract class AbstractBuildForm {
if (isset($formElement[SUBRECORD_PARAMETER_FORM])) {
Support::setIfNotSet($formElement, F_EXTRA_DELETE_FORM, '');
$formElement[F_FINAL_DELETE_FORM] = $formElement[F_EXTRA_DELETE_FORM] != '' ? $formElement[F_EXTRA_DELETE_FORM] : $formElement[SUBRECORD_PARAMETER_FORM];
$linkNew = Support::wrapTag('<th>', $this->createFormLink($formElement, 0, $primaryRecord, $this->symbol[SYMBOL_NEW], 'New'));
// Decode settings in subrecordOption
......@@ -1423,8 +1478,9 @@ abstract class AbstractBuildForm {
$columns .= '<th>' . implode('</th><th>', $control['title']) . '</th>';
}
if ($flagDelete)
if ($flagDelete) {
$columns .= '<th></th>';
}
// Table head
$html = Support::wrapTag('<tr>', $columns);
......@@ -1449,17 +1505,16 @@ abstract class AbstractBuildForm {
$toolTip = 'Delete';
if ($this->showDebugInfo) {
$toolTip .= PHP_EOL . "form = '" . $this->formSpec[F_NAME] . "'" . PHP_EOL . "table = '" . $this->formSpec[F_TABLE_NAME] . "'" . PHP_EOL . "r = '" . $row[$nameColumnId] . "'";
$toolTip .= PHP_EOL . "form = '" . $formElement[F_FINAL_DELETE_FORM] . "'" . PHP_EOL . "r = '" . $row[$nameColumnId] . "'";
}
// $buttonDelete = $this->buildButtonCode('delete-button', $toolTip, GLYPH_ICON_DELETE, $disabled);
$s = $this->createDeleteUrl($formElement[SUBRECORD_PARAMETER_FORM], $targetTableName, $row[$nameColumnId], RETURN_SIP);
$s = $this->createDeleteUrl($formElement[F_FINAL_DELETE_FORM], '', $row[$nameColumnId], RETURN_SIP);
// $rowHtml .= Support::wrapTag('<td>', Support::wrapTag("<button type='button' class='record-delete btn btn-default' data-sip='$s'>", '<span class="glyphicon ' . GLYPH_ICON_DELETE . '"></span>'));
$rowHtml .= Support::wrapTag('<td>', Support::wrapTag("<button type='button' class='record-delete btn btn-default' data-sip='$s' " . Support::doAttribute('title', $toolTip) . ">", '<span class="glyphicon ' . GLYPH_ICON_DELETE . '"></span>'));
}
Support::setIfNotSet($row, FE_SUBRECORD_ROW_CLASS);
......@@ -1753,15 +1808,19 @@ abstract class AbstractBuildForm {
*/
public function createDeleteUrl($formName, $tableName, $recordId, $mode = RETURN_URL) {
//TODO: Umstellen auf Benutzung der Link Klasse.
$queryStringArray = [
SIP_FORM => $formName,
SIP_TABLE => $tableName,
SIP_RECORD_ID => $recordId,
SIP_MODE_ANSWER => MODE_JSON
];
if ($formName !== '') {
$queryStringArray[SIP_FORM] = $formName;
}
if ($tableName !== '') {
$queryStringArray[SIP_TABLE] = $tableName;
}
$queryString = Support::arrayToQueryString($queryStringArray);
$sip = $this->store->getSipInstance();
......
......@@ -158,10 +158,6 @@ class BuildFormBootstrap extends AbstractBuildForm {
if (Support::findInSet(FORM_BUTTON_CLOSE, $this->formSpec['showButton'])) {
$toolTip = 'Close';
if ($this->showDebugInfo) {
$toolTip .= PHP_EOL . "table = '" . $this->formSpec[F_TABLE_NAME] . "'" . PHP_EOL . "r = '" . $recordId . "'";
}
$buttonClose = $this->buildButtonCode('close-button', 'Close', GLYPH_ICON_CLOSE);
}
......@@ -170,7 +166,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
$toolTip = 'Delete';
if ($this->showDebugInfo && $recordId > 0) {
$toolTip .= PHP_EOL . "form = '" . $this->formSpec[F_NAME] . "'" . PHP_EOL . "table = '" . $this->formSpec[F_TABLE_NAME] . "'" . PHP_EOL . "r = '" . $recordId . "'";
$toolTip .= PHP_EOL . "form = '" . $this->formSpec[F_FINAL_DELETE_FORM] . "'" . PHP_EOL . "r = '" . $recordId . "'";
}
$disabled = ($recordId > 0) ? '' : 'disabled';
......@@ -345,7 +341,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
$tabId = $this->getTabId();
if (0 < ($recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP))) {
$deleteUrl = $this->createDeleteUrl($this->formSpec[F_NAME], $this->formSpec[F_TABLE_NAME], $recordId);
$deleteUrl = $this->createDeleteUrl($this->formSpec[F_FINAL_DELETE_FORM], '', $recordId);
}
$actionUpload = FILE_ACTION . '=' . FILE_ACTION_UPLOAD;
......
......@@ -77,7 +77,7 @@ class BuildFormTable extends AbstractBuildForm {
$formEditUrl = $this->createFormEditUrl();
$html .= "<p><a " . Support::doAttribute('href', $formEditUrl) . ">Edit</a><small>[$sipParamString]</small></p>";
$deleteUrl = $this->createDeleteUrl($this->formSpec[F_NAME], $this->formSpec[F_TABLE_NAME], $this->store->getVar(SIP_RECORD_ID, STORE_SIP));
$deleteUrl = $this->createDeleteUrl($this->formSpec[F_FINAL_DELETE_FORM], '', $this->store->getVar(SIP_RECORD_ID, STORE_SIP));
$html .= "<p><a " . Support::doAttribute('href', $deleteUrl) . ">Delete</a>";
$html .= $this->wrapItem(WRAP_SETUP_TITLE, $this->formSpec['title'], true);
......
......@@ -379,6 +379,7 @@ const TOKEN_VALID_LIST = 'sql|head|althead|tail|rbeg|rend|renr|rsep|fbeg|fend|fs
// SQL logging Modes
const SQL_LOG_MODE_ALL = 'all';
const SQL_LOG_MODE_MODIFY = 'modify';
const SQL_LOG_MODE_ERROR = 'error'; // write log entry, independent of global setting (e.g. broken Query)
// api/save.php, api/delete.php, api/load.php
const API_DELETE_PHP = 'delete.php';
......@@ -443,8 +444,11 @@ const GLYPH_ICON_CLOSE = 'glyphicon-remove';
// FORM
const F_NAME = 'name';
const F_TITLE = 'title';
const F_TABLE_NAME = 'tableName';
const F_REQUIRED_PARAMETER = 'requiredParameter';
const F_EXTRA_DELETE_FORM = 'extraDeleteForm';
const F_FINAL_DELETE_FORM = 'finalDeleteForm';
const F_SUBMIT_BUTTON_TEXT = 'submitButtonText';
......@@ -457,6 +461,10 @@ const FE_MODE_READONLY = 'readonly';
const FE_MODE_REQUIRED = 'required';
const FE_MODE_HIDDEN = 'hidden';
const FE_CLASS_NATIVE = 'native';
const FE_CLASS_ACTION = 'action';
const FE_CLASS_CONTAINER = 'container';
const FE_SUBRECORD_ROW_CLASS = '_rowClass';
const FE_SUBRECORD_ROW_TITLE = '_rowTitle';
......@@ -468,6 +476,7 @@ const FE_MODE_SQL = 'modeSql';
// TODO: Konstante FE_DYNAMIC_UPDATE ueberall einsetzen
const FE_DYNAMIC_UPDATE = 'dynamicUpdate';
const FE_VALUE = 'value';
const FE_CLASS = 'class';
// FormElement columns: via parameter field
const FE_DATE_FORMAT = 'dateFormat'; // value: FORMAT_DATE_INTERNATIONAL | FORMAT_DATE_GERMAN
......@@ -492,6 +501,7 @@ const FE_SENDMAIL_REPLY_TO = 'sendMailReplyTo'; // Reply to email address
const FE_SENDMAIL_FLAG_AUTO_SUBMIT = 'sendMailFlagAutoSubmit'; // on|off - if 'on', suppresses OoO answers from receivers.
const FE_SENDMAIL_GR_ID = 'sendMailGrId'; // gr_id: used to classify mail log entries ind table mailLog
const FE_SENDMAIL_X_ID = 'sendMailXId'; // x_id: used to classify mail log entries ind table mailLog
const FE_AUTOFOCUS = 'autofocus'; // value: <none>|0|1 , <none>==1, this element becomes the focus during form load.
// FormElement Types
......
......@@ -246,16 +246,19 @@ class Database {
$this->dbLog($sqlLogMode, $sql, $parameterArray);
if (false === ($this->mysqli_stmt = $this->mysqli->prepare($sql))) {
$this->dbLog(SQL_LOG_MODE_ERROR, $sql, $parameterArray);
throw new DbException('[ mysqli: ' . $this->mysqli->errno . ' ] ' . $this->mysqli->error, ERROR_DB_PREPARE);
}
if (count($parameterArray) > 0) {
if (false === $this->prepareBindParam($parameterArray)) {
$this->dbLog(SQL_LOG_MODE_ERROR, $sql, $parameterArray);
throw new DbException('[ mysqli: ' . $this->mysqli_stmt->errno . ' ] ' . $this->mysqli_stmt->error, ERROR_DB_BIND);
}
}
if (false === $this->mysqli_stmt->execute()) {
$this->dbLog(SQL_LOG_MODE_ERROR, $sql, $parameterArray);
throw new DbException('[ mysqli: ' . $this->mysqli_stmt->errno . ' ] ' . $this->mysqli_stmt->error, ERROR_DB_EXECUTE);
}
......@@ -342,6 +345,8 @@ class Database {
*/
private function dbLog($mode = SQL_LOG_MODE_ALL, $sql = '', $parameterArray = array()) {
$status = '';
$sqlLogMode = $this->store->getVar(SYSTEM_SQL_LOG_MODE, STORE_SYSTEM);
switch ($mode) {
......@@ -354,6 +359,9 @@ class Database {
case SQL_LOG_MODE_MODIFY:
break;
case SQL_LOG_MODE_ERROR:
break;
default:
throw new UserFormException("Unknown SQL_LOG_MODE: $mode", ERROR_UNKNOWN_SQL_LOG_MODE);
}
......@@ -373,7 +381,10 @@ class Database {
}
if ($sql !== '') {
$msg .= '[' . $sql . ']';
if ($mode == SQL_LOG_MODE_ERROR) {
$status = 'FAILED: ';
}
$msg .= '[' . $status . $sql . ']';
}
Logger::logMessage($msg, $this->sqlLog);
......
......@@ -233,7 +233,7 @@ class QuickFormQuery {
$sipFound = $this->validateForm($foundInStore, $formMode);
} else {
// FORM_DELETE without a form definition: Fake the form wiht only a tableName.
// FORM_DELETE without a form definition: Fake the form with only a tableName.
$table = $this->store->getVar(SIP_TABLE, STORE_SIP);
if ($table === false) {
throw new UserFormException("No 'form' and no 'table' definition found.", ERROR_MISSING_VALUE);
......@@ -378,6 +378,8 @@ class QuickFormQuery {
$form = $this->db->sql("SELECT * FROM Form AS f WHERE f." . F_NAME . " LIKE ? AND f.deleted='no'", ROW_EXPECT_1,
[$formName], 'Form not found or multiple forms with the same name.');
$form = $this->modeAdjustFormConfig($mode, $form);
$this->formSpec = $this->eval->parseArray($form);
HelperFormElement::explodeParameter($this->formSpec);
......@@ -388,6 +390,10 @@ class QuickFormQuery {
Support::setIfNotSet($this->formSpec, F_BS_NOTE_COLUMNS, 3, '');
Support::setIfNotSet($this->formSpec, F_SUBMIT_BUTTON_TEXT, '');
Support::setIfNotSet($this->formSpec, F_EXTRA_DELETE_FORM, '');
// Set F_FINAL_DELETE_FORM
$this->formSpec[F_FINAL_DELETE_FORM] = $this->formSpec[F_EXTRA_DELETE_FORM] != '' ? $this->formSpec[F_EXTRA_DELETE_FORM] : $this->formSpec[F_NAME];
// Take default from config.ini
$class = $this->store->getVar(SYSTEM_CSS_CLASS_QFQ_FORM_PILL, STORE_SYSTEM);
......@@ -491,6 +497,27 @@ class QuickFormQuery {
return $formName;
}
/**
* Depending on $mode various formSpec fields might be adjusted.
* E.g.: the form title is not important during a delete.
*
* @param $mode
* @param array $form
* @return array
*/
private function modeAdjustFormConfig($mode, array $form) {
switch ($mode) {
case FORM_DELETE:
$form[F_TITLE] = '';
break;
default:
break;
}
return $form;
}
/**
* Check if loading of the given form is permitted. If not, throw an exception.
*
......
......@@ -39,7 +39,7 @@ class AbstractException extends \Exception {
$this->messageArray['Line'] = $this->getLine();
$this->messageArray['Message'] = $this->getMessage();
$this->messageArray['Code'] = $this->getCode();
$this->messageArray['Timestamp'] = date('Y.m.d H:i:s O');
$this->messageArray['Stacktrace'] = '<pre>' . $this->getTraceAsString() . '</pre>';
if ($store !== null) {
$this->messageArray['Page Id'] = $store->getVar(TYPO3_PAGE_ID, STORE_TYPO3);
......
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