Commit 9f0da3ae authored by Rafael Ostertag's avatar Rafael Ostertag
Browse files

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

Conflicts:
	CODING.md
parents 59ee0179 b98b5926
...@@ -157,6 +157,7 @@ New Button ...@@ -157,6 +157,7 @@ New Button
* Client does not save the modified record. * Client does not save the modified record.
* Client stays on current page. * Client stays on current page.
File Handling File Handling
------------- -------------
* No previous uploaded file present * No previous uploaded file present
...@@ -172,6 +173,31 @@ File Handling ...@@ -172,6 +173,31 @@ File Handling
1. File delete button gets disabled and hidden 1. File delete button gets disabled and hidden
1. Browse button gets enabled and displayed 1. Browse button gets enabled and displayed
Formelement type: DATE / DATETIME / TIME
----------------------------------------
* Available Formats:
* 'yyyy-mm-dd' = FORMAT_DATE_INTERNATIONAL.
* 'dd.mm.yyyy' = FORMAT_DATE_GERMAN.
* The 'DATE_FORMAT' can be specified systemwide in `config.ini`
* The default format is FORMAT_DATE_INTERNATIONAL.
* Optional: 'dateFormat' can be specified per form element in `form.parameter` - this overwrites 'systemwide'.
* If there is no placeholder defined on the form element, the defined dateFormat is shown as placeholder.
* Browser:
* checks the input with a system regexp.
* regexp might be user defined. If given, do not use system regexp!
* No min/max check.
* Server:
* check with system wirde regexp
* regexp might be user defined. If given, do not use system regexp!
* Do min/max check.
* MySQL data: 1000-01-01 - 9999-12-31 and 0000-00-00
* MySQL time: 00:00:00 - 23:59:59
* datetime format: 'DATE TIME'
Debug / Log / Errormessages Debug / Log / Errormessages
=========================== ===========================
......
...@@ -38,20 +38,21 @@ Setup ...@@ -38,20 +38,21 @@ Setup
page.includeCSS { page.includeCSS {
file1 = typo3conf/ext/qfq/Resources/Public/Css/bootstrap.min.css file1 = typo3conf/ext/qfq/Resources/Public/Css/bootstrap.min.css
file2 = typo3conf/ext/qfq/Resources/Public/Css/bootstrap-theme.min.css file2 = typo3conf/ext/qfq/Resources/Public/Css/bootstrap-theme.min.css
file3 = typo3conf/ext/qfq/Resources/Public/Css/jqx.base.css file3 = typo3conf/ext/qfq/Resources/Public/Css/jqx.base.css
file4 = typo3conf/ext/qfq/Resources/Public/Css/jqx.darkblue.css file4 = typo3conf/ext/qfq/Resources/Public/Css/jqx.darkblue.css
file5 = typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css file5 = typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css
} }
page.includeJS { page.includeJS {
file1 = typo3conf/ext/qfq/Resources/Public/JavaScript/jquery.min.js file1 = typo3conf/ext/qfq/Resources/Public/JavaScript/jquery.min.js
file2 = typo3conf/ext/qfq/Resources/Public/JavaScript/bootstrap.min.js file2 = typo3conf/ext/qfq/Resources/Public/JavaScript/bootstrap.min.js
file3 = typo3conf/ext/qfq/Resources/Public/JavaScript/jqx-all.js file3 = typo3conf/ext/qfq/Resources/Public/JavaScript/validator.min.js
file4 = typo3conf/ext/qfq/Resources/Public/JavaScript/EventEmitter.min.js file4 = typo3conf/ext/qfq/Resources/Public/JavaScript/jqx-all.js
file5 = typo3conf/ext/qfq/Resources/Public/JavaScript/qfq.min.js file5 = typo3conf/ext/qfq/Resources/Public/JavaScript/EventEmitter.min.js
file6 = typo3conf/ext/qfq/Resources/Public/JavaScript/qfq.debug.js
} }
FormEditor FormEditor
...@@ -101,6 +102,8 @@ Setup a *report* to manage all *forms*: Create a Typo3 page and insert a content ...@@ -101,6 +102,8 @@ Setup a *report* to manage all *forms*: Create a Typo3 page and insert a content
+------------------------+----------------------------------+----------------------------------------------------------------------------+ +------------------------+----------------------------------+----------------------------------------------------------------------------+
| CSS_LINK_CLASS_EXTERNAL| CSS_LINK_CLASS_EXTERNAL=external | CSS class name of links which points to internal tagets | | CSS_LINK_CLASS_EXTERNAL| CSS_LINK_CLASS_EXTERNAL=external | CSS class name of links which points to internal tagets |
+------------------------+----------------------------------+----------------------------------------------------------------------------+ +------------------------+----------------------------------+----------------------------------------------------------------------------+
| DATE_FORMAT | DATE_FORMAT= yyyy-mm-dd | Possible options: yyyy-mm-dd, dd.mm.yyyy |
+------------------------+----------------------------------+----------------------------------------------------------------------------+
Example: *<ext_dir>/config.ini* Example: *<ext_dir>/config.ini*
......
...@@ -507,9 +507,10 @@ Class: Native ...@@ -507,9 +507,10 @@ Class: Native
|class | enum('native', 'action', | Details below. | |class | enum('native', 'action', | Details below. |
| | 'container') | | | | 'container') | |
+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+ +--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
|type | enum('checkbox', 'dateJQW', 'datetimeJQW', 'gridJQW', 'hidden', 'text', 'note', 'password', 'radio', 'select', 'subrecord', | |type | enum('checkbox', 'date', 'time', 'datetime', 'dateJQW', 'datetimeJQW', 'gridJQW', 'hidden', 'text', 'note', 'password', |
| | 'textarea', 'timeJQW', 'upload', 'fieldset', 'pill', 'before_load', 'before_save', 'before_insert', 'before_update', | | | 'radio', 'select', 'subrecord', 'textarea', 'timeJQW', 'upload', 'fieldset', 'pill', 'before_load', 'before_save', |
| | 'before_delete', 'after_load', 'after_save', 'after_insert', 'after_update', 'after_delete', 'feGroup', 'sendmail') | | | 'before_insert', 'before_update', 'before_delete', 'after_load', 'after_save', 'after_insert', 'after_update', 'after_delete', |
| | 'feGroup', 'sendmail') |
+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+ +--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
|checkType | enum('min|max', 'pattern', | | |checkType | enum('min|max', 'pattern', | |
| | 'number', 'email') | | | | 'number', 'email') | |
...@@ -685,9 +686,19 @@ Checkboxes can be rendered in mode: ...@@ -685,9 +686,19 @@ Checkboxes can be rendered in mode:
Type: date Type: date
^^^^^^^^^^ ^^^^^^^^^^
* Range datetime: '1000-01-01' to '9999-12-31' or '0000-00-00'. (http://dev.mysql.com/doc/refman/5.5/en/datetime.html)
* Optional:
* *dateFormat*: ; yyyy-mm-dd | dd.mm.yyyy
Type: datetime Type: datetime
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
* Range datetime: '1000-01-01 00:00:00' to '9999-12-31 23:59:59' or '0000-00-00 00:00:00'. (http://dev.mysql.com/doc/refman/5.5/en/datetime.html)
* Optional:
* *dateFormat*: ; yyyy-mm-dd | dd.mm.yyyy
* *showSeconds*: 0|1 - shows the seconds. Independent if the user specifies seconds, they are displayed '1' or not '0'.
* *showZero*: 0|1 - For an empty timestamp, With '0' nothing is displayed. With '1' the string '0000-00-00 00:00:00' is displayed.
Type: hidden Type: hidden
^^^^^^^^^^^^ ^^^^^^^^^^^^
...@@ -807,6 +818,11 @@ Typically not used. Useful if user wishes an explicit 'Submit' Button. ...@@ -807,6 +818,11 @@ Typically not used. Useful if user wishes an explicit 'Submit' Button.
Type: time Type: time
^^^^^^^^^^ ^^^^^^^^^^
* Range time: '00:00:00' to '23:59:59' or '00:00:00'. (http://dev.mysql.com/doc/refman/5.5/en/datetime.html)
* Optional:
* *showSeconds*: 0|1 - shows the seconds. Independent if the user specifies seconds, they are displayed '1' or not '0'.
* *showZero*: 0|1 - For an empty timestamp, With '0' nothing is displayed. With '1' the string '00:00[:00]' is displayed.
Type: upload Type: upload
^^^^^^^^^^^^ ^^^^^^^^^^^^
......
...@@ -20,3 +20,6 @@ CSS_LINK_CLASS_EXTERNAL = external ...@@ -20,3 +20,6 @@ CSS_LINK_CLASS_EXTERNAL = external
; QFQ with own Bootstrap: 'container'. QFQ already nested in Bootstrap of mainpage: <empty> ; QFQ with own Bootstrap: 'container'. QFQ already nested in Bootstrap of mainpage: <empty>
CSS_CLASS_QFQ_CONTAINER = CSS_CLASS_QFQ_CONTAINER =
; yyyy-mm-dd, dd.mm.yyyy
DATE_FORMAT = yyyy-mm-dd
<?php
/**
* Created by PhpStorm.
* User: crose
* Date: 4/25/16
* Time: 8:02 PM
*/
$answer = array();
$answer[API_MESSAGE] = '';
$answer[API_STATUS] = API_ANSWER_STATUS_ERROR;
try {
$upload = new \qfq\File();
$upload->process();
$answer[API_MESSAGE] = 'upload: success';
$answer[API_REDIRECT] = API_ANSWER_REDIRECT_NO;
$answer[API_STATUS] = API_ANSWER_STATUS_SUCCESS;
} catch (qfq\UserFormException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\CodeException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\DbException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (\Exception $e) {
$answer[API_MESSAGE] = "Generic Exception: " . $e->getMessage();
}
header("Content-Type: application/json");
echo json_encode($answer);
[Mon, 29 Feb 2016 15:32:39 +0100][SELECT * FROM Form AS f WHERE f.name LIKE 'formElement' AND f.deleted='no']
[Mon, 29 Feb 2016 15:32:39 +0100][Get rows: 1]
[Mon, 29 Feb 2016 15:32:39 +0100][SELECT id, " / ", title FROM Form WHERE id = 0]
[Mon, 29 Feb 2016 15:32:39 +0100][Get rows: 0]
[Mon, 29 Feb 2016 15:32:39 +0100][SELECT *, 'no' AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = '2' AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, 'action' ) AND fe.enabled='yes' ORDER BY fe.ord, fe.id]
[Mon, 29 Feb 2016 15:32:39 +0100][Get rows: 0]
[Mon, 29 Feb 2016 15:32:39 +0100][SELECT *, 'no' AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = '2' AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, 'native' ) AND fe.enabled='yes' ORDER BY fe.ord, fe.id]
[Mon, 29 Feb 2016 15:32:39 +0100][Get rows: 28]
[Mon, 29 Feb 2016 15:32:39 +0100][SHOW FIELDS FROM `FormElement`]
[Mon, 29 Feb 2016 15:32:39 +0100][Get rows: 29]
[Mon, 29 Feb 2016 15:32:39 +0100][UPDATE `FormElement` SET `formId` = '1', `feIdContainer` = '1', `enabled` = 'yes', `name` = 'id1', `label` = 'id', `mode` = 'readonly', `class` = 'native', `type` = 'text', `checkType` = '', `checkPattern` = '', `onChange` = '', `ord` = '100', `tabindex` = '0', `size` = '10', `note` = '', `tooltip` = '', `placeholder` = '', `value` = '', `sql1` = '', `parameter` = '', `clientJs` = '', `feGroup` = '', `debug` = 'no', `deleted` = 'no', `modified` = '2016-02-29 15:17:28', `created` = '0000-00-00 00:00:00' WHERE id = '6']
[Mon, 29 Feb 2016 15:32:39 +0100][Affected rows: 1]
[Mon, 29 Feb 2016 15:32:52 +0100][SELECT * FROM Form AS f WHERE f.name LIKE 'formElement' AND f.deleted='no']
[Mon, 29 Feb 2016 15:32:52 +0100][Get rows: 1]
[Mon, 29 Feb 2016 15:32:52 +0100][SELECT id, " / ", title FROM Form WHERE id = 0]
[Mon, 29 Feb 2016 15:32:52 +0100][Get rows: 0]
[Mon, 29 Feb 2016 15:32:52 +0100][SELECT *, 'no' AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = '2' AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, 'action' ) AND fe.enabled='yes' ORDER BY fe.ord, fe.id]
[Mon, 29 Feb 2016 15:32:52 +0100][Get rows: 0]
[Mon, 29 Feb 2016 15:32:52 +0100][SELECT *, 'no' AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = '2' AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, 'native' ) AND fe.enabled='yes' ORDER BY fe.ord, fe.id]
[Mon, 29 Feb 2016 15:32:52 +0100][Get rows: 28]
[Mon, 29 Feb 2016 15:32:52 +0100][SHOW FIELDS FROM `FormElement`]
[Mon, 29 Feb 2016 15:32:52 +0100][Get rows: 29]
[Mon, 29 Feb 2016 15:32:52 +0100][UPDATE `FormElement` SET `formId` = '1', `feIdContainer` = '1', `enabled` = 'yes', `name` = 'id', `label` = 'id', `mode` = 'readonly', `class` = 'native', `type` = 'text', `checkType` = '', `checkPattern` = '', `onChange` = '', `ord` = '100', `tabindex` = '0', `size` = '10', `note` = '', `tooltip` = '', `placeholder` = '', `value` = '', `sql1` = '', `parameter` = '', `clientJs` = '', `feGroup` = '', `debug` = 'no', `deleted` = 'no', `modified` = '2016-02-29 15:17:28', `created` = '0000-00-00 00:00:00' WHERE id = '6']
[Mon, 29 Feb 2016 15:32:52 +0100][Affected rows: 1]
...@@ -5,12 +5,13 @@ ...@@ -5,12 +5,13 @@
* Date: 1/6/16 * Date: 1/6/16
* Time: 8:02 PM * Time: 8:02 PM
*/ */
namespace qfq; namespace qfq;
use qfq; use qfq;
use qfq\Store; use qfq\Store;
use qfq\UserFormException;
use qfq\OnArray; use qfq\OnArray;
use qfq\UserFormException;
require_once(__DIR__ . '/../qfq/store/Store.php'); require_once(__DIR__ . '/../qfq/store/Store.php');
require_once(__DIR__ . '/../qfq/Constants.php'); require_once(__DIR__ . '/../qfq/Constants.php');
...@@ -66,12 +67,15 @@ abstract class AbstractBuildForm { ...@@ -66,12 +67,15 @@ abstract class AbstractBuildForm {
$this->buildElementFunctionName = [ $this->buildElementFunctionName = [
'checkbox' => 'Checkbox', 'checkbox' => 'Checkbox',
'date' => 'DateTime',
'datetime' => 'DateTime',
'dateJQW' => 'DateJQW', 'dateJQW' => 'DateJQW',
'datetimeJQW' => 'DateJQW', 'datetimeJQW' => 'DateJQW',
'email' => 'Input', 'email' => 'Input',
'gridJQW' => 'GridJQW', 'gridJQW' => 'GridJQW',
'hidden' => 'Hidden', 'hidden' => 'Hidden',
'text' => 'Input', 'text' => 'Input',
'time' => 'DateTime',
'note' => 'Note', 'note' => 'Note',
'password' => 'Input', 'password' => 'Input',
'radio' => 'Radio', 'radio' => 'Radio',
...@@ -84,12 +88,15 @@ abstract class AbstractBuildForm { ...@@ -84,12 +88,15 @@ abstract class AbstractBuildForm {
$this->buildRowName = [ $this->buildRowName = [
'checkbox' => 'Native', 'checkbox' => 'Native',
'date' => 'Native',
'datetime' => 'Native',
'dateJQW' => 'Native', 'dateJQW' => 'Native',
'datetimeJQW' => 'Native', 'datetimeJQW' => 'Native',
'email' => 'Native', 'email' => 'Native',
'gridJQW' => 'Native', 'gridJQW' => 'Native',
'hidden' => 'Native', 'hidden' => 'Native',
'text' => 'Native', 'text' => 'Native',
'time' => 'Native',
'note' => 'Native', 'note' => 'Native',
'password' => 'Native', 'password' => 'Native',
'radio' => 'Native', 'radio' => 'Native',
...@@ -124,7 +131,14 @@ abstract class AbstractBuildForm { ...@@ -124,7 +131,14 @@ abstract class AbstractBuildForm {
$htmlSubrecords = ''; $htmlSubrecords = '';
$htmlElements = ''; $htmlElements = '';
$json = array(); $json = array();
$modeCollectFe = ($mode === FORM_SAVE) ? FLAG_ALL : FLAG_DYNAMIC_UPDATE;
$modeCollectFe = FLAG_DYNAMIC_UPDATE;
$storeUse = STORE_USE_DEFAULT;
if ($mode === FORM_SAVE) {
$modeCollectFe = FLAG_ALL;
$storeUse = STORE_RECORD . STORE_TABLE_DEFAULT;
}
// <form> // <form>
if ($mode === FORM_LOAD) { if ($mode === FORM_LOAD) {
...@@ -145,7 +159,7 @@ abstract class AbstractBuildForm { ...@@ -145,7 +159,7 @@ abstract class AbstractBuildForm {
$json[] = $jsonTmp; $json[] = $jsonTmp;
} }
} else { } else {
$htmlElements = $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), $filter, 0, $json, $modeCollectFe, $htmlElementNameIdZero); $htmlElements = $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), $filter, 0, $json, $modeCollectFe, $htmlElementNameIdZero, $storeUse);
} }
$htmlSip = $this->buildHiddenSip($json); $htmlSip = $this->buildHiddenSip($json);
...@@ -303,7 +317,7 @@ abstract class AbstractBuildForm { ...@@ -303,7 +317,7 @@ abstract class AbstractBuildForm {
* @throws \qfq\UserFormException * @throws \qfq\UserFormException
*/ */
public function elements($recordId, $filter = FORM_ELEMENTS_NATIVE, $feIdContainer = 0, &$json, public function elements($recordId, $filter = FORM_ELEMENTS_NATIVE, $feIdContainer = 0, &$json,
$modeCollectFe = FLAG_DYNAMIC_UPDATE, $htmlElementNameIdZero = false) { $modeCollectFe = FLAG_DYNAMIC_UPDATE, $htmlElementNameIdZero = false, $storeUse = STORE_USE_DEFAULT) {
$html = ''; $html = '';
// get current data record // get current data record
...@@ -330,8 +344,11 @@ abstract class AbstractBuildForm { ...@@ -330,8 +344,11 @@ abstract class AbstractBuildForm {
$evaluate = new Evaluate($this->store, $this->db); $evaluate = new Evaluate($this->store, $this->db);
$formElement = $evaluate->parseArray($fe, $debugStack); $formElement = $evaluate->parseArray($fe, $debugStack);
// Some Defaults
$formElement = Support::setFeDefaults($formElement);
// Get default value // Get default value
$value = ($formElement['value'] === '') ? $this->store->getVar($formElement['name'], STORE_USE_DEFAULT, $value = ($formElement['value'] === '') ? $this->store->getVar($formElement['name'], $storeUse,
$formElement['checkType']) : $formElement['value']; $formElement['checkType']) : $formElement['value'];
// Typically: $htmlElementNameIdZero = true // Typically: $htmlElementNameIdZero = true
...@@ -369,7 +386,7 @@ abstract class AbstractBuildForm { ...@@ -369,7 +386,7 @@ abstract class AbstractBuildForm {
// Construct Marshaller Name: buildRow // Construct Marshaller Name: buildRow
$buildRowName = 'buildRow' . $this->buildRowName[$formElement['type']]; $buildRowName = 'buildRow' . $this->buildRowName[$formElement['type']];
$html .= $this->$buildRowName($formElement, $elementHtml); $html .= $this->$buildRowName($formElement, $elementHtml, $htmlFormElementId);
// break; // break;
} }
...@@ -457,23 +474,26 @@ abstract class AbstractBuildForm { ...@@ -457,23 +474,26 @@ abstract class AbstractBuildForm {
return $url; return $url;
} }
abstract public function buildRowNative($formElement, $elementHtml); abstract public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementId);
abstract public function buildRowPill($formElement, $elementHtml); abstract public function buildRowPill(array $formElement, $elementHtml);
abstract public function buildRowFieldset($formElement, $elementHtml); abstract public function buildRowFieldset(array $formElement, $elementHtml);
abstract public function buildRowSubrecord($formElement, $elementHtml); abstract public function buildRowSubrecord(array $formElement, $elementHtml);
/** /**
* Builds a label, typically for an html-'<input>'-element. * Builds a label, typically for an html-'<input>'-element.
* *
* @param array $htmlFormElementId * @param string $htmlFormElementId
* @param $label * @param string $label
* @return string * @return string
*/ */
public function buildLabel($htmlFormElementId, $label) { public function buildLabel($htmlFormElementId, $label) {
$html = '<label for="' . $htmlFormElementId . '">' . $label . '</label>'; $attributes = Support::doAttribute('for', $htmlFormElementId);
$attributes .= Support::doAttribute('class', 'control-label');
$html = Support::wrapTag("<label $attributes>", $label);
return $html; return $html;
} }
...@@ -495,6 +515,7 @@ abstract class AbstractBuildForm { ...@@ -495,6 +515,7 @@ abstract class AbstractBuildForm {
$textarea = ''; $textarea = '';
$attribute = Support::doAttribute('name', $htmlFormElementId); $attribute = Support::doAttribute('name', $htmlFormElementId);
$attribute .= Support::doAttribute('class', 'form-control');
// Check for input type 'textarea' // Check for input type 'textarea'
$colsRows = explode(',', $formElement['size'], 2); $colsRows = explode(',', $formElement['size'], 2);
...@@ -532,7 +553,7 @@ abstract class AbstractBuildForm { ...@@ -532,7 +553,7 @@ abstract class AbstractBuildForm {
$json = $this->getJsonElementUpdate($htmlFormElementId, $value, $formElement['mode']); $json = $this->getJsonElementUpdate($htmlFormElementId, $value, $formElement['mode']);
return "$htmlTag $attribute>$textarea"; return "$htmlTag $attribute>$textarea" . $this->getHelpBlock();
} }
...@@ -544,6 +565,27 @@ abstract class AbstractBuildForm { ...@@ -544,6 +565,27 @@ abstract class AbstractBuildForm {
// MIN( $formElement['maxLength'], tabledefinition) // MIN( $formElement['maxLength'], tabledefinition)
$maxLength = $this->getColumnSize($formElement['name']); $maxLength = $this->getColumnSize($formElement['name']);
switch ($formElement['type']) {
case 'date':
$feMaxLength = 10;
break;
case 'datetime':
$feMaxLength = 19;
break;
case 'time':
$feMaxLength = 8;
break;
default:
$feMaxLength = false;
break;
}
// In case the underlying tablecolumn is not of type date/time, the $maxLength might be to high: correct
if ($feMaxLength !== false && $maxLength !== false && $feMaxLength < $maxLength) {
$maxLength = $feMaxLength;
}
// date/datetime
if ($maxLength !== false) { if ($maxLength !== false) {
if (is_numeric($formElement['maxLength'])) { if (is_numeric($formElement['maxLength'])) {
if ($formElement['maxLength'] > $maxLength) { if ($formElement['maxLength'] > $maxLength) {
...@@ -559,14 +601,25 @@ abstract class AbstractBuildForm { ...@@ -559,14 +601,25 @@ abstract class AbstractBuildForm {
* Get column spec from tabledefinition and parse size of it. If nothing defined, return false. * Get column spec from tabledefinition and parse size of it. If nothing defined, return false.
* *
* @param $column * @param $column
* @return bool|int * @return bool|int a) 'false' if there is no length definition, b) length definition, c) date|time|datetime|timestamp use hardcoded length
*/ */
private function getColumnSize($column) { private function getColumnSize($column) {
$matches = array(); $matches = array();
$typeSpec = $this->store->getVar($column, STORE_TABLE_COLUMN_TYPES); $typeSpec = $this->store->getVar($column, STORE_TABLE_COLUMN_TYPES);
switch ($typeSpec) {
case 'date': // yyyy-mm-dd
return 10;
case 'datetime': // yyyy-mm-dd hh:mm:ss
case 'timestamp': // yyyy-mm-dd hh:mm:ss
return 19;
case 'time': // hh:mm:ss
return 8;
default:
break;
}
// e.g.: string(64), enum('yes','no') // e.g.: string(64) >> 64, enum('yes','no') >> false
if (1 === preg_match('/\((.+)\)/', $typeSpec, $matches)) { if (1 === preg_match('/\((.+)\)/', $typeSpec, $matches)) {
if (is_numeric($matches[1])) if (is_numeric($matches[1]))
return $matches[1]; return $matches[1];
...@@ -679,6 +732,13 @@ abstract class AbstractBuildForm { ...@@ -679,6 +732,13 @@ abstract class AbstractBuildForm {
return $attribute; return $attribute;
} }
/**
* @return string
*/
private function getHelpBlock() {
return '<div class="help-block with-errors"></div>';
}
/** /**
* Builds HTML 'checkbox' element. * Builds HTML 'checkbox' element.
* *
...@@ -1085,6 +1145,7 @@ abstract class AbstractBuildForm { ...@@ -1085,6 +1145,7 @@ abstract class AbstractBuildForm {
$attribute = $this->getAttributeMode($formElement); $attribute = $this->getAttributeMode($formElement);
$attribute .= Support::doAttribute('name', $htmlFormElementId); $attribute .= Support::doAttribute('name', $htmlFormElementId);
$attribute .= Support::doAttribute('class', 'form-control');
$attribute .= Support::doAttribute('title', $formElement['tooltip']); $attribute .= Support::doAttribute('title', $formElement['tooltip']);
$attribute .= $this->getAttributeList($formElement, ['autofocus']); $attribute .= $this->getAttributeList($formElement, ['autofocus']);
$attribute .= Support::doAttribute('data-load', ($formElement['dynamicUpdate'] === 'yes') ? 'data-load' : ''); $attribute .= Support::doAttribute('data-load', ($formElement['dynamicUpdate'] === 'yes') ? 'data-load' : '');
...@@ -1118,7 +1179,7 @@ abstract class AbstractBuildForm { ...@@ -1118,7 +1179,7 @@ abstract class AbstractBuildForm {
$json = $this->getJsonElementUpdate($htmlFormElementId, $jsonValues, $formElement['mode']); $json = $this->getJsonElementUpdate($htmlFormElementId, $jsonValues, $formElement['mode']);
return '<select ' . $attribute . '>' . $option . '</select>'; return '<select ' . $attribute . '>' . $option . '</select>' . $this->getHelpBlock();
} }
/** /**
...@@ -1442,30 +1503,194 @@ abstract class AbstractBuildForm { ...@@ -1442,30 +1503,194 @@ abstract class AbstractBuildForm {
* @throws UserFormException * @throws UserFormException
*/ */
public function buildFile(array $formElement, $htmlFormElementId, $value, &$json) { public function buildFile(array $formElement, $htmlFormElementId, $value, &$json) {
$attribute = '';
$attribute = $this->getAttributeMode($formElement); $sip = $this->store->getVar(SIP_SIP, STORE_SIP);
$value = basename($value); // Strip directories
$attribute .= Support::doAttribute('name', $htmlFormElementId);
// $attribute .= Support::doAttribute('class', 'form-control');
$attribute .= Support::doAttribute('type', 'file'); $attribute .= Support::doAttribute('type', 'file');
$attribute .= Support::doAttribute('title', $formElement['tooltip']); $attribute .= Support::doAttribute('title', $formElement['tooltip']);
$attribute .= Support::doAttribute('name', $htmlFormElementId);
$attribute .= $this->getAttributeList($formElement, ['autofocus', 'accept']); $attribute .= $this->getAttributeList($formElement, ['autofocus', 'accept']);
$attribute .= Support::doAttribute('data-load', ($formElement['dynamicUpdate'] === 'yes') ? 'data-load' : ''); $attribute .= Support::doAttribute('data-load', ($formElement['dynamicUpdate'] === 'yes') ? 'data-load' : '');
if ($value === '') {
$textDeleteClass = 'hidden';
$uploadClass = '';
} else {
$textDeleteClass = '';
$uploadClass = 'hidden';
$formElement['mode'] = 'disabled';
}
$attribute .= $this->getAttributeMode($formElement);
$attribute .= Support::doAttribute('class', $uploadClass, true);
$htmlInputFile = '<input ' . $attribute . '>' . $this->getHelpBlock();
$deleteButton = Support::wrapTag("<button class='delete-file' data-sip='$sip' name='trash-$htmlFormElementId'>", $this->symbol[SYMBOL_DELETE]);