diff --git a/docs/50_Forms/Input.md b/docs/50_Forms/Input.md index 90dc83d57e3f3b152c8021acaec16d16954a0c5a..b60d6c9e59759260158c6f5b067057698d3c1ced 100644 --- a/docs/50_Forms/Input.md +++ b/docs/50_Forms/Input.md @@ -31,21 +31,22 @@ Content: Key | Description --- | --- +hint | optional: Hint text above form field label | label in front of the input element name | name attribute for sending form data value | value of the input field/ visible text; for checkbox and radio: the data to send when sending a form -### Example +### Examples #### Simple text input field ```php -$renderAdminLTE->getFormInput(array ( +$renderAdminLTE->getFormInput([ 'label' => 'Enter firstname', 'type' => 'text', 'name' => 'firstname', 'value' => '', -)); +]); ``` You get a label, an input field wrapped in a ``<div class="form-group row">``. @@ -72,8 +73,6 @@ With using append and prepend keys you can create gray boxes on left and right. For these input types you can use multiple elements. You must wrap a bunch of input elements into ``<div class="form-group row">`` "manually". - - ```php echo '<div class="form-group">' . $renderAdminLTE->getFormInput([ @@ -91,3 +90,60 @@ echo '<div class="form-group">' .'</div>' ; ``` + +#### Simple range slider + +A simple slider: + +```php +$renderAdminLTE->getFormInput([ + 'tag' => 'input', + 'type' => 'range', // <----------- + 'min' => 0, + 'max' => 3, + 'step' => 1, + 'label' => 'Select 0..6', +]); +``` + +#### Range with labels + +To add labels you need a datalist for the values and the labels to show, eg + +```html +<datalist id="datalist-range"> + <option value="0" label="no risc"></option> + <option value="1" label="1"></option> + <option value="2" label="2"></option> + <option value="3" label="medium"></option> + <option value="4" label="4"></option> + <option value="5" label="5"></option> + <option value="6" label="critical"></option> +</datalist> +``` + +The id you ned to reference in the key "datalist": + +```php +$renderAdminLTE->getFormInput([ + 'tag' => 'input', + 'type' => 'range', + 'min' => 0, + 'max' => 6, + 'step' => 1, + 'label' => 'Select 0..6', + 'datalist' => 'datalist-range', // <----------- +]); +``` + +For the datalist you need to extend your css: + +```css +datalist { + display: flex; + flex-direction: column; + justify-content: space-between; + writing-mode: vertical-lr; + width: 100%; +} +``` diff --git a/docs/50_Forms/Select.md b/docs/50_Forms/Select.md index 415a7f312baf18ebb6511bff41847cc410531e1a..e83f6623f2a6a18e6a8e37fe1faa8b063a36c3f9 100644 --- a/docs/50_Forms/Select.md +++ b/docs/50_Forms/Select.md @@ -26,6 +26,7 @@ Styling for select tag: Key | Description --- | --- +bootstrap-select | optional: use bootstrap-select pugin with live search (you need to load the plugin in your page - see example below) class | optional: additional css classes size | optional: visible option lines @@ -33,6 +34,7 @@ Content: Key | Description --- | --- +hint | optional: Hint text above form field name | name attribute for sending form data value | value of the input field/ visible text; for checkbox and radio: the data to send when sending a form @@ -41,8 +43,7 @@ value | value of the input field/ visible text; for checkbox and radio: the d #### Simple select box ```php -$renderAdminLTE->getFormSelect(array -( +$renderAdminLTE->getFormSelect([ 'label' => 'Select contact', 'name' => 'contact', 'tag' => 'select', @@ -53,7 +54,7 @@ $renderAdminLTE->getFormSelect(array ['value' => '2', 'label' => 'Dick', 'selected' => 1 ], ['value' => '3', 'label' => 'Harry'], ], -)); +]); ``` You get a label, an select box wrapped in a ``<div class="form-group row">``. @@ -73,3 +74,31 @@ You get a label, an select box wrapped in a ``<div class="form-group row">``. </div> </div> ``` + +#### Select box with search field + +We added support for the plugin **bootstrap-select**. +Get its files from the website and put it into a vendor directory. + +Website: <https://developer.snapappointments.com/bootstrap-select/> + +In your html header section add its css and javascript: + +```html + <!-- bootstrap-select --> + <link rel="stylesheet" href="../vendor/bootstrap-select/1.13.18/css/bootstrap-select.min.css"> + <script src="../vendor/bootstrap-select/1.13.18/js/bootstrap-select.min.js"></script> +``` + +In your select box add ``'bootstrap-select' => 1,`` : + +```php +$renderAdminLTE->getFormSelect([ + 'label' => 'Select contact', + 'name' => 'contact', + 'tag' => 'select', + 'size' => 1, + 'bootstrap-select' => 1, // <---------- + 'options' => [ ... ], +]); +``` diff --git a/docs/50_Forms/Textarea.md b/docs/50_Forms/Textarea.md index 69f28d32ddadaca76e02f04ec2b3f7cf49f1477a..34b8de4874566dc8b86ebd640ca710d568d1c5df 100644 --- a/docs/50_Forms/Textarea.md +++ b/docs/50_Forms/Textarea.md @@ -29,6 +29,7 @@ Content: Key | Description --- | --- +hint | optional: Hint text above form field label | label in front of the Textarea element name | name attribute for sending form data value | value of the textarea; visible text @@ -40,11 +41,11 @@ value | value of the textarea; visible text You get a label and a textare wrapped in a ``<div class="form-group row">``. ```php -$renderAdminLTE->getFormTextarea(array ( +$renderAdminLTE->getFormTextarea([ 'label' => 'Enter text', 'name' => 'textdata', 'value' => 'Here is some text...', -)); +]); ``` #### Html editor @@ -72,7 +73,7 @@ By adding ``'type' => 'html'`` an html editor will be rendered by adding a class ```php $renderAdminLTE->getFormTextarea(array ( - 'type' => 'html', + 'type' => 'html', // <---------- 'label' => 'Enter text', 'name' => 'textdata', 'value' => 'Here is some text...', diff --git a/public_html/classes/htmlelements.class.php b/public_html/classes/htmlelements.class.php index 91943c7c97d4a3226b6a2c457496ed85b08ef447..18d58b69e46f14477046359e68e5a6d732a85f52 100755 --- a/public_html/classes/htmlelements.class.php +++ b/public_html/classes/htmlelements.class.php @@ -15,26 +15,39 @@ * - icon - will be added as <i class="[icon value]"></i> to the label * * @author Axel + * + * 2024-07-04 <axel.hahn@unibe.ch> added type declarations; update php docs */ -class htmlelements { +class htmlelements +{ /** * set of auto generated icon prefixes - * @var type + * @var array + */ + var $_aIcons = array( + // 'fa-'=>'fa ', + ); + + /** + * label of an html tag (pseudo attribute) + * @var string */ - var $_aIcons=array( - // 'fa-'=>'fa ', - ); - var $_sLabel = ''; + + /** + * hash of attributes and values of an html tag + * @var array + */ var $_aAttributes = array(); - + // ---------------------------------------------------------------------- // CONSTRUCTOR // ---------------------------------------------------------------------- - - public function __construct() { + + public function __construct() + { return true; } @@ -43,25 +56,26 @@ class htmlelements { // PRIVATE FUNCTIONS // // ---------------------------------------------------------------------- - - + + /** * generate html attibutes with all internal attributes key -> values * @return string */ - protected function _addAttributes() { + protected function _addAttributes(): string + { $sReturn = ''; foreach ($this->_aAttributes as $sAttr => $sValue) { - if(is_array($sValue)){ - echo "ERROR: an html tag was defined with array in attribute [$sAttr]:<br><pre>".print_r($this->_aAttributes, 1)."</pre>"; + if (is_array($sValue)) { + echo "ERROR: an html tag was defined with array in attribute [$sAttr]:<br><pre>" . print_r($this->_aAttributes, 1) . "</pre>"; } - $sReturn .= ' '.$sAttr . '="' . $sValue . '"'; - + $sReturn .= ' ' . $sAttr . '="' . $sValue . '"'; + } return $sReturn; } - - + + /** * internal helper: fetch all attributes from key-value hash; * Specialties here: @@ -71,17 +85,18 @@ class htmlelements { * @param array $aAttributes * @return boolean */ - protected function _setAttributes($aAttributes){ - $this->_sLabel=''; - if(isset($aAttributes['icon']) && $aAttributes['icon']){ - $this->_sLabel.=$this->getIcon($aAttributes['icon']); + protected function _setAttributes(array $aAttributes): bool + { + $this->_sLabel = ''; + if (isset($aAttributes['icon']) && $aAttributes['icon']) { + $this->_sLabel .= $this->getIcon($aAttributes['icon']); unset($aAttributes['icon']); } - if(isset($aAttributes['label']) && $aAttributes['label']){ + if (isset($aAttributes['label']) && $aAttributes['label']) { $this->_sLabel .= $aAttributes['label']; unset($aAttributes['label']); } - $this->_aAttributes=$aAttributes; + $this->_aAttributes = $aAttributes; return true; } @@ -91,7 +106,7 @@ class htmlelements { // HTML GENERIC // // ---------------------------------------------------------------------- - + /** * generic function to get html code for a single tag * @@ -100,12 +115,13 @@ class htmlelements { * @param boolean $bCloseTag optional: set false if tag has no closing tag (= ending with "/>") * @return type */ - public function getTag($sTag, $aAttributes, $bCloseTag=true){ + public function getTag(string $sTag, array $aAttributes, bool $bCloseTag = true): string + { $sTpl = $bCloseTag ? "<$sTag%s>%s</$sTag>" : "<$sTag %s/>%s"; $this->_setAttributes($aAttributes); return sprintf($sTpl, $this->_addAttributes(), $this->_sLabel); } - + // ---------------------------------------------------------------------- // // PUBLIC FUNCTIONS @@ -114,28 +130,28 @@ class htmlelements { // ---------------------------------------------------------------------- /** - * helper detect prefix of a string add prefix of a framework + * get html code for an icon + * includes a helper detect prefix of a string add prefix of a framework * i.e. value "fa-close" detects font awesome and adds "fa " as prefix * - * @param string $sIconclass - * @return boolean + * @param string $sIconclass name of the icon + * @return string */ - public function getIcon($sIconclass=false){ - if(!$sIconclass){ + public function getIcon(string $sIconclass = ''): string + { + if (!$sIconclass) { return ''; } - $sPrefix=''; - foreach ($this->_aIcons as $sPrefix =>$add) { - if (strpos($sIconclass, $sPrefix)===0){ - $sPrefix=$add; + $sPrefix = ''; + foreach ($this->_aIcons as $sPrefix => $add) { + if (strpos($sIconclass, $sPrefix) === 0) { + $sPrefix = $add; continue; } } - // do not use this .. it overrides internal attribute vars - // return $this->getTag('i', array('class'=>$sPrefix.$sIconclass)); - return '<i class="'.$sPrefix.$sIconclass.'"></i> '; + return '<i class="' . $sPrefix . $sIconclass . '"></i> '; } - + // ---------------------------------------------------------------------- // @@ -150,7 +166,8 @@ class htmlelements { * @param array $aAttributes attributes of the select tag * @return string */ - public function getFormInput($aAttributes){ + public function getFormInput($aAttributes) + { $sTpl = '<input %s/>'; $this->_setAttributes($aAttributes); return sprintf($sTpl, $this->_addAttributes()); @@ -161,7 +178,8 @@ class htmlelements { * @param array $aAttributes attributes of the option tag * @return string */ - public function getFormOption($aAttributes){ + public function getFormOption(array $aAttributes): string + { $sTpl = '<option %s>%s</option>'; $this->_setAttributes($aAttributes); return sprintf($sTpl, $this->_addAttributes(), $this->_sLabel); @@ -173,50 +191,57 @@ class htmlelements { * @param array $aOptions array for all option fields * @return string */ - public function getFormSelect($aAttributes, $aOptions=array()){ + public function getFormSelect(array $aAttributes, array $aOptions = array()) + { // $sTpl = '<select %s>%s</select>'; - if(!count($aOptions)){ + if (!count($aOptions)) { return false; } - $sOptions=''; - foreach($aOptions as $aOptionAttributes){ + $sOptions = ''; + foreach ($aOptions as $aOptionAttributes) { // $sOptions.=$this->getFormOption($aOptionAttributes); - $sOptions.=$this->getTag('option', $aOptionAttributes); + $sOptions .= $this->getTag('option', $aOptionAttributes); } - $aAttributes['label']=$sOptions; + $aAttributes['label'] = $sOptions; return $this->getTag('select', $aAttributes); - /* - $this->_setAttributes($aAttributes); - return sprintf($sTpl, $this->_addAttributes(), $sOptions); - * - */ } - public function getTable($aHead, $aBody, $aTableAttributes=array()){ - $sReturn=''; - $sTdata=''; - $sThead=''; + + /** + * Generates an HTML table based on the provided header and body arrays. + * + * @param array $aHead An array of strings representing the table headers. + * @param array $aBody A 2-dimensional array of strings representing the table body rows and cells. + * @param array $aTableAttributes An optional array of attributes to be applied to the table element. + * @return string The HTML code for the generated table. + */ + public function getTable(array $aHead, array $aBody, array $aTableAttributes = []): string + { + $sReturn = ''; + $sTdata = ''; + $sThead = ''; $sTpl = '<table %s>' - . '<thead><tr>%s</tr></thead>' - . '<tbody>%s</tbody>' - . '</table>'; - - foreach($aHead as $sTh){ - $sThead.='<th>'.$sTh.'</th>'; + . '<thead><tr>%s</tr></thead>' + . '<tbody>%s</tbody>' + . '</table>'; + + foreach ($aHead as $sTh) { + $sThead .= '<th>' . $sTh . '</th>'; } - foreach($aBody as $aTr){ - $sTdata.='<tr>'; - foreach($aTr as $sTd){ - $sTdata.='<td>'.$sTd.'</td>'; + foreach ($aBody as $aTr) { + $sTdata .= '<tr>'; + foreach ($aTr as $sTd) { + $sTdata .= '<td>' . $sTd . '</td>'; } - $sTdata.='</tr>'; + $sTdata .= '</tr>'; } $this->_setAttributes($aTableAttributes); - return sprintf($sTpl, - $this->_addAttributes(), - $sThead, - $sTdata - ); + return sprintf( + $sTpl, + $this->_addAttributes(), + $sThead, + $sTdata + ); } } diff --git a/public_html/classes/render-adminlte.class.php b/public_html/classes/render-adminlte.class.php index 1035af9dac0f6e7adc4704f6e9cca0fa36851aca..83cf626c624afc23bc6237422c52be5c2b01d7b4 100755 --- a/public_html/classes/render-adminlte.class.php +++ b/public_html/classes/render-adminlte.class.php @@ -1,156 +1,171 @@ <?php require_once 'htmlelements.class.php'; /** - * ====================================================================== + * ______________________________________________________________________ + * + * _ __ __ _ + * | || \/ || |__ Institute for Medical Education + * |_||_|\/|_||____| University of Bern + * + * ______________________________________________________________________ * * RENDERER FOR ADNINLTE template https://adminlte.io - * DOCS: https://adminlte.io/docs/3.2/ - * https://adminlte.io/themes/v3/index3.html + * its docs: https://adminlte.io/docs/3.2/ + * https://adminlte.io/themes/v3/index3.html + * + * This is a php class to render + * - grid layout + * - navigation + * - widgets, components and forms * + * DOCS: https://os-docs.iml.unibe.ch/adminlte-renderer/ * ---------------------------------------------------------------------- * 2023-09-11 <axel.hahn@unibe.ch> add shadows on card + callout * 2023-09-27 <axel.hahn@unibe.ch> add form input fields * 2023-11-17 <axel.hahn@unibe.ch> add tabbed content; "=" renders hamburger item * 2024-05-03 <axel.hahn@unibe.ch> add line in sidebar menu; add getFormSelect + * 2024-05-10 <axel.hahn@unibe.ch> add support for bootstrap-select in getFormSelect + * 2024-05-18 <axel.hahn@unibe.ch> add variable types + * 2024-07-04 <axel.hahn@unibe.ch> added type declarations * ====================================================================== - * - * @author Axel */ -class renderadminlte { +class renderadminlte +{ - var $aPresets=[ + protected array $aPresets = [ - 'bgcolor'=>[ - 'description'=>'background colors', - 'group'=>'styling', - 'values'=>[ + 'bgcolor' => [ + 'description' => 'background colors', + 'group' => 'styling', + 'values' => [ // https://adminlte.io/themes/v3/pages/UI/general.html - ''=>'no value', - 'indigo'=>'indigo', - 'lightblue'=>'', - 'navy'=>'', - 'purple'=>'', - 'fuchsia'=>'', - 'pink'=>'', - 'maroon'=>'', - 'orange'=>'', - 'lime'=>'', - 'teal'=>'', - 'olive'=>'', - - 'black'=>'black', - 'dark'=>'dark gray', - 'gray'=>'gray', - 'light'=>'light gray', + '' => 'no value', + 'indigo' => 'indigo', + 'lightblue' => '', + 'navy' => '', + 'purple' => '', + 'fuchsia' => '', + 'pink' => '', + 'maroon' => '', + 'orange' => '', + 'lime' => '', + 'teal' => '', + 'olive' => '', + + 'black' => 'black', + 'dark' => 'dark gray', + 'gray' => 'gray', + 'light' => 'light gray', ] ], - - 'type'=>[ - 'description'=>'type or status like info/ warning/ danger to define a color', - 'group'=>'styling', - 'values'=>[ - ''=>'no value', - 'danger'=>'red', - 'info'=>'aqua', - 'primary'=>'blue', - 'secondary'=>'gray', - 'success'=>'green', - 'warning'=>'yellow', - 'dark'=>'dark gray', - 'gray'=>'gray', + + 'type' => [ + 'description' => 'type or status like info/ warning/ danger to define a color', + 'group' => 'styling', + 'values' => [ + '' => 'no value', + 'danger' => 'red', + 'info' => 'aqua', + 'primary' => 'blue', + 'secondary' => 'gray', + 'success' => 'green', + 'warning' => 'yellow', + 'dark' => 'dark gray', + 'gray' => 'gray', ] ], - 'shadow'=>[ - 'description'=>'use a shadow', - 'group'=>'styling', - 'values'=>[ - ''=>'no value', - 'none'=>'none', - 'small'=>'small', - 'regular'=>'regular', - 'large'=>'large' + 'shadow' => [ + 'description' => 'use a shadow', + 'group' => 'styling', + 'values' => [ + '' => 'no value', + 'none' => 'none', + 'small' => 'small', + 'regular' => 'regular', + 'large' => 'large' ] ], - 'size'=>[ - 'description'=>'set a size', - 'group'=>'styling', - 'values'=>[ - ''=>'no value', - 'lg'=>'', - 'sm'=>'', - 'xs'=>'', - 'flat'=>'', + 'size' => [ + 'description' => 'set a size', + 'group' => 'styling', + 'values' => [ + '' => 'no value', + 'lg' => '', + 'sm' => '', + 'xs' => '', + 'flat' => '', ] ], - 'variant'=>[ - 'description'=>'coloring style', - 'group'=>'styling', - 'values'=>[ - ''=>'no value', - 'outline'=>'small stripe on top', - 'solid'=>'full filled widget', - 'gradient'=>'full filled with gradient', + 'variant' => [ + 'description' => 'coloring style', + 'group' => 'styling', + 'values' => [ + '' => 'no value', + 'outline' => 'small stripe on top', + 'solid' => 'full filled widget', + 'gradient' => 'full filled with gradient', ] ], - 'visibility'=>[ - 'description'=>'', - 'group'=>'customizing', - 'values'=>[ - ''=>'no value', - '0'=>'hide', - '1'=>'show', + 'visibility' => [ + 'description' => '', + 'group' => 'customizing', + 'values' => [ + '' => 'no value', + '0' => 'hide', + '1' => 'show', ] ], // for keys: state - 'windowstate'=>[ - 'description'=>'state of a resizable widget', - 'group'=>'customizing', - 'values'=>[ - ''=>'no value', - 'collapsed'=>'header only', - 'maximized'=>'full window', + 'windowstate' => [ + 'description' => 'state of a resizable widget', + 'group' => 'customizing', + 'values' => [ + '' => 'no value', + 'collapsed' => 'header only', + 'maximized' => 'full window', ] ], // for keys: dismissable - 'yesno'=>[ - 'description'=>'', - 'group'=>'customizing', - 'values'=>[ - ''=>'no value', - '0'=>'no', - '1'=>'yes', + 'yesno' => [ + 'description' => '', + 'group' => 'customizing', + 'values' => [ + '' => 'no value', + '0' => 'no', + '1' => 'yes', ] ], ]; - var $_aValueMappings=[ - 'shadow'=>[ - 'default' => '', - 'none' => 'shadow-none', - 'small' => 'shadow-small', - 'regular' => 'shadow', - 'large' => 'shadow-lg', + protected array $_aValueMappings = [ + 'shadow' => [ + 'default' => '', + 'none' => 'shadow-none', + 'small' => 'shadow-small', + 'regular' => 'shadow', + 'large' => 'shadow-lg', ] ]; - var $_aElements=[]; - + protected array $_aElements = []; + /** - * instance of htmlelements + * instance of htmlelements object * @var object */ - var $_oHtml=false; - - + protected object $_oHtml; + + // ---------------------------------------------------------------------- // // CONSTRUCTOR // // ---------------------------------------------------------------------- - public function __construct() { - $this->_oHtml=new htmlelements(); + public function __construct() + { + $this->_oHtml = new htmlelements(); $this->_initElements(); - return true; + // return true; } // ---------------------------------------------------------------------- @@ -158,343 +173,380 @@ class renderadminlte { // PRIVATE FUNCTIONS // // ---------------------------------------------------------------------- - + /** * used in cosntructor * initialize all element definitions + * @return void */ - protected function _initElements(){ - $this->_aElements=[ + protected function _initElements(): void + { + $this->_aElements = [ // ------------------------------------------------------------ - 'alert'=>[ - 'label'=>'Alert', - 'description'=>'Colored box with title and a text', - 'method'=>'getAlert', - - 'params'=>[ - 'type' => ['select'=>$this->aPresets['type'], 'example_value'=>'warning'], - 'dismissible' => ['select'=>$this->aPresets['yesno'], 'example_value'=>''], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'' + 'alert' => [ + 'label' => 'Alert', + 'description' => 'Colored box with title and a text', + 'method' => 'getAlert', + + 'params' => [ + 'type' => ['select' => $this->aPresets['type'], 'example_value' => 'warning'], + 'dismissible' => ['select' => $this->aPresets['yesno'], 'example_value' => ''], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => '' ], - 'title' => [ - 'description'=>'Title in a bit bigger font', - 'group'=>'content', - 'example_value'=>'Alert title' + 'title' => [ + 'description' => 'Title in a bit bigger font', + 'group' => 'content', + 'example_value' => 'Alert title' ], - 'text' => [ - 'description'=>'Message text', - 'group'=>'content', - 'example_value'=>'I am a message. Read me, please.' + 'text' => [ + 'description' => 'Message text', + 'group' => 'content', + 'example_value' => 'I am a message. Read me, please.' ], ] ], // ------------------------------------------------------------ - 'badge'=>[ - 'label'=>'Badge', - 'description'=>'Tiny additional info; mostly as counter', - 'method'=>'getBadge', - - 'params'=>[ - 'type' => ['select'=>$this->aPresets['type'], 'example_value'=>'danger'], - 'bgcolor' => ['select'=>$this->aPresets['bgcolor'], 'example_value'=>''], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'' + 'badge' => [ + 'label' => 'Badge', + 'description' => 'Tiny additional info; mostly as counter', + 'method' => 'getBadge', + + 'params' => [ + 'type' => ['select' => $this->aPresets['type'], 'example_value' => 'danger'], + 'bgcolor' => ['select' => $this->aPresets['bgcolor'], 'example_value' => ''], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => '' ], - 'id' => [ - 'group'=>'customizing', - 'description'=>'optional: id attribute', - 'example_value'=>'' + 'id' => [ + 'group' => 'customizing', + 'description' => 'optional: id attribute', + 'example_value' => '' ], - 'title' => [ - 'group'=>'content', - 'description'=>'optional: title attribute for mouseover', - 'example_value'=>'Errors: 5' + 'title' => [ + 'group' => 'content', + 'description' => 'optional: title attribute for mouseover', + 'example_value' => 'Errors: 5' ], - 'text' => [ - 'group'=>'content', - 'description'=>'Text or value in the badge', - 'example_value'=>'5' + 'text' => [ + 'group' => 'content', + 'description' => 'Text or value in the badge', + 'example_value' => '5' ], ] ], // ------------------------------------------------------------ - 'button'=>[ - 'label'=>'Button', - 'description'=>'Buttons<br>In this component you can add other parmeter keys too - these will be added as attributes in the button tag.', - 'method'=>'getButton', - - 'params'=>[ - 'type' => ['select'=>$this->aPresets['type'], 'example_value'=>'primary'], - 'size' => ['select'=>$this->aPresets['size'], 'example_value'=>''], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'' + 'button' => [ + 'label' => 'Button', + 'description' => 'Buttons<br>In this component you can add other parmeter keys too - these will be added as attributes in the button tag.', + 'method' => 'getButton', + + 'params' => [ + 'type' => ['select' => $this->aPresets['type'], 'example_value' => 'primary'], + 'size' => ['select' => $this->aPresets['size'], 'example_value' => ''], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => '' ], - 'text' => [ - 'group'=>'content', - 'description'=>'Text/ html code on the button', - 'example_value'=>'Click me' + 'text' => [ + 'group' => 'content', + 'description' => 'Text/ html code on the button', + 'example_value' => 'Click me' ], ] ], // ------------------------------------------------------------ - 'callout'=>[ - 'label'=>'Callout', - 'description'=>'Kind of infobox', - 'method'=>'getCallout', - - 'params'=>[ - 'type' => ['select'=>$this->aPresets['type'], 'example_value'=>'danger'], - 'shadow' => ['select'=>$this->aPresets['shadow'], 'example_value'=>''], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'' + 'callout' => [ + 'label' => 'Callout', + 'description' => 'Kind of infobox', + 'method' => 'getCallout', + + 'params' => [ + 'type' => ['select' => $this->aPresets['type'], 'example_value' => 'danger'], + 'shadow' => ['select' => $this->aPresets['shadow'], 'example_value' => ''], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => '' ], - 'title' => [ - 'group'=>'content', - 'description'=>'Title in a bit bigger font', - 'example_value'=>'I am a callout' + 'title' => [ + 'group' => 'content', + 'description' => 'Title in a bit bigger font', + 'example_value' => 'I am a callout' ], - 'text' => [ - 'group'=>'content', - 'description'=>'Message text', - 'example_value'=>'Here is some description to whatever.' + 'text' => [ + 'group' => 'content', + 'description' => 'Message text', + 'example_value' => 'Here is some description to whatever.' ], ] ], // ------------------------------------------------------------ - 'card'=>[ - 'label'=>'Card', - 'description'=>'Content box with header, text, footer', - 'method'=>'getCard', - - 'params'=>[ - 'type' => ['select'=>$this->aPresets['type'], 'example_value'=>'primary'], - 'variant' => ['select'=>$this->aPresets['variant'], 'example_value'=>'outline'], - 'shadow' => ['select'=>$this->aPresets['shadow'], 'example_value'=>''], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'' + 'card' => [ + 'label' => 'Card', + 'description' => 'Content box with header, text, footer', + 'method' => 'getCard', + + 'params' => [ + 'type' => ['select' => $this->aPresets['type'], 'example_value' => 'primary'], + 'variant' => ['select' => $this->aPresets['variant'], 'example_value' => 'outline'], + 'shadow' => ['select' => $this->aPresets['shadow'], 'example_value' => ''], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => '' ], - 'state' => [ - 'group'=>'customizing', - 'select'=>$this->aPresets['windowstate'], - 'example_value'=>'' + 'state' => [ + 'group' => 'customizing', + 'select' => $this->aPresets['windowstate'], + 'example_value' => '' ], - - 'tb-collapse' => ['description'=>'show minus symbol as collapse button', 'select'=>$this->aPresets['visibility'], 'example_value'=>''], - 'tb-expand' => ['description'=>'show plus symbol to expand card', 'select'=>$this->aPresets['visibility'], 'example_value'=>''], - 'tb-maximize' => ['description'=>'show maximize button for fullscreen', 'select'=>$this->aPresets['visibility'], 'example_value'=>''], - 'tb-minimize' => ['description'=>'show minimize button to minimize', 'select'=>$this->aPresets['visibility'], 'example_value'=>''], - 'tb-remove' => ['description'=>'show cross symbol to remove card', 'select'=>$this->aPresets['visibility'], 'example_value'=>''], - - 'title' => [ - 'group'=>'content', - 'description'=>'Title in the top row', - 'example_value'=>'I am a card' + + 'tb-collapse' => ['description' => 'show minus symbol as collapse button', 'select' => $this->aPresets['visibility'], 'example_value' => ''], + 'tb-expand' => ['description' => 'show plus symbol to expand card', 'select' => $this->aPresets['visibility'], 'example_value' => ''], + 'tb-maximize' => ['description' => 'show maximize button for fullscreen', 'select' => $this->aPresets['visibility'], 'example_value' => ''], + 'tb-minimize' => ['description' => 'show minimize button to minimize', 'select' => $this->aPresets['visibility'], 'example_value' => ''], + 'tb-remove' => ['description' => 'show cross symbol to remove card', 'select' => $this->aPresets['visibility'], 'example_value' => ''], + + 'title' => [ + 'group' => 'content', + 'description' => 'Title in the top row', + 'example_value' => 'I am a card' ], - 'tools' => [ - 'group'=>'content', - 'description'=>'Html code for the top right', - 'example_value'=>'' + 'tools' => [ + 'group' => 'content', + 'description' => 'Html code for the top right', + 'example_value' => '' ], - 'text' => [ - 'group'=>'content', - 'description'=>'Main content', - 'example_value'=>'Here is some beautiful content.' + 'text' => [ + 'group' => 'content', + 'description' => 'Main content', + 'example_value' => 'Here is some beautiful content.' ], - 'footer' => [ - 'group'=>'content', - 'description'=>'optional: footer content', - 'example_value'=>'Footer' + 'footer' => [ + 'group' => 'content', + 'description' => 'optional: footer content', + 'example_value' => 'Footer' ], ] ], // ------------------------------------------------------------ - 'infobox'=>[ - 'label'=>'Info box', - 'description'=>'Box with icon to highlight a single value; optional with a progress bar', - 'method'=>'getInfobox', - - 'params'=>[ - 'type'=>['select'=>$this->aPresets['type'], 'example_value'=>''], - 'iconbg'=>['select'=>$this->aPresets['type'], 'example_value'=>'info'], - 'shadow'=>['select'=>$this->aPresets['shadow'], 'example_value'=>''], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'' + 'infobox' => [ + 'label' => 'Info box', + 'description' => 'Box with icon to highlight a single value; optional with a progress bar', + 'method' => 'getInfobox', + + 'params' => [ + 'type' => ['select' => $this->aPresets['type'], 'example_value' => ''], + 'iconbg' => ['select' => $this->aPresets['type'], 'example_value' => 'info'], + 'shadow' => ['select' => $this->aPresets['shadow'], 'example_value' => ''], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => '' ], - 'icon'=>[ - 'group'=>'content', - 'description'=>'css class for an icon', - 'example_value'=>'fa-regular fa-thumbs-up' + 'icon' => [ + 'group' => 'content', + 'description' => 'css class for an icon', + 'example_value' => 'fa-regular fa-thumbs-up' ], - 'text'=>[ - 'group'=>'content', - 'description'=>'short information text', - 'example_value'=>'Likes' + 'text' => [ + 'group' => 'content', + 'description' => 'short information text', + 'example_value' => 'Likes' ], - 'number'=>[ - 'group'=>'content', - 'description'=>'a number to highlight', - 'example_value'=>"41,410" + 'number' => [ + 'group' => 'content', + 'description' => 'a number to highlight', + 'example_value' => "41,410" ], - 'progressvalue'=>[ - 'group'=>'content', - 'description'=>'optional: progress value 0..100 to draw a progress bar', - 'example_value'=>70 + 'progressvalue' => [ + 'group' => 'content', + 'description' => 'optional: progress value 0..100 to draw a progress bar', + 'example_value' => 70 ], - 'progresstext'=>[ - 'group'=>'content', - 'description'=>'optional: text below progress bar', - 'example_value'=>'70% Increase in 30 Days' + 'progresstext' => [ + 'group' => 'content', + 'description' => 'optional: text below progress bar', + 'example_value' => '70% Increase in 30 Days' ] ] ], // ------------------------------------------------------------ - 'smallbox'=>[ - 'label'=>'Small box', - 'description'=>'Solid colored box to highlight a single value; optional with a link', - 'method'=>'getSmallbox', - - 'params'=>[ - 'type'=>['select'=>$this->aPresets['type'], 'example_value'=>'info'], - 'shadow'=>['select'=>$this->aPresets['shadow'], 'example_value'=>''], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'' + 'smallbox' => [ + 'label' => 'Small box', + 'description' => 'Solid colored box to highlight a single value; optional with a link', + 'method' => 'getSmallbox', + + 'params' => [ + 'type' => ['select' => $this->aPresets['type'], 'example_value' => 'info'], + 'shadow' => ['select' => $this->aPresets['shadow'], 'example_value' => ''], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => '' ], - 'icon'=>['group'=>'content', 'description'=>'css class for an icon', 'example_value'=>'fa-solid fa-shopping-cart'], - - 'text'=>['group'=>'content', 'description'=>'short information text', 'example_value'=>'New orders'], - 'number'=>['group'=>'content', 'description'=>'a number to highlight', 'example_value'=>"150"], - 'url'=>['group'=>'content', 'description'=>'optional: url to set a link on the bottom', 'example_value'=>'#'], - 'linktext'=>['group'=>'content', 'description'=>'used if a url was given: linked text', 'example_value'=>'More info'] + 'icon' => ['group' => 'content', 'description' => 'css class for an icon', 'example_value' => 'fa-solid fa-shopping-cart'], + + 'text' => ['group' => 'content', 'description' => 'short information text', 'example_value' => 'New orders'], + 'number' => ['group' => 'content', 'description' => 'a number to highlight', 'example_value' => "150"], + 'url' => ['group' => 'content', 'description' => 'optional: url to set a link on the bottom', 'example_value' => '#'], + 'linktext' => ['group' => 'content', 'description' => 'used if a url was given: linked text', 'example_value' => 'More info'] ] ], // ------------------------------------------------------------ - 'input'=>[ - 'label'=>'Form: input', - 'description'=>'Input form fiels', - 'method'=>'getFormInput', - - 'params'=>[ - 'label' => [ - 'group'=>'styling', - 'description'=>'label for the input field', - 'example_value'=>'Enter something' + 'input' => [ + 'label' => 'Form: input', + 'description' => 'Input form fiels', + 'method' => 'getFormInput', + + 'params' => [ + 'label' => [ + 'group' => 'styling', + 'description' => 'label for the input field', + 'example_value' => 'Enter something' ], - 'type'=>['select'=> [ - 'description'=>'type or input field', - 'group'=>'styling', - 'values'=>[ - 'text'=>'text', - 'password'=>'password', - 'email'=>'email', - 'hidden'=>'hidden', - - 'button'=>'button', - 'checkbox'=>'checkbox', - 'color'=>'color', - 'date'=>'date', - 'datetime-local'=>'datetime-local', - 'email'=>'email', - 'file'=>'file', - 'hidden'=>'hidden', - 'image'=>'image', - 'month'=>'month', - 'number'=>'number', - 'password'=>'password', - 'radio'=>'radio', - 'range'=>'range', - 'reset'=>'reset', - 'search'=>'search', - 'submit'=>'submit', - 'tel'=>'tel', - 'text'=>'text', - 'time'=>'time', - 'url'=>'url', - 'week'=>'week', - ] - ], - 'example_value'=>'text' + 'type' => [ + 'select' => [ + 'description' => 'type or input field', + 'group' => 'styling', + 'values' => [ + + 'button' => 'button', + 'checkbox' => 'checkbox', + 'color' => 'color', + 'date' => 'date', + 'datetime-local' => 'datetime-local', + 'email' => 'email', + 'file' => 'file', + 'hidden' => 'hidden', + 'image' => 'image', + 'month' => 'month', + 'number' => 'number', + 'password' => 'password', + 'radio' => 'radio', + 'range' => 'range', + 'reset' => 'reset', + 'search' => 'search', + 'submit' => 'submit', + 'tel' => 'tel', + 'text' => 'text', + 'time' => 'time', + 'url' => 'url', + 'week' => 'week', + ] + ], + 'example_value' => 'text' ], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'myclass' + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => 'myclass' ], - 'prepend' => [ - 'group'=>'styling', - 'description'=>'optional: content on input start', - 'example_value'=>'' + 'prepend' => [ + 'group' => 'styling', + 'description' => 'optional: content on input start', + 'example_value' => '' ], - 'append' => [ - 'group'=>'styling', - 'description'=>'optional: content on input end', - 'example_value'=>'' + 'append' => [ + 'group' => 'styling', + 'description' => 'optional: content on input end', + 'example_value' => '' ], - 'name' => [ - 'group'=>'content', - 'description'=>'name attribute', - 'example_value'=>'firstname' + 'name' => [ + 'group' => 'content', + 'description' => 'name attribute', + 'example_value' => 'firstname' ], 'value' => [ - 'group'=>'content', - 'description'=>'Value', - 'example_value'=>'Jack' + 'group' => 'content', + 'description' => 'Value', + 'example_value' => 'Jack' ], ] ], // ------------------------------------------------------------ - 'textarea'=>[ - 'label'=>'Form: textarea', - 'description'=>'textarea or html editor', - 'method'=>'getFormTextarea', - - 'params'=>[ - 'label' => [ - 'group'=>'styling', - 'description'=>'label for the input field', - 'example_value'=>'Enter text' + // WIP + 'select' => [ + 'label' => 'Form: select', + 'description' => 'Select box', + 'method' => 'getFormSelect', + + 'params' => [ + 'label' => [ + 'group' => 'styling', + 'description' => 'label for the select field', + 'example_value' => 'Enter text' ], - 'type'=>['select'=> [ - 'description'=>'type or input field', - 'group'=>'styling', - 'values'=>[ - ''=>'text', - 'html'=>'html editor', - ] - ], + 'bootstrap-select' => [ + 'select' => [ + 'description' => 'Enable bootstrap-select plugin', + 'group' => 'styling', + 'values' => [ + '0' => 'no', + '1' => 'yes', + ] + ] ], - 'class' => [ - 'group'=>'styling', - 'description'=>'optional: css classes', - 'example_value'=>'myclass' + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => 'myclass' ], - 'name' => [ - 'group'=>'content', - 'description'=>'name attribute', - 'example_value'=>'textdata' + 'options' => [ + 'example_value' => [ + ["value" => "1", "label" => "one"], + ["value" => "2", "label" => "two"], + ["value" => "3", "label" => "three"], + ], + ] + ], + ], + // ------------------------------------------------------------ + 'textarea' => [ + 'label' => 'Form: textarea', + 'description' => 'textarea or html editor', + 'method' => 'getFormTextarea', + + 'params' => [ + 'label' => [ + 'group' => 'styling', + 'description' => 'label for the input field', + 'example_value' => 'Enter text' + ], + 'type' => [ + 'select' => [ + 'description' => 'type or input field', + 'group' => 'styling', + 'values' => [ + '' => 'text', + 'html' => 'html editor', + ] + ], + ], + 'class' => [ + 'group' => 'styling', + 'description' => 'optional: css classes', + 'example_value' => 'myclass' + ], + 'name' => [ + 'group' => 'content', + 'description' => 'name attribute', + 'example_value' => 'textdata' ], 'value' => [ - 'group'=>'content', - 'description'=>'Value', - 'example_value'=>'Here is some text...' + 'group' => 'content', + 'description' => 'Value', + 'example_value' => 'Here is some text...' ], ] - ], + ], ]; } /** @@ -503,10 +555,12 @@ class renderadminlte { * @param array $aAttributes array of its attributes * @param string $sContent content between opening and closing tag * @param bool $bClosetag flag: write a closing tag or not? default: true + * @return string */ - protected function _tag($sTag, $aAttributes, $sContent=false, $bClosetag=true){ - if ($sContent){ - $aAttributes['label']=(isset($aAttributes['label']) ? $aAttributes['label'] : '') . $sContent; + protected function _tag(string $sTag, array $aAttributes, string $sContent = '', bool $bClosetag = true): string + { + if ($sContent) { + $aAttributes['label'] = (isset($aAttributes['label']) ? $aAttributes['label'] : '') . $sContent; } return $this->_oHtml->getTag($sTag, $aAttributes, $bClosetag); } @@ -520,25 +574,29 @@ class renderadminlte { * render a page by using template * @param string $stemplate html template with placeholders * @param array $aReplace key = what to replace .. value = new value + * @return string */ - public function render($sTemplate, $aReplace){ + public function render(string $sTemplate, array $aReplace): string + { return str_replace( array_keys($aReplace), array_values($aReplace), $sTemplate ); } - /** * add a wrapper: wrap some content into a tag * + * @param string $sTag name of html tag + * @param array $aOptions array of its attributes * @param string $sContent html content inside * @return string */ - public function addWrapper($sTag, $aOptions, $sContent){ - $aOptions['label']=$sContent; - return $this->_tag($sTag, $aOptions)."\n"; + public function addWrapper(string $sTag, array $aOptions, string $sContent): string + { + $aOptions['label'] = $sContent; + return $this->_tag($sTag, $aOptions) . PHP_EOL; } // ---------------------------------------------------------------------- @@ -547,7 +605,6 @@ class renderadminlte { // // ---------------------------------------------------------------------- - /** * get a single navigation item on top bar * @@ -555,80 +612,93 @@ class renderadminlte { * @param integer $iLevel Menu level; 1=top bar; 2=pupup menu with subitems * @return string */ - public function getNavItem($aLink, $iLevel=1){ + public function getNavItem(array $aLink, int $iLevel = 1): string + { static $iCounter; - if(!isset($iCounter)){ - $iCounter=0; + if (!isset($iCounter)) { + $iCounter = 0; } - + switch ($aLink['label']) { // special menu entry: horizontal bar (label is "-") - case '-': return '<div class="dropdown-divider"></div>'; break; + case '-': + return '<div class="dropdown-divider"></div>'; + break; // special menu entry: hamburger menu item (label is "=") - case '=': return '<li class="nav-item"><a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a></li>'; break; + case '=': + return '<li class="nav-item"><a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a></li>'; + break; // special menu entry: hamburger menu item (label is "|") // requires css: .navbar-nav li.divider{border-left: 1px solid rgba(0,0,0,0.2);} - case '|': return '<li class="divider"></li>'; break; + case '|': + return '<li class="divider"></li>'; + break; } - $aChildren=isset($aLink['children']) && is_array($aLink['children']) && count($aLink['children']) ? $aLink['children'] : false; + $aChildren = isset($aLink['children']) && is_array($aLink['children']) && count($aLink['children']) ? $aLink['children'] : false; - $aLink['class']='nav-link' - . (isset($aLink['class']) ? ' '.$aLink['class'] : '') + $aLink['class'] = 'nav-link' + . (isset($aLink['class']) ? ' ' . $aLink['class'] : '') . ($aChildren ? ' dropdown-toggle' : '') - ; - if($aChildren){ + ; + if ($aChildren) { $iCounter++; - $sNavId="navbarDropdown".$iCounter; - $aLink=array_merge($aLink,[ - 'id'=>$sNavId, - 'role'=>"button", - 'data-toggle'=>"dropdown", - 'aria-haspopup'=>"true", - 'aria-expanded'=>"false", + $sNavId = "navbarDropdown" . $iCounter; + $aLink = array_merge($aLink, [ + 'id' => $sNavId, + 'role' => "button", + 'data-toggle' => "dropdown", + 'aria-haspopup' => "true", + 'aria-expanded' => "false", ]); unset($aLink['children']); // remove from html attributes to draw } - $sReturn=$this->_tag('a', $aLink)."\n"; - if($aChildren){ + $sReturn = $this->_tag('a', $aLink) . "\n"; + if ($aChildren) { $iLevel++; - $sReturn.=$this->addWrapper( - 'div', - [ - 'aria-labelledby'=> $sNavId, - 'class'=>'dropdown-menu' - ], - $this->getNavItems($aChildren, $iLevel) - )."\n"; + $sReturn .= $this->addWrapper( + 'div', + [ + 'aria-labelledby' => $sNavId, + 'class' => 'dropdown-menu' + ], + $this->getNavItems($aChildren, $iLevel) + ) . "\n"; $iLevel--; } - - if($iLevel==1){ - $sLiClass='nav-item'.($aChildren ? ' dropdown' : ''); - $sReturn=$this->addWrapper( - 'li', - ['class'=>$sLiClass], - $sReturn + + if ($iLevel == 1) { + $sLiClass = 'nav-item' . ($aChildren ? ' dropdown' : ''); + $sReturn = $this->addWrapper( + 'li', + ['class' => $sLiClass], + $sReturn ); } return $sReturn; } + /** - * get a navigation item for top bar + * get html code for navigation on top bar * + * @param array $aLinks array of navigation items + * @param int $iLevel current navigation level; default: 1 + * @return string|bool */ - public function getNavItems($aLinks, $iLevel=1){ - $sReturn=''; - if (!$aLinks || !is_array($aLinks) || !count($aLinks)){ + public function getNavItems(array $aLinks, int $iLevel = 1): string|bool + { + $sReturn = ''; + if (!$aLinks || !is_array($aLinks) || !count($aLinks)) { return false; } - foreach($aLinks as $aLink){ - $sReturn.=$this->getNavItem($aLink, $iLevel); + foreach ($aLinks as $aLink) { + $sReturn .= $this->getNavItem($aLink, $iLevel); } return $sReturn; } + /** * get a top left navigation for a top navigation bar * @@ -650,20 +720,23 @@ class renderadminlte { * .'</nav>' * </code> * - * @param array $aNavitems array of navigation items/ tree - * @param array $aUlOptions array of html attrubutes for wrapping UL tag + * @param array $aNavItems array of navigation items/ tree + * @param array $aUlOptions array of html attrubutes for wrapping UL tag + * @param array $aNavItemsRight array of html attrubutes for wrapping UL tag + * @param array $aUlOptionsRight array of html attrubutes for wrapping UL tag * @return string */ - public function getTopNavigation($aNavItems, $aUlOptions=false, $aNavItemsRight=[], $aUlOptionsRight=false){ + public function getTopNavigation(array $aNavItems, array $aUlOptions = [], array $aNavItemsRight = [], array $aUlOptionsRight = []): string + { // array_unshift($aNavItems, ['class'=>'nav-link', 'data-widget'=>'pushmenu', 'href'=>'#', 'role'=>'button', 'label'=>'<i class="fa-solid fa-bars"></i>']); - $aUlOptLeft=$aUlOptions ? $aUlOptions : ['class'=>'navbar-nav']; - $aUlOptRight=$aUlOptionsRight ? $aUlOptionsRight : ['class'=>'navbar-nav ml-auto']; + $aUlOptLeft = count($aUlOptions) ? $aUlOptions : ['class' => 'navbar-nav']; + $aUlOptRight = count($aUlOptionsRight) ? $aUlOptionsRight : ['class' => 'navbar-nav ml-auto']; return $this->addWrapper('ul', $aUlOptLeft, $this->getNavItems($aNavItems)) - .(count($aNavItemsRight) + . (count($aNavItemsRight) ? $this->addWrapper('ul', $aUlOptRight, $this->getNavItems($aNavItemsRight)) : '' ) - ; + ; } // ---------------------------------------------------------------------- @@ -677,54 +750,64 @@ class renderadminlte { * .nav-item hr{color: #505860; border-top: 1px solid; height: 1px; padding: 0; margin: 0; } * * @param array $aLinks list of link items + * @return string|bool */ - public function getNavi2Items($aLinks){ - $sReturn=''; - if (!$aLinks || !is_array($aLinks) || !count($aLinks)){ + public function getNavi2Items(array $aLinks): string|bool + { + $sReturn = ''; + if (!$aLinks || !is_array($aLinks) || !count($aLinks)) { return false; } - - foreach($aLinks as $aLink){ - if ($aLink['label']=='-') { + foreach ($aLinks as $aLink) { + + if ($aLink['label'] == '-') { // TODO: draw a nice line - $sReturn.='<li class="nav-item"><hr></li>'; + $sReturn .= '<li class="nav-item"><hr></li>'; continue; } // to render active or open links: - $aLink['class']='nav-link' . (isset($aLink['class']) ? ' '.$aLink['class'] : ''); - - $aChildren=isset($aLink['children']) ? $aLink['children'] : false; - $aLiClass='nav-item' . ($aChildren && strstr($aLink['class'], 'active') ? ' menu-open' : ''); - $sSubmenu=''; - if($aChildren){ - unset($aLink['children']); - $aLink['label'].='<i class="right fa-solid fa-angle-left"></i>'; - $sSubmenu.=$this->getSidebarNavigation($aChildren, ['class'=>'nav nav-treeview']); + $aLink['class'] = 'nav-link' . (isset($aLink['class']) ? ' ' . $aLink['class'] : ''); + + $aChildren = isset($aLink['children']) ? $aLink['children'] : false; + $aLiClass = 'nav-item' . ($aChildren && strstr($aLink['class'], 'active') ? ' menu-open' : ''); + $sSubmenu = ''; + if ($aChildren) { + unset($aLink['children']); + $aLink['label'] .= '<i class="right fa-solid fa-angle-left"></i>'; + $sSubmenu .= $this->getSidebarNavigation($aChildren, ['class' => 'nav nav-treeview']); } - $aLink['label']=$this->addWrapper('p', [], $aLink['label']); - $sReturn.=$this->addWrapper( - 'li', ['class'=>$aLiClass], - $this->_tag('a', $aLink).$sSubmenu - )."\n"; + $aLink['label'] = $this->addWrapper('p', [], $aLink['label']); + $sReturn .= $this->addWrapper( + 'li', + ['class' => $aLiClass], + $this->_tag('a', $aLink) . $sSubmenu + ) . "\n"; } return $sReturn; } /** + * get html code for sidebar navigation * + * @param array $aNavItems navigation item + * @param array $aUlOptions aatributes for UL tag + * @param string */ - public function getSidebarNavigation($aNavItems, $aUlOptions=[ - 'class'=>'nav nav-pills nav-sidebar flex-column nav-flat_ nav-child-indent', - 'data-widget'=>'treeview', - 'role'=>'menu', - 'data-accordion'=>'false' - ]) - { + public function getSidebarNavigation( + array $aNavItems, + array $aUlOptions = [ + 'class' => 'nav nav-pills nav-sidebar flex-column nav-flat_ nav-child-indent', + 'data-widget' => 'treeview', + 'role' => 'menu', + 'data-accordion' => 'false' + ] + ): string { return $this->addWrapper( - 'ul', $aUlOptions, - $this->getNavi2Items($aNavItems) - )."\n"; + 'ul', + $aUlOptions, + $this->getNavi2Items($aNavItems) + ) . "\n"; } // ---------------------------------------------------------------------- @@ -732,15 +815,16 @@ class renderadminlte { // PUBLIC FUNCTIONS :: CONTENT - BASIC FUNCTIONS // // ---------------------------------------------------------------------- - + /** * add page row * * @param string $sContent html content inside * @return string */ - public function addRow($sContent){ - return $this->addWrapper('div', ['class'=>'row'], $sContent); + public function addRow(string $sContent): string + { + return $this->addWrapper('div', ['class' => 'row'], $sContent); } /** @@ -751,8 +835,9 @@ class renderadminlte { * @param string $sFloat css value for float attribute; default=false * @return string */ - public function addCol($sContent, $iCols=6, $sFloat=false){ - return $this->addWrapper('div', ['class'=>'col-md-'.$iCols, 'style'=>'float:'.$sFloat], $sContent); + public function addCol(string $sContent, int $iCols = 6, string $sFloat = ''): string + { + return $this->addWrapper('div', ['class' => 'col-md-' . $iCols, 'style' => 'float:' . $sFloat], $sContent); } // ---------------------------------------------------------------------- @@ -761,49 +846,52 @@ class renderadminlte { // // ---------------------------------------------------------------------- - /** * get a list of all defined components that can be rendered - * @param {bool} $bSendData flag: send including subkeys of the hash; default: false (keys only) - * @return {array} + * @param bool $bSendData flag: send including subkeys of the hash; default: false (keys only) + * @return array */ - public function getComponents($bSendData=false){ + public function getComponents(bool $bSendData = false): array + { return $bSendData ? $this->_aElements : array_keys($this->_aElements) ; } + /** * get data of a component - * @param {string} $sComponent id of the component - * @return {array} + * @param string $sComponent id of the component + * @return array|bool */ - public function getComponent($sComponent){ - if(!isset($this->_aElements[$sComponent])){ + public function getComponent(string $sComponent): array|bool + { + if (!isset($this->_aElements[$sComponent])) { return false; } - $aReturn=array_merge(['id'=>$sComponent], $this->_aElements[$sComponent]); + $aReturn = array_merge(['id' => $sComponent], $this->_aElements[$sComponent]); unset($aReturn['params']); return $aReturn; } /** * get parameter keys of a component - * @param {string} $sComponent id of the component - * @param {bool} $bSendData flag: send including subkeys of the hash; default: false (keys only) - * @return {array} + * @param string $sComponent id of the component + * @param bool $bSendData flag: send including subkeys of the hash; default: false (keys only) + * @return array|bool */ - public function getComponentParamkeys($sComponent, $bSendData=false){ - if(!isset($this->_aElements[$sComponent])){ + public function getComponentParamkeys(string $sComponent, bool $bSendData = false) + { + if (!isset($this->_aElements[$sComponent])) { return false; } - $aKeys=array_keys($this->_aElements[$sComponent]['params']); - if(!$bSendData){ + $aKeys = array_keys($this->_aElements[$sComponent]['params']); + if (!$bSendData) { return $aKeys; } - $aReturn=[]; - foreach($aKeys as $sKey){ - $aReturn[$sKey]=$this->getComponentParamkey($sComponent, $sKey); + $aReturn = []; + foreach ($aKeys as $sKey) { + $aReturn[$sKey] = $this->getComponentParamkey($sComponent, $sKey); } // $aReturn=$this->_aElements[$sComponent]['params']; return $aReturn; @@ -811,34 +899,36 @@ class renderadminlte { /** * get information a parameter keys of a component - * @param {string} $sComponent id of the component - * @param {string} $sKey key in the options array - * @return {array} + * @param string $sComponent id of the component + * @param string $sKey key in the options array + * @return array|bool */ - public function getComponentParamkey($sComponent, $sKey){ - if(!isset($this->_aElements[$sComponent]['params'][$sKey])){ + public function getComponentParamkey(string $sComponent, string $sKey): array|bool + { + if (!isset($this->_aElements[$sComponent]['params'][$sKey])) { return false; } - $aReturn=$this->_aElements[$sComponent]['params'][$sKey]; + $aReturn = $this->_aElements[$sComponent]['params'][$sKey]; // get description from a preset - if(!isset($aReturn['description']) && isset($aReturn['select']['description'])){ - $aReturn['description']=$aReturn['select']['description']; + if (!isset($aReturn['description']) && isset($aReturn['select']['description'])) { + $aReturn['description'] = $aReturn['select']['description']; } - if(!isset($aReturn['group']) && isset($aReturn['select']['group'])){ - $aReturn['group']=$aReturn['select']['group']; + if (!isset($aReturn['group']) && isset($aReturn['select']['group'])) { + $aReturn['group'] = $aReturn['select']['group']; } return $aReturn; } /** * get a flat list of valid parameters for a key in a component - * @param {string} $sComponent id of the component - * @param {string} $sKey key in the options array - * @return {array} + * @param string $sComponent id of the component + * @param string $sKey key in the options array + * @return array|bool */ - public function getValidParamValues($sComponent, $sKey){ - $aOptionkey=$this->getComponentParamkey($sComponent, $sKey); - if(!$aOptionkey || !isset($aOptionkey['select']['values'])){ + public function getValidParamValues(string $sComponent, string $sKey): array|bool + { + $aOptionkey = $this->getComponentParamkey($sComponent, $sKey); + if (!$aOptionkey || !isset($aOptionkey['select']['values'])) { return false; } return array_keys($aOptionkey['select']['values']); @@ -851,43 +941,49 @@ class renderadminlte { * helper: add a css value with prefix * this handles option keys in get[COMPONENT] methods * if a value is set then this function returns a space + prefix (param 2) + value - * @param {string} $sValue option value - * @param {string} $sPrefix prefix in front of css value - * @return {string} + * @param string $sValue option value + * @param string $sPrefix prefix in front of css value + * @return string */ - protected function _addClassValue($sValue, $sPrefix=''){ - return $sValue ? ' '.$sPrefix.$sValue : ''; + protected function _addClassValue(string $sValue, string $sPrefix = ''): string + { + return $sValue ? ' ' . $sPrefix . $sValue : ''; } /** * helper function for get[COMPONENTNAME] methods: - * ensure that all wanted keys exist in an array. Non existing keys will be added with value false + * ensure that all wanted keys exist in an array. Non existing keys will + * be added with value false + * + * @param string $sComponent id of the component + * @param array $aOptions hash with keys for all options * @return array */ - protected function _ensureOptions($sComponent, $aOptions=[]){ + protected function _ensureOptions(string $sComponent, array $aOptions = []): array + { - $aParams=$this->getComponentParamkeys($sComponent, 0); - if(!$aParams){ - $aOptions['_infos'][]="Warning: no definition was found for component $sComponent."; + $aParams = $this->getComponentParamkeys($sComponent, 0); + if (!$aParams) { + $aOptions['_infos'][] = "Warning: no definition was found for component $sComponent."; return $aOptions; } - foreach ($aParams as $sKey){ - if(!isset($aOptions) || !isset($aOptions[$sKey])){ - $aOptions[$sKey]=false; - if(!isset($aOptions['_infos'])){ - $aOptions['_infos']=[]; + foreach ($aParams as $sKey) { + if (!isset($aOptions) || !isset($aOptions[$sKey])) { + $aOptions[$sKey] = false; + if (!isset($aOptions['_infos'])) { + $aOptions['_infos'] = []; } - $aOptions['_infos'][]="added missing key: $sKey"; + $aOptions['_infos'][] = "added missing key: $sKey"; } // $aParamdata - $aValidvalues=$this->getValidParamValues($sComponent, $sKey); - if($aValidvalues){ - if(array_search($aOptions[$sKey], $aValidvalues)===false){ - echo "ERROR: [".$sComponent."] value "".$aOptions[$sKey]."" is not a valid for param key [".$sKey."]; it must be one of ".implode("|", $aValidvalues).'<br>'; + $aValidvalues = $this->getValidParamValues($sComponent, $sKey); + if ($aValidvalues) { + if (array_search($aOptions[$sKey], $aValidvalues) === false) { + echo "ERROR: [" . $sComponent . "] value "" . $aOptions[$sKey] . "" is not a valid for param key [" . $sKey . "]; it must be one of " . implode("|", $aValidvalues) . '<br>'; } } - + // $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__); } // echo '<pre>' . print_r($aOptions, 1) . '</pre>'; @@ -903,35 +999,36 @@ class renderadminlte { * return a alert box * https://adminlte.io/themes/v3/pages/UI/general.html * - * @param type $aOptions hash with keys for all options + * @param array $aOptions hash with keys for all options * - type - one of [none]|danger|info|primary|success|warning * - dismissible - if dismissible - one of true|false; default: false * - title * - text * @return string */ - public function getAlert($aOptions){ - $aOptions=$this->_ensureOptions('alert', $aOptions); - $aAlertIcons=[ - 'danger'=>'icon fa-solid fa-ban', - 'info'=>'icon fa-solid fa-info', - 'warning'=>'icon fa-solid fa-exclamation-triangle', - 'success'=>'icon fa-solid fa-check', + public function getAlert(array $aOptions): string + { + $aOptions = $this->_ensureOptions('alert', $aOptions); + $aAlertIcons = [ + 'danger' => 'icon fa-solid fa-ban', + 'info' => 'icon fa-solid fa-info', + 'warning' => 'icon fa-solid fa-exclamation-triangle', + 'success' => 'icon fa-solid fa-check', ]; - $aElement=[ - 'class'=>'alert' + $aElement = [ + 'class' => 'alert' . $this->_addClassValue($aOptions['type'], 'alert-') . $this->_addClassValue($aOptions['dismissible'], 'alert-') - , - 'label'=>'' + , + 'label' => '' . ($aOptions['dismissible'] ? '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' : '') . $this->_tag('h5', [ - 'label'=> '' - .(isset($aAlertIcons[$aOptions['type']]) ? '<i class="'.$aAlertIcons[$aOptions['type']].'"></i> ' : '') - .$aOptions['title'] - ]) - .$aOptions['text'] + 'label' => '' + . (isset($aAlertIcons[$aOptions['type']]) ? '<i class="' . $aAlertIcons[$aOptions['type']] . '"></i> ' : '') + . $aOptions['title'] + ]) + . $aOptions['text'] ]; return $this->_tag('div', $aElement); @@ -953,20 +1050,22 @@ class renderadminlte { * - text - visible text * - title - optional: title attribute * - type - one of [none]|danger|dark|info|primary|secondary|success|warning + * @return string */ - public function getBadge($aOptions){ - $aOptions=$this->_ensureOptions('badge', $aOptions); - $aElement=[]; - $aElement['class']='badge' - . $this->_addClassValue($aOptions['class'], '') - . $this->_addClassValue($aOptions['type'], 'badge-') + public function getBadge(array $aOptions): string + { + $aOptions = $this->_ensureOptions('badge', $aOptions); + $aElement = []; + $aElement['class'] = 'badge' + . $this->_addClassValue($aOptions['class'], '') + . $this->_addClassValue($aOptions['type'], 'badge-') . $this->_addClassValue($aOptions['bgcolor'], 'bg-') - ; - if ($aOptions['id']){ - $aElement['id']=$aOptions['id']; + ; + if ($aOptions['id']) { + $aElement['id'] = $aOptions['id']; } - $aElement['title']=$aOptions['title']; - $aElement['label']=$aOptions['text']; + $aElement['title'] = $aOptions['title']; + $aElement['label'] = $aOptions['text']; return $this->_tag('span', $aElement); } @@ -978,7 +1077,7 @@ class renderadminlte { * https://adminlte.io/themes/v3/pages/UI/buttons.html * * <button type="button" class="btn btn-block btn-default">Default</button> - * @param type $aOptions hash with keys for all options + * @param array $aOptions hash with keys for all options * - type - one of [none]|danger|dark|info|primary|secondary|success|warning * - size - one of [none]|lg|sm|xs|flat * - class - any css class for customizing, eg. "disabled" @@ -986,16 +1085,17 @@ class renderadminlte { * - text - text on button * @return string */ - public function getButton($aOptions){ - $aOptions=$this->_ensureOptions('button', $aOptions); - $aElement=$aOptions; - $aElement['class']='btn' - . $this->_addClassValue($aOptions['type'], 'btn-') - . $this->_addClassValue($aOptions['size'], 'btn-') - . $this->_addClassValue($aOptions['class'], '') - ; - $aElement['label']=$aOptions['text'] ? $aOptions['text'] : ' '; - foreach(['_infos', 'type', 'size', 'icon', 'text'] as $sDeleteKey){ + public function getButton(array $aOptions): string + { + $aOptions = $this->_ensureOptions('button', $aOptions); + $aElement = $aOptions; + $aElement['class'] = 'btn' + . $this->_addClassValue($aOptions['type'], 'btn-') + . $this->_addClassValue($aOptions['size'], 'btn-') + . $this->_addClassValue($aOptions['class'], '') + ; + $aElement['label'] = $aOptions['text'] ? $aOptions['text'] : ' '; + foreach (['_infos', 'type', 'size', 'icon', 'text'] as $sDeleteKey) { unset($aElement[$sDeleteKey]); } return $this->_tag('button', $aElement); @@ -1005,7 +1105,7 @@ class renderadminlte { * get a callout (box with coloered left border; has type, title + text) * https://adminlte.io/themes/v3/pages/UI/general.html * - * @param type $aOptions hash with keys for all options + * @param array $aOptions hash with keys for all options * >> styling * - type - one of [none]|danger|dark|info|primary|secondary|success|warning * - class - optional css class @@ -1015,19 +1115,21 @@ class renderadminlte { * - text - text: content of the card * @return string */ - public function getCallout($aOptions){ - $aOptions=$this->_ensureOptions('callout', $aOptions); - $sClass='callout' - . $this->_addClassValue($aOptions['type'], 'callout-') - . $this->_addClassValue($aOptions['class'], '') - .($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) - ? ' '.$this->_aValueMappings['shadow'][$aOptions['shadow']] : '') - ; + public function getCallout(array $aOptions): string + { + $aOptions = $this->_ensureOptions('callout', $aOptions); + $sClass = 'callout' + . $this->_addClassValue($aOptions['type'], 'callout-') + . $this->_addClassValue($aOptions['class'], '') + . ($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) + ? ' ' . $this->_aValueMappings['shadow'][$aOptions['shadow']] : '') + ; return $this->addWrapper( - 'div', ['class'=>$sClass], - ($aOptions['title'] ? $this->_tag('h5', ['label'=>$aOptions['title']]) : '') - .($aOptions['text'] ? $this->_tag('p', ['label'=>$aOptions['text']]) : '') + 'div', + ['class' => $sClass], + ($aOptions['title'] ? $this->_tag('h5', ['label' => $aOptions['title']]) : '') + . ($aOptions['text'] ? $this->_tag('p', ['label' => $aOptions['text']]) : '') ); } @@ -1036,7 +1138,7 @@ class renderadminlte { * https://adminlte.io/docs/3.2/components/cards.html * https://adminlte.io/docs/3.2/javascript/card-widget.html * - * @param type $aOptions hash with keys for all options + * @param array $aOptions hash with keys for all options * >> styling * - variant: "default" - titlebar is colored * "outline" - a small stripe on top border is colored @@ -1061,67 +1163,70 @@ class renderadminlte { * - footer - text: footer of the card * @return string */ - public function getCard($aOptions){ - $aOptions=$this->_ensureOptions('card', $aOptions); + public function getCard(array $aOptions): string + { + $aOptions = $this->_ensureOptions('card', $aOptions); // css class prefixes based on "variant" value - $aVariants=[ - 'default' => 'card-', - 'outline' => 'card-outline card-', - 'solid' => 'bg-', + $aVariants = [ + 'default' => 'card-', + 'outline' => 'card-outline card-', + 'solid' => 'bg-', 'gradient' => 'bg-gradient-', ]; // window states: css class and toolbar buttons to add - $aStates=[ - 'collapsed'=>[ 'class'=>'collapsed-card', 'tool'=>'tb-expand'], - 'maximized'=>[ 'class'=>'maximized-card', 'tool'=>'tb-minimize'], + $aStates = [ + 'collapsed' => ['class' => 'collapsed-card', 'tool' => 'tb-expand'], + 'maximized' => ['class' => 'maximized-card', 'tool' => 'tb-minimize'], ]; - $aTools=[ - 'tb-collapse'=>'<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fa-solid fa-minus"></i></button>', - 'tb-expand'=>'<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fa-solid fa-plus"></i></button>', + $aTools = [ + 'tb-collapse' => '<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fa-solid fa-minus"></i></button>', + 'tb-expand' => '<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fa-solid fa-plus"></i></button>', - 'tb-maximize'=>'<button type="button" class="btn btn-tool" data-card-widget="maximize"><i class="fa-solid fa-expand"></i></button>', - 'tb-minimize'=>'<button type="button" class="btn btn-tool" data-card-widget="maximize"><i class="fa-solid fa-compress"></i></button>', + 'tb-maximize' => '<button type="button" class="btn btn-tool" data-card-widget="maximize"><i class="fa-solid fa-expand"></i></button>', + 'tb-minimize' => '<button type="button" class="btn btn-tool" data-card-widget="maximize"><i class="fa-solid fa-compress"></i></button>', - 'tb-remove'=>'<button type="button" class="btn btn-tool" data-card-widget="remove"><i class="fa-solid fa-times"></i></button>', + 'tb-remove' => '<button type="button" class="btn btn-tool" data-card-widget="remove"><i class="fa-solid fa-times"></i></button>', ]; // print_r($aOptions); - $sVariantPrefix=isset($aVariants[$aOptions['variant']]) ? $aVariants[$aOptions['variant']] : $aVariants['default']; - $sClass='card' - . $this->_addClassValue($aOptions['type'], $sVariantPrefix) - .($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) - ? ' '.$this->_aValueMappings['shadow'][$aOptions['shadow']] : '') - . $this->_addClassValue($aOptions['class'], '') - ; + $sVariantPrefix = isset($aVariants[$aOptions['variant']]) ? $aVariants[$aOptions['variant']] : $aVariants['default']; + $sClass = 'card' + . $this->_addClassValue($aOptions['type'], $sVariantPrefix) + . ($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) + ? ' ' . $this->_aValueMappings['shadow'][$aOptions['shadow']] : '') + . $this->_addClassValue($aOptions['class'], '') + ; // check window state - foreach($aStates as $sStatus=>$aStatus){ - if($aOptions['state']===$sStatus){ - $sClass.=' '.$aStatus['class']; - $aOptions[$aStatus['tool']]=1; + foreach ($aStates as $sStatus => $aStatus) { + if ($aOptions['state'] === $sStatus) { + $sClass .= ' ' . $aStatus['class']; + $aOptions[$aStatus['tool']] = 1; } } // add toolbar buttons - from given options or by window state - foreach($aTools as $sTool=>$sHtml){ - $aOptions['tools'].=($aOptions[$sTool] ? $sHtml : ''); + foreach ($aTools as $sTool => $sHtml) { + $aOptions['tools'] .= ($aOptions[$sTool] ? $sHtml : ''); } // build parts of the card - $sCardHeader=$aOptions['title'] - ? $this->addWrapper('div', ['class'=>'card-header'], - $this->_tag('h3', ['class'=>'card-title', 'label'=>$aOptions['title']]) - . ($aOptions['tools'] ? $this->_tag('div', ['class'=>'card-tools', 'label'=>$aOptions['tools']]) : '') + $sCardHeader = $aOptions['title'] + ? $this->addWrapper( + 'div', + ['class' => 'card-header'], + $this->_tag('h3', ['class' => 'card-title', 'label' => $aOptions['title']]) + . ($aOptions['tools'] ? $this->_tag('div', ['class' => 'card-tools', 'label' => $aOptions['tools']]) : '') ) : '' - ; + ; - $sCardBody=$this->_tag('div', ['class'=>'card-body', 'label'=>$aOptions['text']]); - $sCardFooter=$aOptions['footer'] ? $this->_tag('div', ['class'=>'card-footer', 'label'=>$aOptions['footer']]) : ''; + $sCardBody = $this->_tag('div', ['class' => 'card-body', 'label' => $aOptions['text']]); + $sCardFooter = $aOptions['footer'] ? $this->_tag('div', ['class' => 'card-footer', 'label' => $aOptions['footer']]) : ''; // merge all - return $this->addWrapper('div', ['class'=>$sClass], $sCardHeader.$sCardBody.$sCardFooter); + return $this->addWrapper('div', ['class' => $sClass], $sCardHeader . $sCardBody . $sCardFooter); } @@ -1144,39 +1249,44 @@ class renderadminlte { * - progresstext - text below progress bar * @return string */ - public function getInfobox($aOptions){ - $aOptions=$this->_ensureOptions('infobox', $aOptions); + public function getInfobox(array $aOptions): string + { + $aOptions = $this->_ensureOptions('infobox', $aOptions); // print_r($aOptions); - $sClass='info-box' - . $this->_addClassValue($aOptions['type'], 'bg-') - . $this->_addClassValue($aOptions['class'], '') - .($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) - ? ' '.$this->_aValueMappings['shadow'][$aOptions['shadow']] : '') - ; - + $sClass = 'info-box' + . $this->_addClassValue($aOptions['type'], 'bg-') + . $this->_addClassValue($aOptions['class'], '') + . ($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) + ? ' ' . $this->_aValueMappings['shadow'][$aOptions['shadow']] : '') + ; + // build parts - $sIcon=$aOptions['icon'] + $sIcon = $aOptions['icon'] ? $this->addWrapper("span", [ - 'class'=>'info-box-icon'.($aOptions['iconbg'] ? ' bg-'.$aOptions['iconbg'] : '') - ], $this->_tag('i',['class'=>$aOptions['icon']])) + 'class' => 'info-box-icon' . ($aOptions['iconbg'] ? ' bg-' . $aOptions['iconbg'] : '') + ], $this->_tag('i', ['class' => $aOptions['icon']])) : '' - ; - $sContent=$this->addWrapper("div", ['class'=>'info-box-content'], + ; + $sContent = $this->addWrapper( + "div", + ['class' => 'info-box-content'], '' - . ($aOptions['text'] ? $this->_tag('span', ['class'=>'info-box-text', 'label'=>$aOptions['text']]) : '') - . ($aOptions['number'] ? $this->_tag('span', ['class'=>'info-box-number', 'label'=>$aOptions['number']]) : '') - . ($aOptions['progressvalue']!==false && $aOptions['progressvalue']!=='' - ? $this->addWrapper('div', ['class'=>'progress'], - $this->_tag('div', ['class'=>'progress-bar'. ($aOptions['iconbg'] ? ' bg-'.$aOptions['iconbg'] : ''), 'style'=>'width: '.(int)$aOptions['progressvalue'].'%' ]) - ) - . ($aOptions['progresstext'] ? $this->_tag('span', ['class'=>'progress-description', 'label'=>$aOptions['progresstext']]) : '' ) - : '' - ) + . ($aOptions['text'] ? $this->_tag('span', ['class' => 'info-box-text', 'label' => $aOptions['text']]) : '') + . ($aOptions['number'] ? $this->_tag('span', ['class' => 'info-box-number', 'label' => $aOptions['number']]) : '') + . ($aOptions['progressvalue'] !== false && $aOptions['progressvalue'] !== '' + ? $this->addWrapper( + 'div', + ['class' => 'progress'], + $this->_tag('div', ['class' => 'progress-bar' . ($aOptions['iconbg'] ? ' bg-' . $aOptions['iconbg'] : ''), 'style' => 'width: ' . (int) $aOptions['progressvalue'] . '%']) + ) + . ($aOptions['progresstext'] ? $this->_tag('span', ['class' => 'progress-description', 'label' => $aOptions['progresstext']]) : '') + : '' + ) ); // merge all - return $this->_tag('div', ['class'=>$sClass], $sIcon.$sContent); + return $this->_tag('div', ['class' => $sClass], $sIcon . $sContent); } @@ -1186,7 +1296,7 @@ class renderadminlte { * https://adminlte.io/docs/3.2/components/boxes.html * https://adminlte.io/themes/v3/pages/widgets.html * - * @param type $aOptions hash with keys for all options + * @param array $aOptions hash with keys for all options * styling: * - type - color of the box; one of [none]|danger|dark|info|primary|secondary|success|warning * - shadow - size of shadow; one of [none] (=default: between small and regular)|none|small|regular|large @@ -1198,42 +1308,50 @@ class renderadminlte { * - linktext- text below progress bar * @return string */ - public function getSmallbox($aOptions){ - $aOptions=$this->_ensureOptions('smallbox', $aOptions); + public function getSmallbox(array $aOptions): string + { + $aOptions = $this->_ensureOptions('smallbox', $aOptions); // print_r($aOptions); - $sClass='small-box' - . $this->_addClassValue($aOptions['type'], 'bg-') - . $this->_addClassValue($aOptions['class'], '') - .($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) - ? ' '.$this->_aValueMappings['shadow'][$aOptions['shadow']] : '') - ; - + $sClass = 'small-box' + . $this->_addClassValue($aOptions['type'], 'bg-') + . $this->_addClassValue($aOptions['class'], '') + . ($aOptions['shadow'] && isset($this->_aValueMappings['shadow'][$aOptions['shadow']]) + ? ' ' . $this->_aValueMappings['shadow'][$aOptions['shadow']] : '') + ; + // build parts - $sContent=$this->addWrapper("div", ['class'=>'inner'], + $sContent = $this->addWrapper( + "div", + ['class' => 'inner'], '' - . ($aOptions['number'] ? $this->_tag('h3', ['label'=>$aOptions['number']]) : '') - . ($aOptions['text'] ? $this->_tag('p', ['class'=>'info-box-text', 'label'=>$aOptions['text']]) : '') + . ($aOptions['number'] ? $this->_tag('h3', ['label' => $aOptions['number']]) : '') + . ($aOptions['text'] ? $this->_tag('p', ['class' => 'info-box-text', 'label' => $aOptions['text']]) : '') ); - $sIcon=$aOptions['icon'] - ? $this->addWrapper("div", ['class'=>'icon'], - $this->_tag('i',['class'=>$aOptions['icon']])) + $sIcon = $aOptions['icon'] + ? $this->addWrapper( + "div", + ['class' => 'icon'], + $this->_tag('i', ['class' => $aOptions['icon']]) + ) : '' - ; - $sFooter=($aOptions['url'] - ? $this->addWrapper("a", [ - 'class'=>'small-box-footer', - 'href'=>$aOptions['url'], + ; + $sFooter = ($aOptions['url'] + ? $this->addWrapper( + "a", + [ + 'class' => 'small-box-footer', + 'href' => $aOptions['url'], ], '' . ($aOptions['linktext'] ? $aOptions['linktext'] : $aOptions['url']) . ' ' - . $this->_tag('i',['class'=>'fa-solid fa-arrow-circle-right']) + . $this->_tag('i', ['class' => 'fa-solid fa-arrow-circle-right']) ) : '' ); // merge all - return $this->_tag('div', ['class'=>$sClass], $sContent.$sIcon.$sFooter); + return $this->_tag('div', ['class' => $sClass], $sContent . $sIcon . $sFooter); } // ---------------------------------------------------------------------- @@ -1243,12 +1361,27 @@ class renderadminlte { // ---------------------------------------------------------------------- - public function getHorizontalFormElement($sInput, $sLabel=false, $sId=false){ + /** + * Generates a horizontal form element with a label, input, and optional hint. + * + * @param string $sInput The HTML input element to be rendered. + * @param string $sLabel The label for the input element. + * @param string $sId The ID attribute for the label and input elements. + * @param string $sHint An optional hint to be displayed below the input element. + * @return string The generated HTML for the horizontal form element. + */ + public function getHorizontalFormElement(string $sInput, string $sLabel = '', string $sId = '', string $sHint=''): string + { return '<div class="form-group row">' - . '<label for="' . $sId . '" class="col-sm-2 col-form-label">' . $sLabel . '</label>' - . '<div class="col-sm-10">'.$sInput.'</div>' - . '</div>' - ; + . '<label for="' . $sId . '" class="col-sm-2 col-form-label">' . $sLabel . '</label>' + . '<div class="col-sm-10">' + . ($sHint + ? '<div class="text-navy hint">' . $sHint . '</div>' + : '') + . $sInput + . '</div>' + . '</div>' + ; } /** @@ -1258,67 +1391,83 @@ class renderadminlte { * @param array $aOptions hash with keys for all options * styling: * - type - field type: text, email, password, hidden and all other html 5 input types - * content + * content * - label - label tag * - name - name attribute for sending form * - value - value in field + * more: + * - hint - hint to be displayed above the field + * If not set, no hint is displayed. + * css for ".row .hint" to customize look and feel * @return string */ - public function GetFormInput($aOptions){ + public function GetFormInput(array $aOptions): string + { // $aOptions=$this->_ensureOptions('input', $aOptions); - $aElement=$aOptions; - $aElement['class']='' + $aElement = $aOptions; + $aElement['class'] = '' . 'form-control ' - . (isset($aOptions['class']) ? $aOptions['class']: '') - ; - $sFormid=(isset($aOptions['id']) - ? $aOptions['id'] - : (isset($aOptions['name']) ? $aOptions['name'] : 'field' ).'-'.md5(microtime(true)) + . (isset($aOptions['class']) ? $aOptions['class'] : '') + ; + $sFormid = (isset($aOptions['id']) + ? $aOptions['id'] + : (isset($aOptions['name']) ? $aOptions['name'] : 'field') . '-' . md5(microtime(true)) ); + $aElement['id'] = $sFormid; - $sLabel=isset($aOptions['label']) ? $aOptions['label'] : ''; - $sPrepend=''; - $sAppend=''; + $sLabel = isset($aOptions['label']) ? $aOptions['label'] : ''; + $sHint = isset($aOptions['hint']) ? $aOptions['hint'] : ''; + $sPrepend = ''; + $sAppend = ''; - if(isset($aOptions['prepend']) && $aOptions['prepend']){ - $sWrapperclass='input-group'; - $sPrepend=$this->_tag('div',[ 'class'=>'input-group-prepend'], - $this->_tag('span', ['class'=>'input-group-text'] , $aOptions['prepend']) + if (isset($aOptions['prepend']) && $aOptions['prepend']) { + $sWrapperclass = 'input-group'; + $sPrepend = $this->_tag( + 'div', + ['class' => 'input-group-prepend'], + $this->_tag('span', ['class' => 'input-group-text'], $aOptions['prepend']) ); } - if(isset($aOptions['append']) && $aOptions['append']){ - $sWrapperclass='input-group'; - $sAppend=$this->_tag('div',[ 'class'=>'input-group-append'], - $this->_tag('span', ['class'=>'input-group-text'] , $aOptions['append']) + if (isset($aOptions['append']) && $aOptions['append']) { + $sWrapperclass = 'input-group'; + $sAppend = $this->_tag( + 'div', + ['class' => 'input-group-append'], + $this->_tag('span', ['class' => 'input-group-text'], $aOptions['append']) ); - } + } - $aElement['id']=$sFormid; - foreach(['_infos', 'label', 'append', 'prepend', 'debug'] as $sDeleteKey){ - if(isset($aElement[$sDeleteKey])){ + foreach (['_infos', 'label', 'append', 'prepend', 'debug'] as $sDeleteKey) { + if (isset($aElement[$sDeleteKey])) { unset($aElement[$sDeleteKey]); } } // return data - switch($aElement['type']){ + switch ($aElement['type']) { case 'checkbox': case 'radio': - $aElement['class']=str_replace('form-control ', 'form-check-input', $aElement['class']); - return $this->_tag('div' , ['class'=>'form-check'], - $this->_tag('input', $aElement, '', false).$this->_tag('label', ['for'=>$sFormid, 'label'=>$sLabel ], '') + $aElement['class'] = str_replace('form-control ', 'form-check-input', $aElement['class']); + $aElement['title'] = $aElement['title'] ?? $sHint; + return $this->_tag( + 'div', + ['class' => 'form-check'], + $this->_tag('input', $aElement, '', false) . $this->_tag('label', ['for' => $sFormid, 'label' => $sLabel], '') ); break; case 'hidden': + $aElement['title'] = $aElement['title'] ?? $sHint; return $this->_tag('input', $aElement, '', false); break; - default: return $this->getHorizontalFormElement( - $sPrepend.$this->_tag('input', $aElement, '', false).$sAppend, - $sLabel, - $sFormid - ); + default: + return $this->getHorizontalFormElement( + $sPrepend . $this->_tag('input', $aElement, '', false) . $sAppend, + $sLabel, + $sFormid, + $sHint + ); } } @@ -1331,32 +1480,41 @@ class renderadminlte { * - label - label tag * - name - name attribute for sending form * - value - value in + * more: + * - hint - hint to be displayed above the field + * If not set, no hint is displayed. + * css for ".row .hint" to customize look and feel * @return string */ - public function getFormTextarea($aOptions){ + public function getFormTextarea(array $aOptions): string + { // $aOptions=$this->_ensureOptions('textarea', $aOptions); - $aElement=$aOptions; - $aElement['class']='' + $aElement = $aOptions; + $aElement['class'] = '' . 'form-control ' - . ((isset($aOptions['type']) && $aOptions['type']=='html' )? 'summernote ': '') - . (isset($aOptions['class']) ? $aOptions['class']: '') + . ((isset($aOptions['type']) && $aOptions['type'] == 'html') ? 'summernote ' : '') + . (isset($aOptions['class']) ? $aOptions['class'] : '') ; - - $sLabel=isset($aOptions['label']) ? $aOptions['label'] : ''; - $sFormid=(isset($aOptions['id']) - ? $aOptions['id'] - : (isset($aOptions['name']) ? $aOptions['name'] : 'field' ).'-'.md5(microtime(true)) + $sFormid = (isset($aOptions['id']) + ? $aOptions['id'] + : (isset($aOptions['name']) ? $aOptions['name'] : 'field') . '-' . md5(microtime(true)) ); - $value=isset($aOptions['value']) ? $aOptions['value']: ''; - foreach(['_infos', 'label', 'debug','type', 'value'] as $sDeleteKey){ - if(isset($aElement[$sDeleteKey])){ + $sLabel = isset($aOptions['label']) ? $aOptions['label'] : ''; + $sHint = isset($aOptions['hint']) ? $aOptions['hint'] : ''; + $aElement['id'] = $sFormid; + + $value = isset($aOptions['value']) ? $aOptions['value'] : ''; + + foreach (['_infos', 'label', 'debug', 'type', 'value'] as $sDeleteKey) { + if (isset($aElement[$sDeleteKey])) { unset($aElement[$sDeleteKey]); } } return $this->getHorizontalFormElement( - $this->_tag('textarea', $aElement, $value), - $sLabel, - $sFormid + $this->_tag('textarea', $aElement, $value), + $sLabel, + $sFormid, + $sHint ); } @@ -1364,52 +1522,69 @@ class renderadminlte { /** * return a select box field * @param array $aOptions hash with keys for all options - * styling: - * - class - css class * option fields * - options - array of options with keys per item: * - value - value in the option * - label - visible text in the option * other keys are attributes in the option + * styling: + * - bootstrap-select - set true to enable select + * box with bootstrap-select and + * live search + * - class - css class * select tag * - label - label tag * - name - name attribute for sending form * other keys are attributes in the select + * more: + * - hint - hint to be displayed above the field + * If not set, no hint is displayed. + * css for ".row .hint" to customize look and feel * @return string */ - public function getFormSelect($aOptions){ - $aElement=$aOptions; - $aElement['class']='' + public function getFormSelect(array $aOptions): string + { + $aElement = $aOptions; + $aElement['class'] = '' . 'form-control ' - . (isset($aOptions['class']) ? $aOptions['class']: '') + . (isset($aOptions['class']) ? $aOptions['class'] . ' ' : '') + . (isset($aOptions['bootstrap-select']) ? 'selectpicker ' : '') //$aOptions ; - - $sLabel=isset($aOptions['label']) ? $aOptions['label'] : ''; - $sFormid=(isset($aOptions['id']) - - ? $aOptions['id'] - : (isset($aOptions['name']) ? $aOptions['name'] : 'field' ).'-'.md5(microtime(true)) + if (isset($aOptions['bootstrap-select']) && $aOptions['bootstrap-select']) { + $aElement['data-live-search'] = "true"; + } + + $sFormid = (isset($aOptions['id']) + + ? $aOptions['id'] + : (isset($aOptions['name']) ? $aOptions['name'] : 'field') . '-' . md5(microtime(true)) ); + $aElement['id'] = $sFormid; + $sLabel = isset($aOptions['label']) ? $aOptions['label'] : ''; + $sHint = isset($aOptions['hint']) ? $aOptions['hint'] : ''; - $sOptionTags=''; - foreach($aOptions['options'] as $aField){ - $optionText=$aField['label']; + $sOptionTags = ''; + foreach ($aOptions['options'] as $aField) { + $optionText = $aField['label']; unset($aField['label']); - $sOptionTags.=$this->_tag('option', $aField, $optionText )."\n"; + $sOptionTags .= $this->_tag('option', $aField, $optionText) . "\n"; } - foreach(['_infos', 'label', 'debug','type', 'value', 'options'] as $sDeleteKey){ - if(isset($aElement[$sDeleteKey])){ + foreach (['_infos', 'label', 'debug', 'type', 'value', 'options'] as $sDeleteKey) { + if (isset($aElement[$sDeleteKey])) { unset($aElement[$sDeleteKey]); } } return $this->getHorizontalFormElement( - $this->_tag('div', ['class'=>'form-group'], + $this->_tag( + 'div', + ['class' => 'form-group'], $this->_tag('select', $aElement, $sOptionTags) - ), - $sLabel, - $sFormid - ); + ), + $sLabel, + $sFormid, + $sHint + ); } @@ -1423,55 +1598,62 @@ class renderadminlte { * return a box with tabbed content * @param array $aOptions hash with keys for all options * - tabs {array} key=tab label; value=content - * @retunr string|array + * @param bool $asArray optional flag: return hash with keys or as string + * @retunr bool|string|array */ - public function getTabbedContent($aOptions, $asArray=false){ + public function getTabbedContent(array $aOptions, bool $asArray = false): bool|string|array + { static $iTabCounter; - if( ! isset($aOptions['tabs']) || ! is_array($aOptions['tabs']) ){ + if (!isset($aOptions['tabs']) || !is_array($aOptions['tabs'])) { return false; } - if (!isset($iTabCounter)){ - $iTabCounter=1; + if (!isset($iTabCounter)) { + $iTabCounter = 1; } else { - $iTabCounter++; + $iTabCounter++; } - $id='tab-content-'.$iTabCounter; - $iCounter=0; + $id = 'tab-content-' . $iTabCounter; + $iCounter = 0; - $sTabs=''; - $sContent=''; - foreach($aOptions['tabs'] as $sLabel => $sTabContent){ + $sTabs = ''; + $sContent = ''; + foreach ($aOptions['tabs'] as $sLabel => $sTabContent) { $iCounter++; - $sTabId=$id.'-tabitem-'.$iCounter.'-tab'; - $sContentId=$id.'-tabitem-'.$iCounter.'-content'; - - $sTabs.=$this->_tag('li', ['class'=>'nav-item'], - $this->_tag('a', [ - 'class'=>'nav-link'.($iCounter==1 ? ' active' : '' ), - 'id'=>$sTabId, - 'data-toggle'=>'tab', - 'href'=>'#'.$sContentId, - 'role'=>'tab', - 'aria-controls'=>'custom-tabs-one-profile', - 'aria-selected'=>($iCounter==1 ? true : false ), - ], - $sLabel) + $sTabId = $id . '-tabitem-' . $iCounter . '-tab'; + $sContentId = $id . '-tabitem-' . $iCounter . '-content'; + + $sTabs .= $this->_tag( + 'li', + ['class' => 'nav-item'], + $this->_tag( + 'a', + [ + 'class' => 'nav-link' . ($iCounter == 1 ? ' active' : ''), + 'id' => $sTabId, + 'data-toggle' => 'tab', + 'href' => '#' . $sContentId, + 'role' => 'tab', + 'aria-controls' => 'custom-tabs-one-profile', + 'aria-selected' => ($iCounter == 1 ? true : false), + ], + $sLabel + ) ); - $sContent.=$this->_tag('div', [ - 'class'=>'tab-pane fade'.($iCounter==1 ? ' active show' : ''), - 'id'=>$sContentId, - 'role'=>'tabpanel', - 'aria-labelledby'=>$sTabId, - ], $sTabContent); + $sContent .= $this->_tag('div', [ + 'class' => 'tab-pane fade' . ($iCounter == 1 ? ' active show' : ''), + 'id' => $sContentId, + 'role' => 'tabpanel', + 'aria-labelledby' => $sTabId, + ], $sTabContent); } - $sTabs=$this->_tag('ul', ['class'=>'nav nav-tabs', 'role'=>'tablist'], $sTabs); - $sContent=$this->_tag('div', ['class'=>'tab-content'], $sContent); + $sTabs = $this->_tag('ul', ['class' => 'nav nav-tabs', 'role' => 'tablist'], $sTabs); + $sContent = $this->_tag('div', ['class' => 'tab-content'], $sContent); return $asArray - ? ['tabs'=>$sTabs, 'content'=>$sContent] + ? ['tabs' => $sTabs, 'content' => $sContent] : $sTabs . $sContent - ; + ; } }