diff --git a/assets/css/app.css b/assets/css/app.css index d4a8ce0b..e4902527 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -69,8 +69,6 @@ body { /*noinspection CssUnknownProperty*/ scrollbar-width: none; } - - } /*noinspection W3CssValidation*/ @@ -852,4 +850,19 @@ div.dataTables_wrapper div.dataTables_info { ***********************************************/ .typeahead-image { width: 100%; +} + +/*********************************************** + * Special level whitespace characters that only show up when inside a bootstrap-select dropdown + ***********************************************/ +.dropdown-item span.picker-level::after { + content: "\00a0\00a0\00a0"; /* 3 spaces */ +} + +/** Bootstrap-select Hide on Selected element */ +.picker-hs { + display: none; +} +.dropdown-item .picker-hs { + display: inherit; } \ No newline at end of file diff --git a/assets/ts_src/ajax_ui.ts b/assets/ts_src/ajax_ui.ts index d621362b..0ff6825b 100644 --- a/assets/ts_src/ajax_ui.ts +++ b/assets/ts_src/ajax_ui.ts @@ -181,6 +181,7 @@ class AjaxUI { ajaxUI.initTree("#" + target_id, 'tree/tools'); break; case "devices": + ajaxUI.initTree("#" + target_id, 'tree/devices'); ajaxUI.initTree("#" + target_id, 'tree/devices'); break; } diff --git a/src/Form/Part/PricedetailType.php b/src/Form/Part/PricedetailType.php index 1fa52a70..7b929adf 100644 --- a/src/Form/Part/PricedetailType.php +++ b/src/Form/Part/PricedetailType.php @@ -82,6 +82,7 @@ class PricedetailType extends AbstractType $builder->add('currency', CurrencyEntityType::class, [ 'required' => false, 'label' => false, + 'short' => true, ]); } diff --git a/src/Form/Type/CurrencyEntityType.php b/src/Form/Type/CurrencyEntityType.php index 38b7501b..e69a9724 100644 --- a/src/Form/Type/CurrencyEntityType.php +++ b/src/Form/Type/CurrencyEntityType.php @@ -42,6 +42,7 @@ declare(strict_types=1); namespace App\Form\Type; +use App\Entity\Attachments\AttachmentType; use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\PriceInformations\Currency; use App\Services\Trees\NodesListBuilder; @@ -50,6 +51,9 @@ use Symfony\Component\Intl\Currencies; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * An entity to select a currency shortly + */ class CurrencyEntityType extends StructuralEntityType { protected $base_currency; @@ -82,51 +86,41 @@ class CurrencyEntityType extends StructuralEntityType return Currencies::getSymbol($iso_code); }); + + $resolver->setDefault('used_to_select_parent', false); + + //If short is set to true, then the name of the entity will only shown in the dropdown list not in the selected value. + $resolver->setDefault('short', false); } - public function generateChoiceLabels(AbstractStructuralDBElement $choice, $key, $value, $options): string + protected function getChoiceContent(AbstractStructuralDBElement $choice, $key, $value, $options): string { - //Similar to StructuralEntityType, but we use the currency symbol instead if available - - if (!$choice instanceof Currency) { - throw new \InvalidArgumentException('$choice must be an currency object!'); + if(!$choice instanceof Currency) { + throw new \RuntimeException('$choice must be an instance of Currency!'); } + //Generate the level spacing /** @var AbstractStructuralDBElement|null $parent */ $parent = $options['subentities_of']; - - /*** @var Currency $choice */ + /*** @var AbstractStructuralDBElement $choice */ $level = $choice->getLevel(); //If our base entity is not the root level, we need to change the level, to get zero position if (null !== $options['subentities_of']) { $level -= $parent->getLevel() - 1; } - $tmp = str_repeat('   ', $level); //Use 3 spaces for intendation - if (empty($choice->getIsoCode())) { - $tmp .= htmlspecialchars($choice->getName()); - } else { + $tmp = str_repeat('', $level); + + //Show currency symbol or ISO code and the name of the currency + if(!empty($choice->getIsoCode())) { $tmp .= Currencies::getSymbol($choice->getIsoCode()); + //Add currency name as badge + $tmp .= sprintf('%s', $options['short'] ? 'picker-hs' : '' , htmlspecialchars($choice->getName())); + } else { + $tmp .= htmlspecialchars($choice->getName()); } return $tmp; } - protected function generateChoiceAttr(AbstractStructuralDBElement $choice, $key, $value, $options): array - { - /** @var Currency $choice */ - $tmp = []; - - if (!empty($choice->getIsoCode())) { - //Show the name of the currency - $tmp += ['data-subtext' => $choice->getName()]; - } - - //Disable attribute if the choice is marked as not selectable - if ($options['disable_not_selectable'] && $choice->isNotSelectable()) { - $tmp += ['disabled' => 'disabled']; - } - - return $tmp; - } } diff --git a/src/Form/Type/StructuralEntityType.php b/src/Form/Type/StructuralEntityType.php index bcbe41f9..b5cd793e 100644 --- a/src/Form/Type/StructuralEntityType.php +++ b/src/Form/Type/StructuralEntityType.php @@ -239,13 +239,34 @@ class StructuralEntityType extends AbstractType return $this->em->find($options['class'], $value->getID()); } + /** + * This generates the HTML code that will be rendered by selectpicker + * @return string + */ + protected function getChoiceContent(AbstractStructuralDBElement $choice, $key, $value, $options): string + { + $html = ""; + + //Add element name, use a class as whitespace which hides when not used in dropdown list + $html .= $this->getElementNameWithLevelWhitespace($choice, $options, ''); + + if ($options['show_fullpath_in_subtext'] && null !== $choice->getParent()) { + $html .= ' ' . trim(htmlspecialchars($choice->getParent()->getFullPath())) . ''; + } + + if ($choice instanceof AttachmentType && !empty($choice->getFiletypeFilter())) { + $html .= ' ' . trim(htmlspecialchars($choice->getFiletypeFilter())) . ''; + } + + return $html; + } + + protected function generateChoiceAttr(AbstractStructuralDBElement $choice, $key, $value, $options): array { $tmp = []; - if ($options['show_fullpath_in_subtext'] && null !== $choice->getParent()) { - $tmp += ['data-subtext' => $choice->getParent()->getFullPath()]; - } + //Disable attribute if the choice is marked as not selectable if ($options['disable_not_selectable'] && $choice->isNotSelectable()) { @@ -256,10 +277,13 @@ class StructuralEntityType extends AbstractType $tmp += ['data-filetype_filter' => $choice->getFiletypeFilter()]; } + //Add the HTML content that will be shown finally in the selectpicker + $tmp += ['data-content' => $this->getChoiceContent($choice, $key, $value, $options)]; + return $tmp; } - protected function generateChoiceLabels(AbstractStructuralDBElement $choice, $key, $value, $options): string + protected function getElementNameWithLevelWhitespace(AbstractStructuralDBElement $choice, $options, $whitespace = "   "): string { /** @var AbstractStructuralDBElement|null $parent */ $parent = $options['subentities_of']; @@ -271,9 +295,15 @@ class StructuralEntityType extends AbstractType $level -= $parent->getLevel() - 1; } - $tmp = str_repeat('   ', $level); //Use 3 spaces for intendation + $tmp = str_repeat($whitespace, $level); //Use 3 spaces for intendation $tmp .= htmlspecialchars($choice->getName()); return $tmp; } + + protected function generateChoiceLabels(AbstractStructuralDBElement $choice, $key, $value, $options): string + { + //Just for compatibility reasons for the case selectpicker should not work. The real value is generated in the getChoiceContent() method + return $this->getElementNameWithLevelWhitespace($choice, $options, " "); + } }