From 2e18065d5af23ca8fefa2629443af2fcefda30fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Thu, 2 Feb 2023 00:36:42 +0100 Subject: [PATCH] Replaced all occurances of bootstrap-select with tomSelect All choice fields should now use tomselect by default to improve user UX --- .../controllers/elements/select_controller.js | 80 +++++++++++++++++++ .../elements/selectpicker_controller.js | 34 -------- package.json | 1 - src/Form/AdminPages/CurrencyAdminForm.php | 5 -- .../Constraints/UserEntityConstraintType.php | 5 -- src/Form/LabelOptionsType.php | 5 -- src/Form/Type/MasterPictureAttachmentType.php | 4 - src/Form/Type/PartLotSelectType.php | 4 - src/Form/Type/ThemeChoiceType.php | 4 - src/Form/UserAdminForm.php | 10 --- src/Form/UserSettingsType.php | 8 -- .../Form/extendedBootstrap4_layout.html.twig | 28 +++++-- yarn.lock | 5 -- 13 files changed, 100 insertions(+), 93 deletions(-) create mode 100644 assets/controllers/elements/select_controller.js delete mode 100644 assets/controllers/elements/selectpicker_controller.js diff --git a/assets/controllers/elements/select_controller.js b/assets/controllers/elements/select_controller.js new file mode 100644 index 00000000..e95a2361 --- /dev/null +++ b/assets/controllers/elements/select_controller.js @@ -0,0 +1,80 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {Controller} from "@hotwired/stimulus"; +import "tom-select/dist/css/tom-select.bootstrap5.css"; +import '../../css/components/tom-select_extensions.css'; +import TomSelect from "tom-select"; + +export default class extends Controller { + + _tomSelect; + + _emptyMessage; + + connect() { + + this._emptyMessage = this.element.getAttribute("data-empty-message") ?? ""; + if (this._emptyMessage === "" && this.element.hasAttribute('title')) { + this._emptyMessage = this.element.getAttribute('title'); + } + + + let settings = { + allowEmptyOption: true, + selectOnTab: true, + maxOptions: null, + + render: { + item: this.renderItem.bind(this), + option: this.renderOption.bind(this), + } + }; + + this._tomSelect = new TomSelect(this.element, settings); + } + + renderItem(data, escape) { + //The empty option is rendered muted + if (data.value === "") { + let text = data.text; + //If no text was defined on the option, we use the empty message + if (!text) { + text = this._emptyMessage; + } + //And if that is not defined, we use a space to make the option visible + if (!text) { + text = " "; + } + return '
' + escape(text) + '
'; + + } + + return '
' + escape(data.text) + '
'; + } + + renderOption(data, escape) { + //The empty option is rendered muted + if (data.value === "" && data.text === "") { + return '
 
'; + } + + return '
' + escape(data.text) + '
'; + } +} \ No newline at end of file diff --git a/assets/controllers/elements/selectpicker_controller.js b/assets/controllers/elements/selectpicker_controller.js deleted file mode 100644 index df9c2cdd..00000000 --- a/assets/controllers/elements/selectpicker_controller.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -const bootstrap = window.bootstrap = require('bootstrap'); // without this bootstrap-select crashes with `undefined bootstrap` -require('bootstrap-select/js/bootstrap-select'); // we have to manually require the working js file - -import {Controller} from "@hotwired/stimulus"; -import "../../css/lib/boostrap-select.css"; -import "../../css/components/selectpicker_extensions.css"; - -export default class extends Controller { - connect() { - $(this.element).selectpicker({ - dropdownAlignRight: 'auto', - container: '#content', - }); - } -} \ No newline at end of file diff --git a/package.json b/package.json index aa430f53..ca99967e 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ "@ckeditor/ckeditor5-word-count": "^36.0.0", "@jbtronics/bs-treeview": "^1.0.1", "bootbox": "^6.0.0", - "bootstrap-select": "v1.14.0-beta3", "bootswatch": "^5.1.3", "bs-custom-file-input": "^1.3.4", "clipboard": "^2.0.4", diff --git a/src/Form/AdminPages/CurrencyAdminForm.php b/src/Form/AdminPages/CurrencyAdminForm.php index 32465dd8..19123465 100644 --- a/src/Form/AdminPages/CurrencyAdminForm.php +++ b/src/Form/AdminPages/CurrencyAdminForm.php @@ -47,11 +47,6 @@ class CurrencyAdminForm extends BaseEntityAdminForm 'required' => false, 'label' => 'currency.edit.iso_code', 'preferred_choices' => ['EUR', 'USD', 'GBP', 'JPY', 'CNY'], - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'title' => 'selectpicker.nothing_selected', - 'data-live-search' => true, - ], 'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]); diff --git a/src/Form/Filters/Constraints/UserEntityConstraintType.php b/src/Form/Filters/Constraints/UserEntityConstraintType.php index 18082f87..9b28e2ce 100644 --- a/src/Form/Filters/Constraints/UserEntityConstraintType.php +++ b/src/Form/Filters/Constraints/UserEntityConstraintType.php @@ -54,11 +54,6 @@ class UserEntityConstraintType extends AbstractType $builder->add('value', EntityType::class, [ 'class' => User::class, 'required' => false, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'data-live-search' => true, - 'title' => 'selectpicker.nothing_selected', - ] ]); diff --git a/src/Form/LabelOptionsType.php b/src/Form/LabelOptionsType.php index 4ce77e8b..5af69ce6 100644 --- a/src/Form/LabelOptionsType.php +++ b/src/Form/LabelOptionsType.php @@ -111,11 +111,6 @@ class LabelOptionsType extends AbstractType return null; }, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'title' => 'selectpicker.nothing_selected', - 'data-live-search' => true, - ], ]); $builder->add('lines', RichTextEditorType::class, [ diff --git a/src/Form/Type/MasterPictureAttachmentType.php b/src/Form/Type/MasterPictureAttachmentType.php index d21b9fb8..7aba9cc6 100644 --- a/src/Form/Type/MasterPictureAttachmentType.php +++ b/src/Form/Type/MasterPictureAttachmentType.php @@ -42,10 +42,6 @@ class MasterPictureAttachmentType extends AbstractType $resolver->setDefaults([ 'filter' => 'picture', 'choice_translation_domain' => false, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'title' => 'selectpicker.nothing_selected', - ], 'choice_attr' => static function (Options $options) { return static function ($choice, $key, $value) use ($options) { /** @var Attachment $choice */ diff --git a/src/Form/Type/PartLotSelectType.php b/src/Form/Type/PartLotSelectType.php index aa3c6fc6..61e119b0 100644 --- a/src/Form/Type/PartLotSelectType.php +++ b/src/Form/Type/PartLotSelectType.php @@ -47,10 +47,6 @@ class PartLotSelectType extends AbstractType return ($part_lot->getStorageLocation() ? $part_lot->getStorageLocation()->getFullPath() : '') . ' (' . $part_lot->getName() . '): ' . $part_lot->getAmount(); }), - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'data-live-search' => true, - ], 'query_builder' => function (Options $options) { return function (EntityRepository $er) use ($options) { return $er->createQueryBuilder('l') diff --git a/src/Form/Type/ThemeChoiceType.php b/src/Form/Type/ThemeChoiceType.php index 82b2fe8a..88843903 100644 --- a/src/Form/Type/ThemeChoiceType.php +++ b/src/Form/Type/ThemeChoiceType.php @@ -46,10 +46,6 @@ class ThemeChoiceType extends AbstractType 'choice_label' => static function ($entity, $key, $value) { return $value; }, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'title' => 'selectpicker.nothing_selected', - ], 'choice_translation_domain' => false, 'placeholder' => 'user_settings.theme.placeholder' ]); diff --git a/src/Form/UserAdminForm.php b/src/Form/UserAdminForm.php index 8ec75247..774cf8f7 100644 --- a/src/Form/UserAdminForm.php +++ b/src/Form/UserAdminForm.php @@ -130,11 +130,6 @@ class UserAdminForm extends AbstractType //Config section ->add('language', LanguageType::class, [ 'required' => false, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'title' => 'selectpicker.nothing_selected', - 'data-live-search' => true, - ], 'placeholder' => 'user_settings.language.placeholder', 'label' => 'user.language_select', 'preferred_choices' => ['en', 'de'], @@ -142,11 +137,6 @@ class UserAdminForm extends AbstractType ]) ->add('timezone', TimezoneType::class, [ 'required' => false, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'title' => 'selectpicker.nothing_selected', - 'data-live-search' => true, - ], 'placeholder' => 'user_settings.timezone.placeholder', 'label' => 'user.timezone.label', 'preferred_choices' => ['Europe/Berlin'], diff --git a/src/Form/UserSettingsType.php b/src/Form/UserSettingsType.php index 89680a6c..fd07ea3b 100644 --- a/src/Form/UserSettingsType.php +++ b/src/Form/UserSettingsType.php @@ -96,10 +96,6 @@ class UserSettingsType extends AbstractType ->add('language', LanguageType::class, [ 'disabled' => $this->demo_mode, 'required' => false, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'data-live-search' => true, - ], 'placeholder' => 'user_settings.language.placeholder', 'label' => 'user.language_select', 'preferred_choices' => ['en', 'de'], @@ -107,10 +103,6 @@ class UserSettingsType extends AbstractType ->add('timezone', TimezoneType::class, [ 'disabled' => $this->demo_mode, 'required' => false, - 'attr' => [ - 'data-controller' => 'elements--selectpicker', - 'data-live-search' => true, - ], 'placeholder' => 'user_settings.timezone.placeholder', 'label' => 'user.timezone.label', 'preferred_choices' => ['Europe/Berlin'], diff --git a/templates/Form/extendedBootstrap4_layout.html.twig b/templates/Form/extendedBootstrap4_layout.html.twig index 60f1dc2e..2a599672 100644 --- a/templates/Form/extendedBootstrap4_layout.html.twig +++ b/templates/Form/extendedBootstrap4_layout.html.twig @@ -23,12 +23,12 @@ {% block si_unit_widget %}
{{ form_widget(form.value) }} - {% if form.prefix is defined %} - {{ form_widget(form.prefix, {'attr': {'class': '', 'style': 'max-width: 40px;'}}) }} - {% endif %} - {% if unit is not empty %} - - {% endif %} + {% if form.prefix is defined %} + {{ form_widget(form.prefix, {'attr': {'class': '', 'style': 'max-width: 40px;'}}) }} + {% endif %} + {% if unit is not empty %} + + {% endif %}
{{ form_errors(form.value) }} {% endblock %} @@ -98,12 +98,24 @@ {%- block choice_widget_collapsed -%} {# Only add the BS5 form-select class if we dont use bootstrap-selectpicker #} - {% if attr["data-controller"] is defined and attr["data-controller"] not in ["elements--selectpicker"] %} + {# {% if attr["data-controller"] is defined and attr["data-controller"] not in ["elements--selectpicker"] %} {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-select')|trim}) -%} {% else %} - {# If it is an selectpicker add form-control class to fill whole width #} + {# If it is an selectpicker add form-control class to fill whole width {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) -%} {% endif %} + #} + + {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-select')|trim}) -%} + + {# If no data-controller was explictly defined add data-controller=elements--select #} + {% if attr["data-controller"] is not defined %} + {%- set attr = attr|merge({"data-controller": "elements--select"}) -%} + + {% if attr["data-empty-message"] is not defined %} + {%- set attr = attr|merge({"data-empty-message": ("selectpicker.nothing_selected"|trans)}) -%} + {% endif %} + {% endif %} {{- block("choice_widget_collapsed", "bootstrap_base_layout.html.twig") -}} {%- endblock choice_widget_collapsed -%} diff --git a/yarn.lock b/yarn.lock index 451c60be..14e83378 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2241,11 +2241,6 @@ bootbox@^6.0.0: resolved "https://registry.yarnpkg.com/bootbox/-/bootbox-6.0.0.tgz#a5f1074faab38b881e79e009ea4d625c7e8c536d" integrity sha512-+Calbj1v5UvxAXXDAHfoBlsx63Hcz1JqHaZdJ5EjIcOlkyAbZLCreVScx0Em6ZUvsMCqynuz/3nGDyd9FtFrNQ== -bootstrap-select@v1.14.0-beta3: - version "1.14.0-beta3" - resolved "https://registry.yarnpkg.com/bootstrap-select/-/bootstrap-select-1.14.0-beta3.tgz#dc15083fe51d0ac7b38a3b99dfd492dcc0a783b0" - integrity sha512-wYUDY4NAYBcNydXybE7wh3+ucyf+AcUOhZ+e0TFIoZ38A+k/3BVT1RPl5f0CiPxAexP1IQuqALKMqI8wtZS71A== - bootstrap@^5.1.3: version "5.2.3" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.3.tgz#54739f4414de121b9785c5da3c87b37ff008322b"