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

Add 'templateGroup' as a new 'container' option.

Coding.md: Beschreibung in Deutsch wie die Formularelemente , rekursiv, gerendert werden.
AbstractBuildForm.php: new function buildTemplateGroup()
BuildFormBootstrap.php, BuildFormPlain.php, BuildFormTable.php: Preparation for new optional TemplateGroup wrap.
QuickFormQuery.php: update comments.
formEditor.sql: column 'type' definition extended - new 'templateGroup' enum. FormElement 'type' updated to new container element 'templateGroup'
parent ef751a35
......@@ -43,13 +43,25 @@ LOAD
* If a form is called without a SIP (form.permitNew='always'), than a SIP is created on the fly (as a
parameter in the form).
* Depending on `r=0` or `r>0` a form submit will do an MySQL `insert` or `update` later during save.
* For new records (r=0), clicking on 'save' without closing the form is a tricky situation. Additionally the user might have open multiple
tabs (same form, all r=0) and after saving the record (wihtout closing the form) the user expects that it's ok to edit
the record again and again. Unfortunately, the initial created SIP (before 'form load') is not uniqe anymore (multiple
tabs might contain a saved 'new record'). To guarantee correct saving of r=0 records, a unique on the fly generated SIP
is creatd during form load - individually per browser tab.
* Uniq SIP for mutliple tabs with r=0
* Depending on `r=0` or `r>0` a form submit will do an MySQL `insert` or `update` later during save.
* For new records (r=0), clicking on 'save' without closing the form is a tricky situation. Additionally the user might have open multiple
tabs (same form, all r=0) and after saving the record (wihtout closing the form) the user expects that it's ok to edit
the record again and again. Unfortunately, the initial created SIP (before 'form load') is not uniqe anymore (multiple
tabs might contain a saved 'new record'). To guarantee correct saving of r=0 records, a unique on the fly generated SIP
is creatd during form load - individually per browser tab.
* Formular zusammenbausen
* QuickFormQuery: doForm > loadFormSpecification - laedt alle Elemente die nicht genested sind: native, pill, fieldset, templateGroup >> $his->formNative
* Damit wird '(BuildFormBootstrap / AbstractBuildForm) > process()' aufgerufen.
* Hier wird AbstractBuildForm->elements() aufgerufen (ein Aufruf fuer alle root elemente).
* Pro native Element (inkl. pill, fieldset, templateGroup) wird $builElementFunctionName aufgerufen.
- buildText()
- ....
- buildFieldSet() << von hier werden alle zum aktuellen 'FieldSet' gehoerenden SubElemente abgearbeitet - via AbstractBuildForm->elements() (damit schliesst sich der Kreis und wird rekursiv)
- buildPill() << von hier werden alle zum aktuellen 'Pill' gehoerenden SubElemente abgearbeitet - via AbstractBuildForm->elements() (damit schliesst sich der Kreis und wird rekursiv)
- buildTemplateGroup() << von hier werden alle zum aktuellen 'Pill' gehoerenden SubElemente abgearbeitet - via AbstractBuildForm->elements() (damit schliesst sich der Kreis und wird rekursiv)
>>
SAVE
----
* Via wrapper api/save.php
......
......@@ -98,7 +98,8 @@ abstract class AbstractBuildForm {
'subrecord' => 'Subrecord',
'upload' => 'File',
'fieldset' => 'Fieldset',
'pill' => 'Pill'
'pill' => 'Pill',
'templateGroup' => 'TemplateGroup'
];
$this->buildRowName = [
......@@ -120,7 +121,8 @@ abstract class AbstractBuildForm {
'subrecord' => 'Subrecord',
'upload' => 'Native',
'fieldset' => 'Fieldset',
'pill' => 'Pill'
'pill' => 'Pill',
'templateGroup' => 'TemplateGroup'
];
$this->symbol[SYMBOL_EDIT] = "<span class='glyphicon " . GLYPH_ICON_EDIT . "'></span>";
......@@ -345,10 +347,10 @@ abstract class AbstractBuildForm {
$modeCollectFe = FLAG_DYNAMIC_UPDATE, $htmlElementNameIdZero = false, $storeUse = STORE_USE_DEFAULT, $mode = FORM_LOAD) {
$html = '';
$flagOutput = false;
// The following 'FormElement.parameter' will never be used during load (fe.type='upload').
$skip = [FE_SQL_UPDATE, FE_SQL_INSERT, FE_SQL_DELETE, FE_SQL_AFTER, FE_SQL_BEFORE, F_FE_PARAMETER];
// get current data record
if ($recordId > 0 && $this->store->getVar('id', STORE_RECORD) === false) {
$row = $this->db->sql("SELECT * FROM " . $this->formSpec[F_TABLE_NAME] . " WHERE id = ?", ROW_EXPECT_1, array($recordId), "Form '" . $this->formSpec[F_NAME] . "' failed to load record '$recordId' from table '" . $this->formSpec[F_TABLE_NAME] . "'.");
......@@ -367,7 +369,7 @@ abstract class AbstractBuildForm {
continue; // skip this FE
}
$flagOutput = ($fe[FE_TYPE] !== FE_TYPE_EXTRA);
$flagOutput = ($fe[FE_TYPE] !== FE_TYPE_EXTRA); // type='extra' will not displayed not trasnmitted to the form
$debugStack = array();
......@@ -637,12 +639,12 @@ abstract class AbstractBuildForm {
return $url;
}
abstract public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementId);
abstract public function buildRowPill(array $formElement, $elementHtml);
abstract public function buildRowFieldset(array $formElement, $elementHtml);
abstract public function buildRowTemplateGroup(array $formElement, $elementHtml);
abstract public function buildRowSubrecord(array $formElement, $elementHtml);
/**
......@@ -2327,6 +2329,107 @@ abstract class AbstractBuildForm {
return $html;
}
/**
* Build a HTML fieldset. Renders all assigned FormElements inside the fieldset.
*
* @param array $formElement
* @param $htmlFormElementId
* @param $value
* @param array $json
* @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
* @return mixed
* @throws CodeException
* @throws DbException
*/
public function buildTemplateGroup(array $formElement, $htmlFormElementId, $value, array &$json, $mode = FORM_LOAD) {
$attribute = '';
$html = '';
// save parent processed FE's
$tmpStore = $this->feSpecNative;
// $attribute .= Support::doAttribute('name', $htmlFormElementId);
// $attribute .= Support::doAttribute('data-load', ($formElement['dynamicUpdate'] === 'yes') ? 'data-load' : '');
// <fieldset>
// $html = '<fieldset ' . $attribute . '>';
// if ($formElement[FE_LABEL] !== '') {
// $html .= '<legend>' . $formElement[FE_LABEL] . '</legend>';
// }
$qfqFieldsName = 'qfq_fields_' . $formElement[FE_ID]; // ='qfq-fields'
$templateName = 'template_' . $formElement[FE_ID]; // ='template'
$targetName = 'target_' . $formElement[FE_ID]; // ='template'
Support::setIfNotSet($formElement, FE_VALUE, '5', '');
$max = $formElement[FE_VALUE];
$codeJs = <<<EOT
<script type="text/javascript">
$(function () {
$(".$qfqFieldsName").each(
function () {
QfqNS.initializeFields(this);
}
);
});
</script>
EOT;
$htmlAdd = <<<EOT
<button type="button" onclick="QfqNS.addFields('#$templateName', '#$targetName', $max)">Add</button>
EOT;
$htmlDelete = <<<EOT
<div class="qfq-delete-button">
<button type="button" onclick="QfqNS.removeFields(this)">Remove</button>
</div>
EOT;
// 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 class="' . $qfqFieldsName . '" id="' . $targetName . '" data-qfq-line-template="#' . $templateName . '">', '', false);
// Add button, row below: The label & note of the FormElement 'templateGroup' will be used for the add button row.
$tmpFe = $formElement;
$tmpFe[FE_NAME] = '_add';
$tmpFe[FE_LABEL] = '';
$tmpFe[FE_NOTE] = '';
$html .= $this->buildRowNative($tmpFe, $htmlAdd, $htmlFormElementId);
$html = $this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_START] . $html . $this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_END];
// child FE's
$this->feSpecNative = $this->db->getNativeFormElements(SQL_FORM_ELEMENT_SPECIFIC_CONTAINER,
['yes', $this->formSpec["id"], 'native,container', $formElement['id']], $this->formSpec);
$last = count($this->feSpecNative) - 1;
if ($last < 1) {
return '';
}
$this->feSpecNative[$last][FE_NOTE] .= $htmlDelete;
// Get FE natives
$template = $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), FORM_ELEMENTS_NATIVE, 0, $json);
// Wrap the main html code
$template = Support::wrapTag('<div class="qfq-line">', $template);
$template = Support::wrapTag('<script id="' . $templateName . '" type="text/' . $templateName . '">', $template);
$html .= $template . $codeJs;
// restore parent processed FE's
$this->feSpecNative = $tmpStore;
//TODO: nicht klar ob das hier noetig ist.
// $json = $this->getJsonElementUpdate($htmlFormElementId, $value, $formElement[FE_MODE]);
return $html;
}
abstract public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementId);
/**
* Create a delete link.
*
......
......@@ -62,6 +62,9 @@ class BuildFormBootstrap extends AbstractBuildForm {
$this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_START] = "";
$this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_END] = "";
$this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_START] = "";
$this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_END] = "";
// $this->feDivClass['radio'] = 'radio';
// $this->feDivClass['checkbox'] = 'checkbox';
}
......@@ -421,7 +424,9 @@ EOF;
/**
* @param array $formElement
* @param string $htmlElement
* @param $htmlFormElementId
* @return string
* @throws \qfq\UserFormException
*/
public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementId) {
$html = '';
......@@ -491,6 +496,18 @@ EOF;
return $html;
}
/**
* Builds a templateGroup
*
* @param $formElement
* @param $elementHtml
*/
public function buildRowTemplateGroup(array $formElement, $elementHtml) {
$html = $elementHtml;
return $html;
}
/**
* @param $formElement
* @param $elementHtml
......
......@@ -39,6 +39,9 @@ class BuildFormPlain extends AbstractBuildForm {
$this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_START] = '<p>';
$this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_END] = '</p>';
$this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_START] = "";
$this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_END] = "";
}
public function fillWrapLabelInputNote($label, $input, $note) {
......@@ -110,6 +113,10 @@ class BuildFormPlain extends AbstractBuildForm {
// TODO: Implement buildRowFieldset() method.
}
public function buildRowTemplateGroup(array $formElement, $elementHtml) {
// TODO: Implement buildRowTemplate() method.
}
public function buildRowSubrecord(array $formElement, $elementHtml) {
// TODO: Implement buildRowSubrecord() method.
}
......
......@@ -42,6 +42,8 @@ class BuildFormTable extends AbstractBuildForm {
$this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_START] = '<p>';
$this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_END] = '</p>';
$this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_START] = "";
$this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_END] = "";
}
......@@ -149,6 +151,10 @@ class BuildFormTable extends AbstractBuildForm {
// TODO: Implement buildRowFieldset() method.
}
public function buildRowTemplateGroup(array $formElement, $elementHtml) {
// TODO: Implement buildRowTemplate() method.
}
public function buildRowSubrecord(array $formElement, $elementHtml) {
// TODO: Implement buildRowSubrecord() method.
}
......
......@@ -72,6 +72,7 @@ const WRAP_SETUP_INPUT = 'input';
const WRAP_SETUP_NOTE = 'note';
const WRAP_SETUP_SUBRECORD = 'subrecord';
const WRAP_SETUP_IN_FIELDSET = 'inFieldset';
const WRAP_SETUP_IN_TEMPLATE_GROUP = 'inTemplateGroup';
const WRAP_SETUP_START = 'start';
const WRAP_SETUP_END = 'end';
......@@ -493,6 +494,7 @@ const FE_SUBRECORD_ROW_CLASS = '_rowClass';
const FE_SUBRECORD_ROW_TITLE = '_rowTitle';
// FormElement columns: real
const FE_ID = 'id';
const FE_NAME = 'name';
const FE_TYPE = 'type';
const FE_MODE = 'mode';
......
......@@ -281,9 +281,7 @@ class QuickFormQuery {
case FORM_LOAD:
case FORM_UPDATE:
$formAction->elements($recordId, $this->feSpecAction, FE_TYPE_BEFORE_LOAD);
$data = $build->process($formMode);
$formAction->elements($recordId, $this->feSpecAction, FE_TYPE_AFTER_LOAD);
break;
......@@ -407,6 +405,7 @@ class QuickFormQuery {
// "SELECT *, ? AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, ? ) AND fe.feIdContainer = ? AND fe.enabled='yes' ORDER BY fe.ord, fe.id";
switch ($mode) {
case FORM_LOAD:
// Select all Native elements (native, pill, fieldset, templateGroup) which are NOT nested = Root level.
$this->feSpecNative = $this->db->getNativeFormElements(SQL_FORM_ELEMENT_SPECIFIC_CONTAINER,
['no', $this->formSpec["id"], 'native,container', 0], $this->formSpec);
break;
......
......@@ -69,7 +69,8 @@ CREATE TABLE IF NOT EXISTS `FormElement` (
`modeSql` TEXT NOT NULL,
`class` ENUM('native', 'action', 'container') NOT NULL DEFAULT 'native',
`type` ENUM('checkbox', 'date', 'datetime', 'dateJQW', 'datetimeJQW', 'extra', 'gridJQW', 'text',
'editor', 'time', 'note', 'password', 'radio', 'select', 'subrecord', 'upload', 'fieldset', 'pill',
'editor', 'time', 'note', 'password', 'radio', 'select', 'subrecord', 'upload',
'fieldset', 'pill', 'templateGroup',
'beforeLoad', 'beforeSave', 'beforeInsert', 'beforeUpdate', 'beforeDelete', 'afterLoad',
'afterSave', 'afterInsert', 'afterUpdate', 'afterDelete', 'sendMail') NOT NULL DEFAULT 'text',
`subrecordOption` SET('edit', 'delete', 'new') NOT NULL DEFAULT '',
......@@ -222,7 +223,7 @@ VALUES
(2, 'modeSql', 'Mode sql', 'show', 'text', 'all', 'native', 170, '70,2', 255, '', '', '', '', '', 100, '', 'no', '', '', '', '', ''),
(2, 'class', 'Class', 'show', 'select', 'all', 'native', 180, 0, 255, '', '', '{{class:FSRD0:alnumx}}', '', '', 100, '', 'yes', '', '', '', '', ''),
(2, 'type', 'Type', 'show', 'select', 'all', 'native', 190, 0, 255, '', '', '', '',
'itemList={{SELECT IF( "{{class:FRD0:alnumx}}"="native","checkbox,date,time,datetime,dateJQW,datetimeJQW,extra,gridJQW,text,editor,note,password,radio,select,subrecord,upload", IF("{{class:FRD0:alnumx}}"="action","beforeLoad,beforeSave,beforeInsert,beforeUpdate,beforeDelete,afterLoad,afterSave,afterInsert,afterUpdate,afterDelete,sendMail", "fieldset,pill") ) }}',
'itemList={{SELECT IF( "{{class:FRD0:alnumx}}"="native","checkbox,date,time,datetime,dateJQW,datetimeJQW,extra,gridJQW,text,editor,note,password,radio,select,subrecord,upload", IF("{{class:FRD0:alnumx}}"="action","beforeLoad,beforeSave,beforeInsert,beforeUpdate,beforeDelete,afterLoad,afterSave,afterInsert,afterUpdate,afterDelete,sendMail", "fieldset,pill,templateGroup") ) }}',
100, '', 'yes', '', '', '', '', ''),
(2, 'subrecordOption', 'Subrecord Option', 'show', 'checkbox', 'all', 'native', 200, 0, 0, '', '', '', '', '', 100, '', 'no', '', '', '',
'', ''),
......
Markdown is supported
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