new: [helpers] Added collapse, progress and progressTimeline component +

various improvements
pull/59/head
mokaddem 2021-06-12 11:57:49 +02:00
parent 3925c4cee6
commit d125b3b974
3 changed files with 300 additions and 3 deletions

View File

@ -42,12 +42,15 @@
namespace App\View\Helper;
use Cake\View\Helper;
use Cake\Utility\Hash;
use Cake\Utility\Inflector;
use Cake\Utility\Security;
use InvalidArgumentException;
class BootstrapHelper extends Helper
{
public $helpers = ['FontAwesome'];
public function tabs($options)
{
$bsTabs = new BootstrapTabs($options);
@ -80,14 +83,44 @@ class BootstrapHelper extends Helper
public function modal($options)
{
$bsButton = new BoostrapModal($options);
return $bsButton->modal();
$bsModal = new BoostrapModal($options);
return $bsModal->modal();
}
public function progress($options)
{
$bsProgress = new BoostrapProgress($options);
return $bsProgress->progress();
}
public function collapse($options, $content)
{
$bsCollapse = new BoostrapCollapse($options, $content, $this);
return $bsCollapse->collapse();
}
public function progressTimeline($options)
{
$bsProgressTimeline = new BoostrapProgressTimeline($options, $this);
return $bsProgressTimeline->progressTimeline();
}
}
class BootstrapGeneric
{
public static $variants = ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark', 'white', 'transparent'];
public static $textClassByVariants = [
'primary' => 'text-white',
'secondary' => 'text-white',
'success' => 'text-white',
'danger' => 'text-white',
'warning' => 'text-black',
'info' => 'text-white',
'light' => 'text-black',
'dark' => 'text-white',
'white' => 'text-black',
'transparent' => 'text-black'
];
protected $allowedOptionValues = [];
protected $options = [];
@ -146,6 +179,11 @@ class BootstrapGeneric
'arial-hidden' => 'true'
], '×'));
}
protected static function getTextClassForVariant($variant)
{
return !empty(self::$textClassByVariants[$variant]) ? self::$textClassByVariants[$variant] : 'text-black';
}
}
class BootstrapTabs extends BootstrapGeneric
@ -543,7 +581,7 @@ class BoostrapTable extends BootstrapGeneric {
} else {
$key = $field;
}
$cellValue = $row[$key];
$cellValue = Hash::get($row, $key);
$html .= $this->genCell($cellValue, $field, $row);
}
} else { // indexed array
@ -856,3 +894,234 @@ class BoostrapModal extends BootstrapGeneric {
return $buttonCancel . $buttonConfirm;
}
}
class BoostrapProgress extends BootstrapGeneric {
private $defaultOptions = [
'value' => 0,
'total' => 100,
'text' => '',
'title' => '',
'variant' => 'primary',
'height' => '',
'striped' => false,
'animated' => false,
'label' => true
];
function __construct($options) {
$this->allowedOptionValues = [
'variant' => BootstrapGeneric::$variants,
];
$this->processOptions($options);
}
private function processOptions($options)
{
$this->options = array_merge($this->defaultOptions, $options);
$this->checkOptionValidity();
}
public function progress()
{
return $this->genProgress();
}
private function genProgress()
{
$percentage = round(100 * $this->options['value'] / $this->options['total']);
$heightStyle = !empty($this->options['height']) ? sprintf('height: %s;', h($this->options['height'])) : '';
$widthStyle = sprintf('width: %s%%;', $percentage);
$label = $this->options['label'] ? "{$percentage}%" : '';
$pb = $this->genNode('div', [
'class' => [
'progress-bar',
"bg-{$this->options['variant']}",
$this->options['striped'] ? 'progress-bar-striped' : '',
$this->options['animated'] ? 'progress-bar-animated' : '',
],
'role' => "progressbar",
'aria-valuemin' => "0", 'aria-valuemax' => "100",'aria-valuenow' => $percentage,
'style' => "${widthStyle}",
'title' => $this->options['title']
], $label);
$container = $this->genNode('div', [
'class' => [
'progress',
],
'style' => "${heightStyle}",
'title' => h($this->options['title']),
], $pb);
return $container;
}
}
class BoostrapCollapse extends BootstrapGeneric {
private $defaultOptions = [
'text' => '',
'open' => false,
];
function __construct($options, $content, $btHelper) {
$this->allowedOptionValues = [];
$this->processOptions($options);
$this->content = $content;
$this->btHelper = $btHelper;
}
private function processOptions($options)
{
$this->options = array_merge($this->defaultOptions, $options);
$this->checkOptionValidity();
}
public function collapse()
{
return $this->genCollapse();
}
private function genControl()
{
$html = $this->genNode('a', [
'class' => ['text-decoration-none'],
'data-toggle' => 'collapse',
'href' => '#collapseExample',
'role' => 'button',
'aria-expanded' => 'false',
'aria-controls' => 'collapseExample',
], h($this->options['title']));
return $html;
}
private function genContent()
{
$content = $this->genNode('div', [
'class' => 'card',
], $this->content);
$container = $this->genNode('div', [
'class' => ['collapse', $this->options['open'] ? 'show' : ''],
'id' => 'collapseExample',
], $content);
return $container;
}
private function genCollapse()
{
$html = $this->genControl();
$html .= $this->genContent();
return $html;
}
}
class BoostrapProgressTimeline extends BootstrapGeneric {
private $defaultOptions = [
'steps' => [],
'selected' => 0,
'variant' => 'info',
'variantInactive' => 'secondary',
];
function __construct($options, $btHelper) {
$this->allowedOptionValues = [
'variant' => BootstrapGeneric::$variants,
'variantInactive' => BootstrapGeneric::$variants,
];
$this->processOptions($options);
$this->btHelper = $btHelper;
}
private function processOptions($options)
{
$this->options = array_merge($this->defaultOptions, $options);
$this->checkOptionValidity();
}
public function progressTimeline()
{
return $this->genProgressTimeline();
}
private function getStepIcon($step, $i, $nodeActive, $lineActive)
{
$icon = $this->genNode('b', [
'class' => [
!empty($step['icon']) ? h($this->btHelper->FontAwesome->getClass($step['icon'])) : '',
$this->getTextClassForVariant($this->options['variant'])
],
], empty($step['icon']) ? h($i+1) : '');
$iconContainer = $this->genNode('span', [
'class' => [
'd-flex', 'align-items-center', 'justify-content-center',
'rounded-circle',
$nodeActive ? "bg-{$this->options['variant']}" : "bg-{$this->options['variantInactive']}"
],
'style' => 'width:50px; height:50px'
], $icon);
$li = $this->genNode('li', [
'class' => [
'd-flex', 'flex-column',
$nodeActive ? 'progress-active' : 'progress-inactive',
],
], $iconContainer);
$html = $li . $this->getHorizontalLine($i, $nodeActive, $lineActive);
return $html;
}
private function getHorizontalLine($i, $nodeActive, $lineActive)
{
$stepCount = count($this->options['steps']);
if ($i == $stepCount-1) {
return '';
}
$progressBar = (new BoostrapProgress([
'label' => false,
'value' => $nodeActive ? ($lineActive ? 100 : 50) : 0,
'height' => '2px',
'variant' => $this->options['variant']
]))->progress();
$line = $this->genNode('span', [
'class' => [
'progress-line',
'flex-grow-1', 'align-self-center',
$lineActive ? "bg-{$this->options['variant']}" : ''
],
], $progressBar);
return $line;
}
private function getStepText($step, $isActive)
{
return $this->genNode('li', [
'class' => [
'text-center',
'font-weight-bold',
$isActive ? 'progress-active' : 'progress-inactive',
],
], h($step['text'] ?? ''));
}
private function genProgressTimeline()
{
$iconLis = '';
$textLis = '';
foreach ($this->options['steps'] as $i => $step) {
$nodeActive = $i <= $this->options['selected'];
$lineActive = $i < $this->options['selected'];
$iconLis .= $this->getStepIcon($step, $i, $nodeActive, $lineActive);
$textLis .= $this->getStepText($step, $nodeActive);
}
$ulIcons = $this->genNode('ul', [
'class' => [
'd-flex', 'justify-content-around',
],
], $iconLis);
$ulText = $this->genNode('ul', [
'class' => [
'd-flex', 'justify-content-between',
],
], $textLis);
$html = $this->genNode('div', [
'class' => ['progress-timeline']
], $ulIcons . $ulText);
return $html;
}
}

View File

@ -66,3 +66,25 @@
.toast-dark strong {
color: #040505;
}
div.progress-timeline {
padding: 0.2em 0.2em 0.5em 0.2em;
}
div.progress-timeline ul {
position: relative;
padding: 0;
}
div.progress-timeline li {
list-style-type: none;
position: relative
}
div.progress-timeline li.progress-inactive {
opacity: 0.5;
}
div.progress-timeline .progress-line {
height: 2px;
/* background: gray; */
}
div.progress-timeline .progress-line.progress-inactive {
opacity: 0.5;
}

View File

@ -42,6 +42,12 @@ class UIFactory {
theModal.show()
theModal.$modal.data('modalObject', theModal)
return theModal
}).catch((error) => {
UI.toast({
variant: 'danger',
title: 'Error while loading the processor',
body: error.message
})
})
}