From bd8ed65e7ef4192c023198165a21e90bd476f3d4 Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 25 Aug 2022 14:26:48 +0300 Subject: [PATCH] Update BootstrapWidgetTrait (#48) * Update BootstrapWidgetTrait Using pure JS instead Jquery Optimize components activation : only 'popover', 'toast' and 'tooltip' not activates via data attributes Fix outdated PHPDoc's --- CHANGELOG.md | 1 + src/BootstrapWidgetTrait.php | 65 ++++++++++++++++++++++++------------ tests/PopoverTest.php | 2 +- tests/ToastTest.php | 18 ++++------ 4 files changed, 52 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ca685..b08f4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Yii Framework 2 bootstrap5 extension Change Log - Enh #39: Add inline mode to `BaseHtml::checkboxList()` and `BaseHtml::radioList()` (WinterSilence) - Enh #40: Breadcrumbs refactoring (WinterSilence) - Bug #46: Fix data-attribute usage for Dropdown toggle (machour) +- Enh #48: Update `BootstrapWidgetTrait` to initialize JS plugins without jQuery (WinterSilence) 2.0.3 April 22, 2022 diff --git a/src/BootstrapWidgetTrait.php b/src/BootstrapWidgetTrait.php index 519217a..5c3ce9e 100644 --- a/src/BootstrapWidgetTrait.php +++ b/src/BootstrapWidgetTrait.php @@ -13,7 +13,7 @@ use yii\base\InvalidConfigException; use yii\helpers\Json; /** - * BootstrapWidgetTrait is the trait, which provides basic for all bootstrap widgets features. + * BootstrapWidgetTrait is the trait, which provides basic for all Bootstrap widgets features. * * Note: class, which uses this trait must declare public field named `options` with the array default value: * @@ -35,22 +35,21 @@ use yii\helpers\Json; trait BootstrapWidgetTrait { /** - * @var array|bool the options for the underlying Bootstrap JS plugin. - * Please refer to the corresponding Bootstrap plugin Web page for possible options. - * For example, [this page](http://getbootstrap.com/javascript/#modals) shows - * how to use the "Modal" plugin and the supported options (e.g. "remote"). - * If this property is false, registerJs will not be called on the view to initialize the module. + * @var array|false the options for the underlying Bootstrap JS plugin/component. + * Please refer to the corresponding Bootstrap plugin/component Web page for possible options. + * For example, [this page](https://getbootstrap.com/docs/5.1/components/modal/#options) shows + * how to use the "Modal" component and the supported options (e.g. "backdrop"). + * If this property is false, `registerJs()` will not be called on the view to initialize the module. */ public $clientOptions = []; /** * @var array the event handlers for the underlying Bootstrap JS plugin. * Please refer to the corresponding Bootstrap plugin Web page for possible events. - * For example, [this page](http://getbootstrap.com/javascript/#modals) shows - * how to use the "Modal" plugin and the supported events (e.g. "shown"). + * For example, [this page](https://getbootstrap.com/docs/5.1/components/modal/#events) shows + * how to use the "Modal" plugin and the supported events (e.g. "shown.bs.modal"). */ public $clientEvents = []; - /** * Initializes the widget. * This method will register the bootstrap asset bundle. If you override this method, @@ -66,24 +65,46 @@ trait BootstrapWidgetTrait } /** - * Registers a specific Bootstrap plugin and the related events + * Registers a specific Bootstrap plugin/component and the related events. + * * @param string $name the name of the Bootstrap plugin */ protected function registerPlugin(string $name) { - $view = $this->getView(); + /** + * @see https://github.com/twbs/bootstrap/blob/v5.2.0/js/index.esm.js + */ + $jsPlugins = [ + 'alert', + 'button', + 'carousel', + 'collapse', + 'dropdown', + 'modal', + 'offcanvas', + 'popover', + 'scrollspy', + 'tab', + 'toast', + 'tooltip' + ]; + if (in_array($name, $jsPlugins, true)) { + $view = $this->getView(); + BootstrapPluginAsset::register($view); + // 'popover', 'toast' and 'tooltip' plugins not activates via data attributes + if ( + $this->clientOptions !== false + || !empty($this->clientOptions) + || in_array($name, ['popover', 'toast', 'tooltip'], true) + ) { + $name = ucfirst($name); + $id = $this->options['id']; + $options = empty($this->clientOptions) ? '{}' : Json::htmlEncode($this->clientOptions); + $view->registerJs("(new bootstrap.$name('#$id', $options));"); + } - BootstrapPluginAsset::register($view); - - $id = $this->options['id']; - - if ($this->clientOptions !== false) { - $options = empty($this->clientOptions) ? '' : Json::htmlEncode($this->clientOptions); - $js = "jQuery('#$id').$name($options);"; - $view->registerJs($js); + $this->registerClientEvents(); } - - $this->registerClientEvents(); } /** @@ -95,7 +116,7 @@ trait BootstrapWidgetTrait $id = $this->options['id']; $js = []; foreach ($this->clientEvents as $event => $handler) { - $js[] = "jQuery('#$id').on('$event', $handler);"; + $js[] = "document.getElementById('$id').addEventListener('$event', $handler);"; } $this->getView()->registerJs(implode("\n", $js)); } diff --git a/tests/PopoverTest.php b/tests/PopoverTest.php index 1dc05b1..681b3a8 100644 --- a/tests/PopoverTest.php +++ b/tests/PopoverTest.php @@ -39,7 +39,7 @@ HTML; $this->assertInternalType(IsType::TYPE_ARRAY, $js); $options = array_shift($js); - $this->assertContainsWithoutLE("jQuery('#w0').popover({", $options); + $this->assertContainsWithoutLE("(new bootstrap.Popover('#w0', {", $options); $this->assertContainsWithoutLE("id=\u0022w0-popover\u0022", $options); $this->assertContainsWithoutLE("class=\u0022test-header popover-header\u0022", $options); $this->assertContainsWithoutLE('"placement":"bottom"', $options); diff --git a/tests/ToastTest.php b/tests/ToastTest.php index 0d8add4..af9319c 100644 --- a/tests/ToastTest.php +++ b/tests/ToastTest.php @@ -140,7 +140,7 @@ HTML; $this->assertInternalType(IsType::TYPE_ARRAY, $js); $options = array_shift($js); - $this->assertContainsWithoutLE("jQuery('#w0').toast();", $options); + $this->assertContainsWithoutLE("(new bootstrap.Toast('#w0', {}));", $options); } /** @@ -160,33 +160,29 @@ HTML; $out = ob_get_clean(); $this->assertFalse($toast->clientOptions); - $this->assertArrayNotHasKey(View::POS_READY,Yii::$app->view->js); + $this->assertArrayHasKey(View::POS_READY, Yii::$app->view->js); } - /** - * - * @see https://github.com/yiisoft/yii2-bootstrap5/issues/36 - */ - public function testWidgetInitializationTrue() + public function testWidgetInitializationWithClientOptions() { Toast::$counter = 0; ob_start(); $toast = Toast::begin([ 'title' => 'Toast title', - 'clientOptions' => true, + 'clientOptions' => ['delay' => 1000], 'titleOptions' => ['tag' => 'h5', 'style' => ['text-align' => 'left']] ]); echo 'test'; Toast::end(); $out = ob_get_clean(); - $this->assertTrue($toast->clientOptions); - $this->assertArrayHasKey(View::POS_READY,Yii::$app->view->js); + $this->assertArrayHasKey('delay', $toast->clientOptions); + $this->assertArrayHasKey(View::POS_READY, Yii::$app->view->js); $js = Yii::$app->view->js[View::POS_READY]; $this->assertInternalType(IsType::TYPE_ARRAY, $js); $options = array_shift($js); - $this->assertContainsWithoutLE("jQuery('#w0').toast(true);", $options); + $this->assertContainsWithoutLE("(new bootstrap.Toast('#w0', {\"delay\":1000}));", $options); } }