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

#3063, Radios / Checkboxes als Buttons (Bootstrap)

Implemented for Radios. Checkbox is still open.

Index.rst, AbstractBuildForm.php, BuildFormBootstrap.php, Constants.php: split buildRadio() in constructRadioPlain() and constructRadioButton. After several tries to make a base function for both construct variants, CR decided that the code is much more easier to read with to complete separate layout functions.

AbstractBuildForm.php: Notes of input elements as well as the text of a 'Note' FormElement are now wrapped in the class 'qfq-note' - this aligns the text to the label baseline.
parent 0538b123
......@@ -8,6 +8,8 @@
.. ,,
..
.. --------------------------------------------------
.. External Links: `Bootstrap <http://getbootstrap.com/>`_:
..
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
......@@ -1140,7 +1142,7 @@ Type: radio
* Radio Buttons will be built from one of three sources:
* 'sql1': E.g. *{{!SELECT type AS label FROM car }}* or *{{!SELECT type AS label, typeNr AS id FROM car}}* or *{{!SHOW tables}}*.
1. 'sql1': E.g. *{{!SELECT type AS label FROM car }}* or *{{!SELECT type AS label, typeNr AS id FROM car}}* or *{{!SHOW tables}}*.
* Resultset format 'named': column 'label' and optional a column 'id'.
* Resultset format 'index':
......@@ -1148,15 +1150,16 @@ Type: radio
* One column in resultset >> first column represents *label*
* Two or more columns in resultset >> first column represents *id* and second column represents *label*.
* *FormElement.parameter*:
2. *FormElement.parameter*:
* *itemList* = `<attribute>` E.g.: *itemList=red,blue,orange* or *itemList=1:red,2:blue:3:orange*
* Definition of the *enum* or *set* field (only labels, ids are not possible).
3. Definition of the *enum* or *set* field (only labels, ids are not possible).
* *FormElement.maxlength* = `<value>`
* Applies only to 'plain' radio elements (not the Bootstrap 'buttonClass' from below)
* *vertical* or *horizontal* alignment:
* `<value>`: '', 0, 1 - The radios will be aligned *vertical*.
......@@ -1169,6 +1172,19 @@ Type: radio
* *emptyItemAtEnd*: Existence of this item inserts an empty entry at the end of the selectlist.
* *emptyHide*: Existence of this item hides the empty entry. This is useful for e.g. Enums, which have an empty
entry but the empty value should not be an option to be selected.
* *buttonClass*: Instead of the plain radio fields, Bootstrap
`buttons <http://getbootstrap.com/javascript/#buttons-checkbox-radio>`_. are rendered as `radio` elements. Use
one of the following `classes <http://getbootstrap.com/css/#buttons-options>`_:
* `btn-default` (default, grey),
* `btn-primary` (blue),
* `btn-success` (green),
* `btn-info` (light blue),
* `btn-warning` (orange),
* `btn-danger` (red).
With a given *buttonClass*, all buttons (=radios) are rendered horizontal. A value in *FormElement.maxlength* has no effect.
* *No preselection*:
......
......@@ -1326,8 +1326,6 @@ abstract class AbstractBuildForm {
/**
* Build HTML 'radio' element.
*
* Checkboxes will only be submitted, if they are checked. Therefore, a hidden element with the unchecked value will be transfered first.
*
* Format: <input type="hidden" name="$htmlFormElementId" value="$valueUnChecked">
* <input name="$htmlFormElementId" type="radio" [autofocus="autofocus"]
* [required="required"] [disabled="disabled"] value="<value>" [checked="checked"] >
......@@ -1342,6 +1340,118 @@ abstract class AbstractBuildForm {
* @throws \qfq\UserFormException
*/
public function buildRadio(array $formElement, $htmlFormElementId, $value, array &$json, $mode = FORM_LOAD) {
if (isset($formElement[FE_BUTTON_CLASS])) {
if ($formElement[FE_BUTTON_CLASS] == '') {
$formElement[FE_BUTTON_CLASS] = 'btn-default';
}
return $this->constructRadioButton($formElement, $htmlFormElementId, $value, $json, $mode);
} else {
return $this->constructRadioPlain($formElement, $htmlFormElementId, $value, $json, $mode);
}
}
/**
* Build Bootstrap Button 'radio' element.
*
* <div class="btn-group" data-toggle="buttons">
*
* <label class="btn btn-primary active">
* <input type="radio" name="options" id="option1" autocomplete="off" checked> Radio 1 (preselected)
* </label>
*
* <label class="btn btn-primary">
* <input type="radio" name="options" id="option2" autocomplete="off"> Radio 2
* </label>
*
* <label class="btn btn-primary">
* <input type="radio" name="options" id="option3" autocomplete="off"> Radio 3
* </label>
*
* </div>
*
* @param array $formElement
* @param $htmlFormElementId
* @param $value
* @param array $json
* @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
* @return string
* @throws CodeException
* @throws \qfq\UserFormException
*/
private function constructRadioButton(array $formElement, $htmlFormElementId, $value, array &$json, $mode = FORM_LOAD) {
$itemKey = array();
$itemValue = array();
// Fill $itemKey & $itemValue
$this->getKeyValueListFromSqlEnumSpec($formElement, $itemKey, $itemValue);
$attributeBase = $this->getAttributeFeMode($formElement[FE_MODE]);
$attributeBase .= $this->getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]);
$attributeBase .= Support::doAttribute('name', $htmlFormElementId);
$attributeBase .= Support::doAttribute('type', $formElement[FE_TYPE]);
$attributeBase .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
$attribute = $attributeBase;
if (isset($formElement['autofocus'])) {
$attribute .= Support::doAttribute('autofocus', $formElement['autofocus']);
}
$html = $this->buildNativeHidden($htmlFormElementId, $value);
for ($ii = 0; $ii < count($itemValue); $ii++) {
$classActive = '';
$attribute .= Support::doAttribute('value', $itemKey[$ii]);
$attribute .= Support::doAttribute('title', $formElement['tooltip']);
if ($itemKey[$ii] === $value) {
$attribute .= Support::doAttribute('checked', 'checked');
$classActive = ' active';
}
$htmlElement = '<input ' . $attribute . '>' . $itemValue[$ii];
$htmlElement = Support::wrapTag("<label class='btn " . $formElement[FE_BUTTON_CLASS] . "$classActive'>", $htmlElement);
$html .= $htmlElement;
// Init for the next round
$attribute = $attributeBase;
}
$html = Support::wrapTag('<div class="btn-group" data-toggle="buttons">', $html);
$json = $this->getJsonElementUpdate($htmlFormElementId, $value, $formElement[FE_MODE]);
return $html;
}
/**
* Build plain HTML 'radio' element.
*
* Format: <input type="hidden" name="$htmlFormElementId" value="$valueUnChecked">
* <input name="$htmlFormElementId" type="radio" [autofocus="autofocus"]
* [required="required"] [disabled="disabled"] value="<value>" [checked="checked"] >
*
* @param array $formElement
* @param $htmlFormElementId
* @param $value
* @param array $json
* @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
* @return string
* @throws CodeException
* @throws \qfq\UserFormException
*/
private function constructRadioPlain(array $formElement, $htmlFormElementId, $value, array &$json, $mode = FORM_LOAD) {
if (isset($formElement[FE_BUTTON_CLASS])) {
return $this->constructRadioButton($formElement, $htmlFormElementId, $value, $json, $mode);
}
$itemKey = array();
$itemValue = array();
......@@ -1355,22 +1465,20 @@ abstract class AbstractBuildForm {
$attributeBase .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
$jj = 0;
$flagFirst = true;
$orientation = ($formElement['maxLength'] > 1) ? ALIGN_HORIZONTAL : ALIGN_VERTICAL;
$radioClass = ($orientation === ALIGN_HORIZONTAL) ? 'radio-inline' : 'radio';
$br = '';
$attribute = $attributeBase;
if (isset($formElement['autofocus'])) {
$attribute .= Support::doAttribute('autofocus', $formElement['autofocus']);
}
$html = $this->buildNativeHidden($htmlFormElementId, $value);
for ($ii = 0; $ii < count($itemValue); $ii++) {
$jj++;
$attribute = $attributeBase; //
if ($flagFirst) {
$flagFirst = false;
if (isset($formElement['autofocus']))
$attribute .= Support::doAttribute('autofocus', $formElement['autofocus']);
}
$attribute .= Support::doAttribute('value', $itemKey[$ii]);
$attribute .= Support::doAttribute('title', $formElement['tooltip']);
......@@ -1402,6 +1510,8 @@ abstract class AbstractBuildForm {
$htmlElement = Support::wrapTag("<div class='$radioClass'>", $htmlElement) . $br;
$html .= $htmlElement;
$attribute = $attributeBase;
}
$json = $this->getJsonElementUpdate($htmlFormElementId, $value, $formElement[FE_MODE]);
......@@ -2279,7 +2389,7 @@ abstract class AbstractBuildForm {
* @return mixed
*/
public function buildNote(array $formElement, $htmlFormElementId, $value, array &$json, $mode = FORM_LOAD) {
return $value;
return Support::wrapTag("<div class='qfq-note'>", $value);
}
/**
......@@ -2525,26 +2635,4 @@ EOT;
abstract public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementId);
/**
* Create a delete link.
*
* @param $table
* @param $recordId
* @param $symbol
* @param $toolTip
* @return string
*/
// private function createDeleteLink($table, $recordId, $symbol, $toolTip) {
//
// if ($this->showDebugInfo) {
// $toolTip .= PHP_EOL . "table = '$table'" . PHP_EOL . "id = '$recordId'";
// }
//
// $url = $this->createDeleteUrl('', $table, $recordId);
//
// return Support::wrapTag('<a ' . Support::doAttribute('href', $url) . ' title="' . $toolTip . '">', $symbol);
//
// }
}
\ No newline at end of file
......@@ -405,25 +405,6 @@ EOF;
return $html;
}
/**
* @param array $formElement
* @param string $htmlElement
* @return string
*/
// public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementId) {
// $html = '';
//
// $htmlLabel = $this->buildLabel($htmlFormElementId, $formElement[FE_LABEL]);
//
// $html .= $this->wrapItem(WRAP_SETUP_LABEL, $htmlLabel);
// $html .= $this->wrapItem(WRAP_SETUP_INPUT, $htmlElement);
// $html .= $this->wrapItem(WRAP_SETUP_NOTE, $formElement[FE_NOTE], true);
//
// $html = $this->wrapItem(WRAP_SETUP_ELEMENT, $html);
//
// return $html;
// }
/**
* @param array $formElement Complete FormElement, especially some FE_WRAP
* @param string $htmlElement Content to wrap.
......
......@@ -567,6 +567,7 @@ const FE_TEMPLATE_GROUP_REMOVE_TEXT = 'tgRemoveText';
const FE_TEMPLATE_GROUP_CLASS = 'tgClass';
const FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH = 5;
const FE_TEMPLATE_GROUP_NAME_PATTERN = '%d';
const FE_BUTTON_CLASS = 'buttonClass';
const RETYPE_FE_NAME_EXTENSION = 'RETYPE';
// FormElement Types
......
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