copied missing tests and actions and docs from bs4

This commit is contained in:
Simon Karlen 2021-07-09 11:53:24 +02:00
parent c92be88adf
commit 887efc4147
No known key found for this signature in database
GPG Key ID: 0630C27D666EBCC3
100 changed files with 6302 additions and 15 deletions

7
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,7 @@
Contributing to Yii2
====================
- [Report an issue](https://github.com/yiisoft/yii2/blob/master/docs/internals/report-an-issue.md)
- [Translate documentation or messages](https://github.com/yiisoft/yii2/blob/master/docs/internals/translation-workflow.md)
- [Give us feedback or start a design discussion](http://www.yiiframework.com/forum/index.php/forum/42-general-discussions-for-yii-20/)
- [Contribute to the core code or fix bugs](https://github.com/yiisoft/yii2/blob/master/docs/internals/git-workflow.md)

5
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,5 @@
# These are supported funding model platforms
open_collective: yiisoft
github: [yiisoft]
tidelift: "packagist/yiisoft/yii2-bootstrap4"

19
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,19 @@
<!--
Please use this issue tracker for bugs and feature requests only. In case you need support please use one of
Yii communities listed at https://github.com/yiisoft/yii2/wiki/communities
-->
### What steps will reproduce the problem?
### What's expected?
### What do you get instead?
### Additional info
| Q | A
| ---------------- | ---
| Yii vesion |
| PHP version |
| Operating system |

7
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,7 @@
| Q | A
| ------------- | ---
| Is bugfix? | yes/no
| New feature? | yes/no
| Breaks BC? | yes/no
| Tests pass? | yes/no
| Fixed issues | comma-separated list of tickets # fixed by the PR, if any

6
.github/SECURITY.md vendored Normal file
View File

@ -0,0 +1,6 @@
# Security Policy
Please use the [security issue form](https://www.yiiframework.com/security) to report to us any security issue you find in Yii.
DO NOT use the issue tracker or discuss it in the public forum as it will cause more damage than help.
Please note that as a non-commerial OpenSource project we are not able to pay bounties at the moment.

47
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,47 @@
name: build
on: [push, pull_request]
env:
DEFAULT_COMPOSER_FLAGS: "--prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi"
jobs:
phpunit:
name: PHP ${{ matrix.php }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
php: ['7.4', '8.0']
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer update $DEFAULT_COMPOSER_FLAGS
- name: Run unit tests with coverage
run: vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --colors=always
if: matrix.php == '7.4'
- name: Run unit tests without coverage
run: vendor/bin/phpunit --verbose --colors=always
if: matrix.php != '7.4'
- name: Upload code coverage
run: |
wget https://scrutinizer-ci.com/ocular.phar
php ocular.phar code-coverage:upload --format=php-clover coverage.clover
if: matrix.php == '7.4'
continue-on-error: true # if is fork

6
CHANGELOG.md Normal file
View File

@ -0,0 +1,6 @@
Yii Framework 2 bootstrap5 extension Change Log
==============================================
1.0.0 under development
-----------------------
- Initial release

29
LICENSE.md Normal file
View File

@ -0,0 +1,29 @@
Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Yii Software LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

49
README.md Normal file
View File

@ -0,0 +1,49 @@
<p align="center">
<a href="http://getbootstrap.com/" target="_blank" rel="external">
<img src="https://getbootstrap.com/docs/5.0/assets/brand/bootstrap-logo.svg" height="80px">
</a>
<h1 align="center">Twitter Bootstrap 5 Extension for Yii 2</h1>
<br>
</p>
This is the Twitter Bootstrap extension for [Yii framework 2.0](http://www.yiiframework.com). It encapsulates [Bootstrap 5](http://getbootstrap.com/) components
and plugins in terms of Yii widgets, and thus makes using Bootstrap components/plugins
in Yii applications extremely easy.
For license information check the [LICENSE](LICENSE.md)-file.
Documentation is at [docs/guide/README.md](docs/guide/README.md).
[![Latest Stable Version](https://poser.pugx.org/simialbi/yii2-bootstrap5/v/stable.png)](https://packagist.org/packages/simialbi/yii2-bootstrap5)
[![Total Downloads](https://poser.pugx.org/simialbi/yii2-bootstrap5/downloads.png)](https://packagist.org/packages/simialbi/yii2-bootstrap5)
[![Build Status](https://github.com/simialbi/yii2-bootstrap5/workflows/build/badge.svg)](https://github.com/simialbi/yii2-bootstrap5/actions)
Installation
------------
The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
Either run
```
php composer.phar require --prefer-dist simialbi/yii2-bootstrap5
```
or add
```
"simialbi/yii2-bootstrap5": "~1.0@dev"
```
to the require section of your `composer.json` file.
Usage
----
For example, the following
single line of code in a view file would render a Bootstrap Progress plugin:
```php
<?= yii\bootstrap5\Progress::widget(['percent' => 60, 'label' => 'test']) ?>
```

View File

@ -1,5 +1,5 @@
{ {
"name": "mylistryx/yii2-bootstrap5", "name": "simialbi/yii2-bootstrap5",
"description": "The Twitter Bootstrap v5 extension for the Yii framework", "description": "The Twitter Bootstrap v5 extension for the Yii framework",
"version": "1.0.0", "version": "1.0.0",
"keywords": [ "keywords": [
@ -10,25 +10,29 @@
"type": "yii2-extension", "type": "yii2-extension",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"support": { "support": {
"source": "https://github.com/mylistryx/yii2-bootstrap45" "source": "https://github.com/simialbi/yii2-bootstrap5"
}, },
"authors": [ "authors": [
{ {
"name": "Sergey Zhukovskiy", "name": "Sergey Zhukovskiy",
"email": "mylistryx@gmail.com", "email": "mylistryx@gmail.com",
"homepage": "https://net23.ru/" "homepage": "https://net23.ru/"
},
{
"name": "Simon Karlen",
"email": "simi.albi@outlook.com"
} }
], ],
"minimum-stability": "dev", "minimum-stability": "stable",
"require": { "require": {
"php": "~7.4.0", "php": ">=7.4.0",
"yiisoft/yii2": "~2.0", "ext-json": "*",
"npm-asset/bootstrap": "^5.0.0", "yiisoft/yii2": "^2.0.42",
"ext-json": "*" "npm-asset/bootstrap": "^5.0.0"
}, },
"require-dev": { "require-dev": {
"yiisoft/yii2-coding-standards": "~2.0", "yiisoft/yii2-coding-standards": "~2.0",
"cweagans/composer-patches": "^1.7" "phpunit/phpunit": "^7.5.20"
}, },
"repositories": [ "repositories": [
{ {
@ -41,6 +45,11 @@
"yii\\bootstrap5\\": "src" "yii\\bootstrap5\\": "src"
} }
}, },
"autoload-dev": {
"psr-4": {
"yiiunit\\extensions\\bootstrap5\\": "tests"
}
},
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.0.x-dev"

30
docs/guide-de/README.md Normal file
View File

@ -0,0 +1,30 @@
Twitter Bootstrap Erweiterung für Yii 2
=======================================
Diese Erweiterung enthält Unterstützung für das [Bootstrap 4 Framework](http://getbootstrap.com/) (auch bekannt als "Twitter Bootstrap")
Markup und dessen Komponenten. Bootstrap ist eine exzellentes, reponsives Framework welches den clientseitigen
Entwicklungsprozess vehement zu verkürzen vermag.
Die Basis von Bootstrap ist unterteilt in folgende 2 Bereiche:
- CSS Basics: Grid Layout System, Typography, Helper-Klassen, Responsive Funktionen.
- "Ready to use"-Komponenten: Formulare, Menus, Paginationen, Modals, Tabs etc.
Loslegen
--------
* [Installation](installation.md)
* [Assets Setup](assets-setup.md)
* [Basic Usage](basic-usage.md)
Verwendung
----------
* [Yii widgets](usage-widgets.md)
* [Html helper](helper-html.md)
* [Asset Bundles](asset-bundles.md)
Weitere Themen
--------------
* [Using the .sass files of Bootstrap directly](topics-sass.md)
* [Migration von yii2-bootstrap](migrating-yii2-bootstrap.md)

View File

@ -0,0 +1,15 @@
Asset Bundles
=============
Bootstrap ist eine komplexe Front-End-Lösung, welche CSS, Javascript, Schriften usw. beinhaltet.
Um Ihnen die flexibelste Kontrolle über die einzelnen Komponenten zu ermöglichen enthält diese Erweiterung verschiedene Asset Bundles.
Das sind:
- [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] - enthält nur das hauptsächliche CSS.
- [[yii\bootstrap4\BootstrapPluginAsset|BootstrapPluginAsset]] - enthält das Javascript. Abhängig von [[yii\bootstrap4\BootstrapAsset]].
Verschiedene Anwendunganforderungen erfordern verschiedene Bundles (bzw. Kombinationen).
Falls Sie nur auf das CSS angewiesen sind, reicht es wenn Sie [[yii\bootstrap4\BootstrapAsset]] laden.
Wenn Sie das Javascript verwenden möchten, müssen Sie [[yii\bootstrap4\BootstrapPluginAsset]] auch laden.
> Tipp: Die meisten Widgets laden [[yii\bootstrap4\BootstrapPluginAsset]] automatisch.

View File

@ -0,0 +1,170 @@
Asset-Konfiguration
===================
Diese Erweiterung beruht auf [Bower](http://bower.io/) und/oder [NPM](https://www.npmjs.org/) Packages für die Asset Installation.
Bevor Sie diese Erweiterung einsetzen, sollten Sie entscheiden, auf welche Weise Sie diese Packages installieren möchten.
## Verwendung des asset-packagist Repository
Sie können [asset-packagist.or](https://asset-packagist.org) als Package-Quelle für die Bootstrap-Assets angeben.
Fügen Sie dazu folgende Zeilen zur `composer.json`-Datei ihres Projekts hinzu:
```json
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
```
Passen Sie `@npm` und `@bower` in der Konfiguration ihrer Applikation wie folgt an:
```php
return [
//...
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
//...
];
```
## Verwendung des composer asset Plugins
Installieren Sie das [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/) global durch das Ausführen folgendes Befehls:
```
composer global require "fxp/composer-asset-plugin:^1.4.0"
```
Fügen Sie folgende Zeilen zur `composer.json`-Datei ihres Projekts hinzu um das Verzeichnis der Installation von Assets anzupassen
falls Sie möchten, das Yii sie verwaltet:
```json
"extra": {
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
```
Daraufhin können Sie den composer install bzw. update Befehl ausführen um die Boostrap Assets zu installieren.
> Warnung: Das Plugin `fxp/composer-asset-plugin` verlangsamt den `composer update` Befehl signifikant verglichen zur
"asset-packagist"-Methode.
## Direkte Verwendung des Bower/NPM Clients
Sie kännen die Bootstrap Assets direkt via Bower oder NPM Client installieren.
Fügen Sie dafür folgende Zeilen zur `package.json`-Datei Ihres Projekts hinzu:
```json
{
...
"dependencies": {
"bootstrap": "4.2.1",
...
}
...
}
```
Fügen Sie zur `composer.json`-Datei Ihres Projekts folgende Zeilen hinzu zum Verhindern von redundanten Bootstrap-Installationen:
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
## Verwendung des CDN
Sie können die Bootstrap Assets vom [offiziellen CDN](https://www.bootstrapcdn.com) laden.
Fügen Sie zur `composer.json`-Datei Ihres Projekts folgende Zeilen hinzu zum Verhindern von redundanten Bootstrap-Installationen:
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
Konfigurieren Sie die 'assetManager'-Komponente wie folgt (überschreibt die Bootstrap Asset mit den CDN Links):
```php
return [
'components' => [
'assetManager' => [
// override bundles to use CDN :
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'sourcePath' => null,
'baseUrl' => 'https://stackpath.bootstrapcdn.com/bootstrap/4.2.1',
'css' => [
'css/bootstrap.min.css'
],
],
'yii\bootstrap4\BootstrapPluginAsset' => [
'sourcePath' => null,
'baseUrl' => 'https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1',
'js' => [
'js/bootstrap.bundle.min.js'
],
],
],
],
// ...
],
// ...
];
```
## Kompilieren von den .sass Dateien
Falls Sie den Bootstrap Quelltext direkt anpassen möchten, können Sie das CSS direkt von den Quell *.sass-Dateien kompilieren.
In diesem Fall macht die Installation der Bootstrap Assets via composer bzw. Bower/NPM kein Sinn, da Sie keine Dateien innerhalb
des 'vendor'-Verzeichnisses bearbeiten können.
Sie müssen die Bootstrap-Assets manuell herunterladen und sie irgendwo in Ihrem Projekt platzieren (z.B. 'assets/source/bootstrap').
Fügen Sie zur `composer.json`-Datei Ihres Projekts folgende Zeilen hinzu zum Verhindern von redundanten Bootstrap-Installationen:
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
Konfigurieren Sie die 'assetManager'-Komponente wie folgt (überschreibt die Bootstrap Assets):
```php
return [
'components' => [
'assetManager' => [
// override bundles to use local project files :
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'sourcePath' => '@app/assets/source/bootstrap/dist',
'css' => [
YII_ENV_DEV ? 'css/bootstrap.css' : 'css/bootstrap.min.css',
],
],
'yii\bootstrap4\BootstrapPluginAsset' => [
'sourcePath' => '@app/assets/source/bootstrap/dist',
'js' => [
YII_ENV_DEV ? 'js/bootstrap.js' : 'js/bootstrap.min.js',
]
],
],
],
// ...
],
// ...
];
```
Nach dem Verändern des Bootstrap Quellcodes, stellen Sie sicher, dass sie neu [kompiliert werden](https://getbootstrap.com/docs/4.1/getting-started/build-tools/), z.B. mittels `npm run dist`.

View File

@ -0,0 +1,17 @@
Grundlegende Verwendung
=======================
Yii verpackt die Bootstrap Basics nicht in PHP Code, da dass HTML selbst sehr einfach aufgebaut ist. Sie finden mehr
Informationen zur Verwendung der Basics unter [bootstrap documentation website](http://getbootstrap.com/css/). Yii bietet
aber eine einfache Methode zur Einbindung der Bootstrap Assets in Ihre Seite durch das Hinzufügen einer Zeile zu `AppAsset.ph`
im `@app/assets` Verzeichnis:
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // Diese Zeile
];
```
Die Verwendung von Bootstrap mittels des Yii Asset Manager erlaubt die Komprimierung und Kombinierung der Bootstrapressourcen
mit den Applikationsressourcen (falls nötig).

View File

@ -0,0 +1,28 @@
HTML helper
===========
Bootstrap führt viele konsistente HTML Strukturen ein, welche es erlauben, verschiedene visuelle Effekte einfach zu verwenden.
Ausschliesslich die komplexesten von ihnen sind mittels Widgets in dieser Erweiterung umgesetzt worden. Der Rest kann manuell
mittels HTML zusammengestellt werden.
Einige spezielle Bootstrap Markups sind implementiert im [[\yii\bootstrap4\Html]]-Helper.
Die [[\yii\bootstrap4\Html]]-Klasse ist eine Erweiterung der regulären [[\yii\helpers\Html]]-Klasse mit Anpassungen zur
Verwendung mit Bootstrap. Sie bietet verschiedene nützliche Methoden.
Die [[\yii\bootstrap4\Html]]-Klasse erbt von der [[\yii\helpers\Html]]-Klasse und ersetzt diese dadurch vollumfänglich.
Sie benötigen folglich **nicht** beide in Ihren Views.
Beispiel:
```php
<?php
use yii\bootstrap4\Button;
use yii\bootstrap4\Html;
?>
<?= Button::widget([
'label' => Html::tag('i', ['class' => 'fas fa-check']) . Html::encode('Save & apply'),
'encodeLabel' => false,
'options' => ['class' => 'btn-primary'],
]); ?>
```
> Vorsicht: Verwechseln Sie [[\yii\bootstrap4\Html]] und [[\yii\helpers\Html]] Klassen nicht und bedenken Sie jeweils
welche Sie in Ihren Views verwenden.

View File

@ -0,0 +1,20 @@
Installation
============
## Mittels Composer Package
Der empfohlene Weg zur Installation dieser Erweiterung ist mittels [composer](http://getcomposer.org/download/).
Führen Sie entweder folgenden Befehlt aus
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
oder fügen Sie folgendes
```
"yiisoft/yii2-bootstrap4": "~1.0.0"
```
zur `require`-Sektion Ihrer `composer.json`-Datei hinzu.

View File

@ -0,0 +1,110 @@
Migration von yii2-bootstrap
============================
yii2-bootstrap4 ist eine komplette Überarbeitung des Projekts (siehe den Bootstrap 4 von Bootstrap 3 Migrationsguide).
Die grössten Änderungen finden Sie hier zusammengefasst:
## Allgemein
* Der Namespace ist nun `yii\bootstrap4` anstatt `yii\bootstrap`
* Es wird das `npm` Paket verwendet anstatt das `bower` Paket
* Es gibt kein Theme Asset mehr
* `popper.js` muss nicht mehr extra installiert werden (wird vom Bootstrap JS Bundle mitgeliefert)
## Widgets / Klassen
* [[yii\bootstrap\Collapse|Collapse]] wurde umbenannt zu [[yii\bootstrap4\Accordion|Accordion]]
* [[yii\bootstrap\BootstrapThemeAsset|BootstrapThemeAsset]] wurde entfernt
* [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]] wurde hinzugefügt (Bootstrap 4 Implementation von [[yii\widgets\Breadcrumbs]])
* [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]] wurde hinzugefügt (https://getbootstrap.com/docs/4.3/components/button-group/#button-toolbar)
### BaseHtml
Die Methode `icon` wurde entfernt. Sie macht keinen Sinn mehr, da Bootstrap 4 keine Icons mehr mit sich bringt. Eine
mögliche Alternative wäre das [Font Awesome Widget](https://github.com/rmrevin/yii2-fontawesome) oder aber das
[Font Awesome Inline Widget](https://github.com/YiiRocks/yii2-fontawesome-inline).
### ActiveField
Folgende Properties wurden umbenannt:
* `$checkboxTemplate` zu `$checkTemplate`,
* `$horizontalCheckboxTemplate` zu `$checkHorizontalTemplate`,
* `$horizontalRadioTemplate` zu `$radioHorizontalTemplate`
Die Properties `$inlineCheckboxListTemplate` und `$inlineRadioListTemplate` wurden entfernt. Dafür gibt es ein neues
Template mit dem Namen `$checkEnclosedTemplate`. In Bootstrap 4 sind Checkboxen standardmässig nicht mehr von Labeln
eingeschlossen.
### ActiveForm
Hier wurden die Konstanten [[yii\bootstrap4\ActiveForm::LAYOUT_DEFAULT]], [[yii\bootstrap4\ActiveForm::LAYOUT_HORIZONTAL]]
und [[yii\bootstrap4\ActiveForm::LAYOUT_INLINE]] eingeführt. Sie sollen die Verwendung der Layout vereinfachen und bei
allfälligen Änderungen der Werte Folgefehler verhindern.
### Breadcrumbs
Dieses Widget wurde neu eingeführt um die Korrekte Darstellung von Breadcrumbs im Bootstrap 4 Design zu gerwährleisten.
Es ist vollständig komptibel mit [[yii\widgets\Breadcrumbs]].
### ButtonDropdown
Dieses Widget hat ein neues Property mit Namen `$direction` erhalten. Es ermöglicht die Anzeige des Menüs auf z.B. der
rechten Seite des Buttons. Des weiteren gibt es die Konstanten [[yii\bootstrap4\ButtonDropdown::DIRECTION_DOWN]],
[[yii\bootstrap4\ButtonDropdown::DIRECTION_LEFT]], [[yii\bootstrap4\ButtonDropdown::DIRECTION_RIGHT]] und
[[yii\bootstrap4\ButtonDropdown::DIRECTION_UP]] um die Richtungsselektion zu vereinfachen.
Es wurde ein weiteres Property eingeführt mit dem Namen `$renderContainer`. Falls dieses auf `false` gestellt wird, wird
das rendern des das Dropdown umfassenden DIVs verhindert.
Folgende Properties wurden umbenannt:
* `$containerOptions` zu `$options`,
* `$options` zu `$buttonOptions`
### ButtonToolbar
Dieses Widget wurde eingeführt um einfach Button-Toolbars zu erstellen. Weitere Informationen erhalten Sie unter
https://getbootstrap.com/docs/4.3/components/button-group/#button-toolbar.
### Carousel
Dieses Widget hat das Property `$crossfade` erhalten. Es erlaubt das Ändern der Animation zwischen den Slides auf ein Fade,
anstatt eines Slided wenn es auf `true` gestellt wird.
### LinkPager
Dieses neue Widget repräsentiert die Bootstrap Version von [[yii\widgets\LinkPager]]. Es rendert eine Pagination im Bootstrap
Stil. Weitere Informationen erhalten Sie unter https://getbootstrap.com/docs/4.3/components/pagination/.
### Modal
Folgende Properties wurden umbenannt:
* `$header` zu `$title`,
* `$headerOptions` zu `$titleOptions`
Des Weiteren ist es nicht mehr von nöten, beim `$title` die Titel-Tags `<h2 class="modal-title></h2>` anzugeben. Diese
werden nun automatisch gerendert.
### Nav
Das `$dropdDownCaret` Property wurde entfernt. Dies ist nur noch über (S)CSS steuerbar. Weitere Informationen erhalten Sie
unter https://getbootstrap.com/docs/4.3/getting-started/theming/#sass-options
### NavBar
Folgende Properties wurden umbenannt:
* `$containerOptions` zu `$collapseOptions`
Das Property `$headerContent` wurde entfernt. Der "Toggler" ist nun anpassbar. Dazu gibt es neu die Properties
`$togglerContent` sowie `$togglerOptions`.
### Tabs
Es gibt neu das Property `$panes`. Es ermöglicht das Definieren der Tabinhalte via separatem Property anstatt über
`$items[0]['content']`. Der Index des panes-Arrays korrespondiert mit dessen des items-Arrays. Z.B. gehört `$items[0]`
zu `$panes[0]`.
### ToggleButtonGroup
Dieses Widget hat die Konstanten [[yii\bootstrap4\ToggleButtonGroup::TYPE_CHECKBOX]] und
[[yii\bootstrap4\ToggleButtonGroup::TYPE_RADIO]] erhalten zur vereinfachten Selektion des Typs und bei allfälligen
Änderungen der Werte zur Verhinderung von Folgefehlern.

View File

@ -0,0 +1,17 @@
Direkte Verwendung der .sass Dateien von Bootstrap
==================================================
Falls Sie das [Bootstrap CSS direkt in Ihre SASS-Dateien integerieren](https://getbootstrap.com/docs/4.1/getting-started/theming/#sass)
möchten, müssen Sie unter Umständen das Laden der Orginal Bootstrap-CSS-Dateien verhindern.
Dies können Sie durch das Leeren des `css`-Property in der [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]]-Datei bewerkstelligen.
Konfigurieren Sie dazu die `assetManager`-[Komponente](https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-application-components.md) wie folgt:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [],
]
]
]
```

View File

@ -0,0 +1,91 @@
Yii widgets
===========
Die komplexesten Bootstrap Komponenten sind umgesetzt mittels Yii-Widget zur vereinfachten Verwendung und Integration
von Framework-Funktionen. Alle Widgets gehören zum `\yii\bootstrap4` Namespace:
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]
## Anpassen der Widget CSS-Klassen <span id="customizing-css-classes"></span>
Die Widgets erlauben die schnelle Erstellung von HTML-Markup der Bootstrap Komponenten.
Die Standard-CSS-Klassen einer bestimmten Komponente wird automatisch vom Widget hinzugefügt. Alle weiteren (optionalen)
Klassen können Sie mittels der Attribute des Widgets anpassen.
Verwenden Sie z.B. [[yii\bootstrap4\Button::options]] zur Anpassung des Aussehens des Buttons. Die Klasse `btn`, welche
benötigt vom Button Widget benötigt wird, wird automatisch hinzugefügt. Sie müssen lediglich die besondere Button-Klasse
hinzufügen:
```php
echo Button::widget([
'label' => 'Action',
'options' => ['class' => 'btn-primary'], // produces class "btn btn-primary"
]);
```
Manchmal möchte man aber die Standard-Klasse ersetzen.
Das [[yii\bootstrap4\ButtonGroup]]-Widget beispielsweise verwendet standardmässig die 'btn-group' Klasse für den Container,
es müsste aber 'btn-group-vertical' erhalten zur vertikalen Ausrichtung.
Würden Sie wie oben nur die 'class'-Option verwenden, würde die 'btn-group-vertical'-Klasse zur 'btn-group'-Klasse hinzugefügt.
Zum Überschreiben der Standard-Klassen eines Widgets, müssen Sie die 'class'-Option unter dem Array-Schlüssel 'widget' angeben:
```php
echo ButtonGroup::widget([
'options' => [
'class' => ['widget' => 'btn-group-vertical'] // replaces 'btn-group' with 'btn-group-vertical'
],
'buttons' => [
['label' => 'A'],
['label' => 'B'],
]
]);
```
## Navbar widget <span id="navbar-widget"></span>
Das Navbar Widget hat so seine Eigenheiten. Bei der Verwendung des Widgets sollten Sie darauf achten, dass der Breakpoint,
ab welchem die Navigation zugeklappt wird (Mobile Navigation) sowie das Farbschema definiert sind.
Diese Definition geschieht über CSS Klassen. Die Standartwerte lauten `navbar-light bg-light` fürs Farbschema und
`navbar-expand-lg` für den brakpoint. Für weitere Informationen, konsultieren Sie die [Bootstrap Dokumentation](https://getbootstrap.com/docs/4.2/components/navbar/):
```php
Navbar::begin([
'options' => [
'class' => ['navbar-dark', 'bg-dark', 'navbar-expand-md']
]
]);
[...]
Navbar::end();
```
Falls Sie die Reihenfolge des Logos und des "Toggle Buttons" ändern möchten, können Sie dies wie folgt tun:
```php
Navbar::begin([
'brandOptions' => [
'class' => ['order-1']
],
'togglerOptions' => [
'class' => ['order-0']
]
]);
[...]
Navbar::end();
```

29
docs/guide-es/README.md Normal file
View File

@ -0,0 +1,29 @@
Extensión Twitter Bootstrap para Yii 2
======================================
La extensión incluye soporte para el marcado de [Bootstrap 4](http://getbootstrap.com/) y los componentes del framework
(también conocido como "Twitter Bootstrap"). Bootstrap es un excelente framework responsivo que puede acelerar
enormemente el proceso de desarrollo del lado del cliente.
El núcleo de Boostrap está representado por dos partes:
- Bases de CSS, tales como un sistema de cuadriculas, tipografía, clases de ayuda, y utilidades responsivas.
- Componentes listos para usar, tales como formularios, menús, paginación, cajas modales, tabs, etc.
Pasos Iniciales
---------------
* [Instalación](installation.md)
* [Uso Básico](basic-usage.md)
Uso
---
* [Yii widgets](usage-widgets.md)
* [Html helper](helper-html.md)
* [Asset Bundles](asset-bundles.md)
Temas Adicionales
-----------------
* [Usando directamente los ficheros .sass de Bootstrap](topics-sass.md)

View File

@ -0,0 +1,16 @@
Asset Bundles
=============
Bootstrap es una completa solución front-end, que incluye CSS, JavaScript, fuentes y mucho más.
Con el fin de permitir un control más flexible sobre los componentes de Bootstrap, esta extensión proporciona
varios asset bundles.
Ellos son:
- [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] - contiene unicamente los ficheros CSS principales.
- [[yii\bootstrap4\BootstrapPluginAsset|BootstrapPluginAsset]] - depende de [[yii\bootstrap4\BootstrapAsset]], contiene ficheros javascript.
Particularmente las aplicaciones pueden necesitar requerir diferentes usos de bundle (o combinación de bundle).
Si necesitas unicamente estilos CSS, [[yii\bootstrap4\BootstrapAsset]] será suficiente para ti. Sin embargo, si
quieres usar el JavaScript de Bootstrap, necesitas registrar [[yii\bootstrap4\BootstrapPluginAsset]].
> Consejo: la mayoría de los widgets registran automaticamente [[yii\bootstrap4\BootstrapPluginAsset]].

View File

@ -0,0 +1,16 @@
Uso Básico
==========
Yii no se ajusta a los conceptos básicos de bootstrap dentro del código PHP, desde el HTML es muy simple en si mismo
en este caso. Puedes encontrar los detalles sobre el uso de los conceptos básicos en la [web de bootstrap](http://getbootstrap.com/css/). Yii proporciona una manera de incluir los assets de bootstrap en tus páginas añadiendo una única linea a `AppAsset.php` localizado en tu
directorio `@app/assets`:
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // esta linea
];
```
Usando bootstrap a través de Yii asset manager permite que minimices los recursos y combinarlos con tus propios recursos
cuando lo necesites.

View File

@ -0,0 +1,29 @@
Html helper
===========
Bootstrap introduce muchas construcciones y esqueletos consistentes de HTML, que permiten crear diferentes efectos visuales.
Unicamente lo más complejo está cubierto por los widgets proporcionados en esta extensión. El resto debería ser
compuesto manualmente usando HTML directamente.
Sin embargo, algunas marcas especiales de Bootstrap son cubiertas por el helper [[\yii\bootstrap4\Html]].
[[\yii\bootstrap4\Html]] es una versión mejorada de la regular [[\yii\helpers\Html]] dedicada a las necesidades de Bootstrap.
Proporciona varios métodos útiles:
- `icon()` - permite renderizar iconos de Glyphicon
- `staticControl()` - permite renderizar formularios "static controls"
[[\yii\bootstrap4\Html]] hereda todas las funcionalidades disponibles en [[\yii\helpers\Html]] y puede usarse como sustituto,
así que no es necesario incluir ambos dentro de los archivos de tus vistas.
Por ejemplo:
```php
<?php
use yii\bootstrap4\Html;
?>
<?= Button::widget([
'label' => Html::icon('approve') . Html::encode('Save & apply'),
'encodeLabel' => false,
'options' => ['class' => 'btn-primary'],
]); ?>
```
> Atención: no confundas [[\yii\bootstrap4\Html]] con [[\yii\helpers\Html]], ten cuidado que clases estás usando dentro de tus vistas.

View File

@ -0,0 +1,20 @@
Instalación
===========
## Obteniendo el Paquete de Composer
La mejor manera para instalar esta extensión es a través de [composer](http://getcomposer.org/download/).
Ejecuta
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
o añade
```
"yiisoft/yii2-bootstrap": "~1.0.0"
```
en la sección require de tu fichero `composer.json`.

View File

@ -0,0 +1,17 @@
Usando directamente los ficheros .sass de Bootstrap
===================================================
Si deseas incluir el [css de Bootstrap directamente en tus ficheros sass](http://getbootstrap.com/getting-started/#customizing) puedes necesitar deshabilitar los ficheros css de bootstrap originales para ser cargados.
Puedes hacer esto mediante la configuración de la propiedad css de [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] asignando
un array vacio.
Para esto necesitas configurar el `assetManager` [componente de aplicación](https://github.com/yiisoft/yii2/blob/master/docs/guide-es/structure-application-components.md) como se muestra a continuación:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [],
]
]
]
```

View File

@ -0,0 +1,62 @@
Yii widgets
===========
La mayoría de los componentes de bootstrap están encapsulados dentro de Yii widgets lo que permite una sintaxis
más robusta y poder integrarse con las características del framework. Todos los widgets pertenecen
al namespace `\yii\bootstrap4`:
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]
## Personalización de las clases css para los widget <span id="customizing-css-classes"></span>
Los widgets permiten una rápida composición del HTML para los componentes de bootstrap que requieren las clases
CSS de bootstrap.
Las clases por defecto para un componente en particular serán añadidas automáticamente por los widgets, y las clases
opcionales que quieres personalizar son frecuentemente soportadas a través de las propiedades de los widgets.
Por ejemplo, puedas usar [[yii\bootstrap4\Button::options]] para personalizar la apariencia de un botón.
La clase 'btn' que se requiere para un botón será añadida automáticamente, por lo que no necesitas preocuparte
por ello.
Todo lo que necesitas es especificar una clase de botón en particular:
```php
echo Button::widget([
'label' => 'Action',
'options' => ['class' => 'btn-primary'], // produce la clase "btn btn-primary"
]);
```
Sin embargo, a veces puede que tengas que remplazar las clases por defecto por las alternativas.
Por ejemplo, el widget [[yii\bootstrap4\ButtonGroup]] utiliza por defecto la clase 'btn-group' para el contenido del div, pero necesitas usar 'btn-group-vertical' en lugar de alinear los botones verticalmente.
El uso directo de la opción 'class' simplemente añade 'btn-group-vertical' a 'btn-group, el cual producirá un resultado incorrecto.
Con el fin de sobrescribir las clases por defecto de un widget, necesitas especificar la opción 'class' como un
array que contiene la definición de la clase personalizada bajo la clave 'widget':
```php
echo ButtonGroup::widget([
'options' => [
'class' => ['widget' => 'btn-group-vertical'] // remplaza 'btn-group' con 'btn-group-vertical'
],
'buttons' => [
['label' => 'A'],
['label' => 'B'],
]
]);
```

31
docs/guide-ja/README.md Normal file
View File

@ -0,0 +1,31 @@
Yii 2 Twitter Bootstrap エクステンション
========================================
このエクステンションは、マークアップとコンポーネントのフレームワーク [Bootstrap 4](http://getbootstrap.com/) ("Twitter Bootstrap" としても知られています)
に対するサポートを提供します。
Bootstrap は優れた、レスポンシブなフレームワークであり、クライアント・サイドの開発プロセスを大いにスピードアップすることが出来るものです。
Bootstrap のコアは二つの部分によって表されます。
- CSS の基礎。例えば、グリッド・レイアウト・システム、タイポグラフィ、ヘルパ・クラス、レスポンシブ・ユーティリティなど。
- そのまま使えるコンポーネント。フォーム、メニュー、ページネーション、モーダル・ボックス、タブなど。
始めよう
--------
* [インストール](installation.md)
* [アセットのセットアップ](assets-setup.md)
* [基本的な使用方法](basic-usage.md)
使用方法
--------
* [Yii ウィジェット](usage-widgets.md)
* [Html ヘルパ](helper-html.md)
* [アセット・バンドル](asset-bundles.md)
追加のトピック
--------------
* [Bootstrap の .sass ファイルを直接に使う](topics-sass.md)
* [yii2-bootstrap からの移行](migrating-yii2-bootstrap.md)

View File

@ -0,0 +1,16 @@
アセット・バンドル
==================
Bootstrap は、CSS、JavaScript、フォントなどを含む複雑なフロントエンド・ソリューションです。
Bootstrap コンポーネントに対する最大限の柔軟な制御を可能にするために、このエクステンションは複数のアセット・バンドルを提供しています。
すなわち、
- [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] - メインの CSS ファイルのみを含みます。
- [[yii\bootstrap4\BootstrapPluginAsset|BootstrapPluginAsset]] - [[yii\bootstrap4\BootstrapAsset]] に依存し、javascript ファイルを含みます。
個々のアプリケーションは、その要求に応じて、異なるバンドル (またはバンドルの組み合わせ) を必要とするでしょう。
CSS のスタイルだけが必要なのであれば、[[yii\bootstrap4\BootstrapAsset]] だけで十分です。
しかし、Bootstrap の JavaScript を必要とする場合は、[[yii\bootstrap4\BootstrapPluginAsset]]
をも登録しなければなりません。
> Tip: ほとんどのウィジェットは [[yii\bootstrap4\BootstrapPluginAsset]] を自動的に登録します。

View File

@ -0,0 +1,176 @@
アセットのセットアップ
======================
Bootstrap エクステンションは、アセットのインストールについて、[Bower](http://bower.io/) および/または [NPM](https://www.npmjs.org/) のパッケージに依存しています。
Bootstrap パッケージを使う前に、これらのパッケージをあなたのプロジェクトにインストールする方法を決定しなければなりません。
## asset-packagist レポジトリを使う
[asset-packagist.org](https://asset-packagist.org) を Bootstrap アセットのソース・パッケージとしてセットアップすることが出来ます。
あなたのプロジェクトの `composer.json` に下記の行を追加して下さい。
```json
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
```
そして、アプリケーション構成で `@npm``@bower` を設定します。
```php
return [
//...
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
//...
];
```
## composer アセット・プラグインを使う
次のコマンドを使って [composer アセット・プラグイン](https://github.com/francoispluchino/composer-asset-plugin/) をグローバルにインストールします。
```
composer global require "fxp/composer-asset-plugin:^1.4.0"
```
Yii を使ってアセットを発行したい場合は、あなたのプロジェクトの `composer.json` に下記の行を追加して、
インストールされるパッケージが置かれるディレクトリを設定します。
```json
"extra": {
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
```
これで、`composer install/update` コマンドを実行すると、Bootstrap のアセットを取得することが可能になります。
> Note: `fxp/composer-asset-plugin` は asset-packagist に比べると、`composer update`
コマンドを著しく遅くさせます。
## Bower/NPM クライアントを直接に使う
Bower または NPM のクライアントを直接に使って Bootstrap のアセットをインストールすることが出来ます。
あなたのプロジェクトの `package.json` に次の行を追加して下さい。
```json
{
...
"dependencies": {
"bootstrap": "4.2.1",
...
}
...
}
```
あなたのプロジェクトの `package.json` に次の行を追加して、Bootstrap アセットの冗長なインストールを防止します。
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
## CDN を使う
[公式 CDN](https://www.bootstrapcdn.com) から Bootstrap アセットを使うことが出来ます。.
あなたのプロジェクトの `package.json` に次の行を追加して、Bootstrap アセットの冗長なインストールを防止します。
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
'assetManager' アプリケーション・コンポーネントを構成して、Bootstrap アセット・バンドルを CDN のリンクでオーバーライドします。
```php
return [
'components' => [
'assetManager' => [
// CDN を使うようにバンドルをオーバーライド
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'sourcePath' => null,
'baseUrl' => 'https://stackpath.bootstrapcdn.com/bootstrap/4.2.1',
'css' => [
'css/bootstrap.min.css'
],
],
'yii\bootstrap4\BootstrapPluginAsset' => [
'sourcePath' => null,
'baseUrl' => 'https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1',
'js' => [
'js/bootstrap.bundle.min.js'
],
],
],
],
// ...
],
// ...
];
```
## .sass ファイルからコンパイルする
Bootstrap CSS ソースを直接にカスタマイズしたい場合、ソースの *.sass ファイルから CSS をコンパイルしたいと思うことがあるでしょう。
そのような場合は、Bootstrap アセットを Composer や Bower/NPM からインストールしても意味がありません。
なぜなら、`vendor` ディレクトリ内のファイルは変更できないからです。
Bootstrap アセットを手作業でダウンロードし、プロジェクト・ソース・コード内のどこか、
例えば `assets/source/bootstrap` フォルダに置かなければなりません。
あなたのプロジェクトの `package.json` に次の行を追加して、Bootstrap アセットの冗長なインストールを防止します。
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
'assetManager' アプリケーション・コンポーネントを構成して、Bootstrap アセット・バンドルをオーバーライドします。
```php
return [
'components' => [
'assetManager' => [
// バンドルをオーバーライドし、ローカル・プロジェクト・ファイルを使う
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'sourcePath' => '@app/assets/source/bootstrap/dist',
'css' => [
YII_ENV_DEV ? 'css/bootstrap.css' : 'css/bootstrap.min.css',
],
],
'yii\bootstrap4\BootstrapPluginAsset' => [
'sourcePath' => '@app/assets/source/bootstrap/dist',
'js' => [
YII_ENV_DEV ? 'js/bootstrap.js' : 'js/bootstrap.min.js',
]
],
],
],
// ...
],
// ...
];
```
Bootsrap のソース・ファイルを変更した後は、例えば `npm run dist` を使って、必ず[コンパイル](https://getbootstrap.com/docs/4.1/getting-started/build-tools/)して下さい。

View File

@ -0,0 +1,17 @@
基本的な使用方法
================
Yii は bootstrap の基礎を PHP コードでラップすることをしていません。なぜなら、この場合の HTML コードがそれ自体として非常にシンプルだからです。
bootstrap の基礎を使用することに関する詳細は、[bootstrap ドキュメント・ウェブ・サイト](http://getbootstrap.com/css/) で見ることが出来ます。
それでも、Yii はあなたのページに bootstrap のアセットをインクルードするための便利な方法を提供しています。
`@app/assets` ディレクトリに配置されている `AppAsset.php` に一行を加えるだけで大丈夫です。
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // この行です
];
```
Yii のアセットマネージャによって bootstrap を使うと、必要に応じて、bootstrap のリソースを最小化したり、
あなた自身のリソースと結合したりすることが出来ます。

View File

@ -0,0 +1,30 @@
Html ヘルパ
===========
Bootstrap は、一貫性の高い多数の HTML 構文ないしはスケルトンを導入して、さまざまな視覚的効果の生成を可能にしています。
このエクステンションによって提供されるウィジェットがカバーしているのは、その中の最も複雑なものだけです。
残りのものは、直接に HTML 構文を使って、手作業で構築しなければなりません。
ただし、いくつかの特別な Bootstrap マークアップについては、[[\yii\bootstrap4\Html]] によってカバーされています。
[[\yii\bootstrap4\Html]] は通常の [[\yii\helpers\Html]] の拡張版であり、Bootstrap の要求に特化して、
いくつかの便利なメソッドを提供するものです。例えば、
- `staticControl()` - フォームの "[static controls](https://getbootstrap.com/docs/4.1/components/forms/#readonly-plain-text)" のレンダリングを可能にする
[[\yii\bootstrap4\Html]] は [[\yii\helpers\Html]] を継承しており、
その代替物として使うことが出来ますので、ビュー・ファイルの中で両方を使う必要はありません。
例えば、
```php
<?php
use yii\bootstrap4\Html;
?>
<?= Button::widget([
'label' => Html::icon('approve') . Html::encode('Save & apply'),
'encodeLabel' => false,
'options' => ['class' => 'btn-primary'],
]); ?>
```
> 注意: [[\yii\bootstrap4\Html]] と [[\yii\helpers\Html]] を混同してはいけません。
ビューの中でどちらのクラスを使っているのかに注意してください。

View File

@ -0,0 +1,19 @@
インストール
============
## Composer パッケージを取得する
このエクステンションをインストールするのに推奨される方法は [composer](http://getcomposer.org/download/) によるものです。
下記のコマンドを実行してください。
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
または、あなたの `composer.json` ファイルの `require` セクションに、
```
"yiisoft/yii2-bootstrap": "~1.0.0"
```
を追加してください。

View File

@ -0,0 +1,107 @@
yii2-bootstrap からの移行
=========================
yii2-bootstrap4 は、Bootstrap 3 から Bootstrap 4 への移行ガイドに従って、yii-bootstrap プロジェクト全体を大きく書き換えたものです。
最も注目すべき変更点を要約すると以下の通りです。
## 一般
* 名前空間は `yii\bootstrap` から `yii\bootstrap4` に変更
* `bower` ではなく `npm` パッケージを使用
* テーマ・アセットは廃止
* `popper.js` は不要になった (bootstrap js バンドルによって供給される)
## ウィジェット / クラス
* [[yii\bootstrap\Collapse|Collapse]] の名前は [[yii\bootstrap4\Accordion|Accordion]] に変更
* [[yii\bootstrap\BootstrapThemeAsset|BootstrapThemeAsset]] は廃止
* [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]] を追加 ([[yii\widgets\Breadcrumbs]] の Bootstrap 4 による実装)
* [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]] を追加 (https://getbootstrap.com/docs/4.3/components/button-group/#button-toolbar)
### BaseHtml
`icon` メソッドは削除されました。グリフアイコンがもうバンドルされておらず、このメソッドが無意味になったためです。
代りに、[Font Awesome Widget](https://github.com/rmrevin/yii2-fontawesome) または
[Font Awesome Inline Widget](https://github.com/YiiRocks/yii2-fontawesome-inline) を使うことを検討して下さい。
### ActiveField
以下のプロパティの名前が変りました。
* `$checkboxTemplate``$checkTemplate` に変更。
* `$horizontalCheckboxTemplate``$checkHorizontalTemplate` に変更。
* `$horizontalRadioTemplate``$radioHorizontalTemplate` に変更。
プロパティ `$inlineCheckboxListTemplate` および `$inlineRadioListTemplate` は削除されました。`$checkEnclosedTemplate` と呼ばれる新しいテンプレートが追加されています。
bootstrap 4 では、チェックボックスはラベルに包まれないのがデフォルトになりました。
### ActiveForm
新しい定数 [[yii\bootstrap4\ActiveForm::LAYOUT_DEFAULT]]、[[yii\bootstrap4\ActiveForm::LAYOUT_HORIZONTAL]]
および [[yii\bootstrap4\ActiveForm::LAYOUT_INLINE]] が追加されました。
これらによって、レイアウトの選択が容易になり、文字列がいつ何時変っても、リファクタリングが安全に出来るようになることが期待されます。
### Breadcrumbs
このクラスは bootstrap の要求を満たす正しいクラスと属性でパンくずリストをレンダリングするために導入されました。
これは [[yii\widgets\Breadcrumbs]] と完全に互換です。
### ButtonDropdown
`$direction` という新しいプロパティが導入され、メニューを開く方向を選ぶ(例えばボタンの右側に開く)ことが可能になりました。
方向の選択をより容易にするために、[[yii\bootstrap4\ButtonDropdown::DIRECTION_DOWN]]、[[yii\bootstrap4\ButtonDropdown::DIRECTION_LEFT]]、
[[yii\bootstrap4\ButtonDropdown::DIRECTION_RIGHT]] そして
[[yii\bootstrap4\ButtonDropdown::DIRECTION_UP]] という定数が導入されました。
`$renderContainer` という新しいプロパティもあります。これが `false` に設定されると、ドロップダウンを包む div は描画されません。
次のプロパティは名前が変更されました。
* `$containerOptions``$options` に変更。
* `$options` はe `$buttonOptions` に変更。
### ButtonToolbar
この新しいクラスを使うとボタン・ツールバーを描画することが出来ます。
詳細は https://getbootstrap.com/docs/4.3/components/button-group/#button-toolbar を参照して下さい。
### Carousel
スライド間のアニメーションを制御する `$crossfade` というプロパティが導入されました。
これが `true` に設定されると、スライド・アニメーションの代りにクロスフェイド・アニメーションが実行されます。
### LinkPager
この新しいクラスは [[yii\widgets\LinkPager]] のブートストラップ・バージョンです。
詳細は https://getbootstrap.com/docs/4.3/components/pagination/ を参照して下さい。
### Modal
次のプロパティの名前が変りました。
* `$header``$title` に変更。
* `$headerOptions``$titleOptions` に変更。
もう `<h2 class="modal-title></h2>` と書く必要はありません。自動的にそのようにレンダリングされます。
### Nav
`$dropdDownCaret` プロパティは削除されました。キャレットは (S)CSS によってのみ制御可能となりました。
https://getbootstrap.com/docs/4.3/getting-started/theming/#sass-options を参照して下さい。
### NavBar
次のプロパティの名前が変りました。
* `$containerOptions``$collapseOptions` に変更。
`$headerContent` プロパティは削除されました。NavBar のヘッダはもう有りません。
トグラーがカスタマイズ可能になり、プロパティ `$togglerContent` および `$togglerOptions` が導入されました。
### Tabs
プロパティ `$panes` が導入されました。これによって、ペインの内容を `$items[0]['content']` ではなく、独立したプロパティによって定義することが出来るようになりました。
ペインの配列のインデックスがアイテムのインデックスに対応します。
例えば、`$items[0]` は `$panes[0]` に属します。
### ToggleButtonGroup
新しい定数 [[yii\bootstrap4\ToggleButtonGroup::TYPE_CHECKBOX]] および
[[yii\bootstrap4\ToggleButtonGroup::TYPE_RADIO]] が導入され、選択がより容易になり、
いつ文字列が変ってもリファクタリングがより安全に出来るようになりました。

View File

@ -0,0 +1,17 @@
Bootstrap の .sass ファイルを直接に使う
=======================================
あなたが [Bootstrap CSS をあなたの sass ファイルに直接含める](http://getbootstrap.com/getting-started/#customizing) ことを望む場合は、
オリジナルの CSS ファイルがロードされないように無効化する必要があります。
[[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] の `css` プロパティを空に設定することによって、そうすることが出来ます。
そのためには、`assetManager` [アプリケーション・コンポーネント](https://github.com/yiisoft/yii2/blob/master/docs/guide-ja/structure-application-components.md) を以下のように構成します。
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [],
]
]
]
```

View File

@ -0,0 +1,91 @@
Yii ウィジェット
================
複雑な bootstrap コンポーネントのほとんどは Yii ウィジェットでラップされて、より堅牢な構文を与えられ、フレームワークの諸機能と統合されています。
全てのウィジェットは `\yii\bootstrap4` 名前空間に属します。
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]
## ウィジェットの CSS クラスをカスタマイズする <span id="customizing-css-classes"></span>
これらのウィジェットを使うと、bootstrap CSS クラスの使用を要求する bootstrap コンポーネントのための HTML を素速く構成することが出来ます。特定のコンポーネントのデフォルトの CSS クラスはウィジェットによって自動的に追加されます。
そして、あなたがカスタマイズしたいであろうオプションの CSS クラスは、通常は、ウィジェットのプロパティによってサポートされています。
例えば、[[yii\bootstrap4\Button::options]] を使って、ボタンの外見をカスタマイズすることが出来ます。
このとき、ボタンに要求される 'btn' クラスは自動的に追加されますので、あなたが心配をする必要はありません。
特定のボタン・クラスを指定するだけで十分です。
```php
echo Button::widget([
'label' => 'Action',
'options' => ['class' => 'btn-primary'], // "btn btn-primary" というクラスを生成
]);
```
しかしながら、時として、デフォルトのクラスを別のクラスで置き換える必要がある場合があります。
例えば、[[yii\bootstrap4\ButtonGroup]] は、コンテナの div に 'btn-group' をデフォルトで使用しますが、
ボタンを垂直に並べるために 'btn-group-vertical' を代りに使いたいことがあるでしょう。
単純に 'class' オプションを使うと、'btn-group-vertical' が 'btn-group' に追加されるだけで、正しくない結果が生成されることになります。
ウィジェットのデフォルトのクラスをオーバーライドするためには、'class' オプションに配列形式を使用して、'widget' キーの下にカスタマイズしたクラスの定義を指定しなければなりません。
```php
echo ButtonGroup::widget([
'options' => [
'class' => ['widget' => 'btn-group-vertical'] // 'btn-group' を 'btn-group-vertical' で置き換え
],
'buttons' => [
['label' => 'A'],
['label' => 'B'],
]
]);
```
## Navbar ウィジェット <span id="navbar-widget"></span>
Navbar ウィジェットには独特の癖があります。あなたは Navbar が折り畳まれるブレークポイントと
Navbar の全体的なスタイル (カラー・スキーム) を指定しなければなりません。
カラー・スキームと折り畳みのブレークポイントは CSS のクラスで変更することが出来ます。指定されない場合は、カラー・スキームは `navbar-light bg-light`
ブレークポイントは`navbar-expand-lg` がデフォルトとして採用されます。詳細な情報は、[Bootstrap documentation](https://getbootstrap.com/docs/4.2/components/navbar/) を参照して下さい。
```php
Navbar::begin([
'options' => [
'class' => ['navbar-dark', 'bg-dark', 'navbar-expand-md']
]
]);
[...]
Navbar::end();
```
モバイル向けナビゲーションでブランド (アイコン) とトグル・ボタンの位置を入れ替えたい場合は、次のようにすることが出来ます。
```php
Navbar::begin([
'brandOptions' => [
'class' => ['order-1']
],
'togglerOptions' => [
'class' => ['order-0']
]
]);
[...]
Navbar::end();
```

View File

@ -0,0 +1,29 @@
Extenção Twitter Bootstrap para Yii 2
=====================================
A extensão inclui suporte para marcação e componentes ao framework [Bootstrap 4](http://getbootstrap.com/)
(também conhecido como "Bootstrap Twitter"). Bootstrap é um excelente framework ágil, que pode acelerar bastante o
do lado do cliente do seu processo de desenvolvimento.
O núcleo do bootstrap é representado por duas partes:
- Noções básicas de estilo CSS, tais como um sistema de rede layout, tipografia, classes auxiliares, e os utilitários de resposta.
- Componentes prontos para usar, tais como formulários, menus, paginação, caixas de modais, guias, etc.
Iniciando
---------------
* [Instalação](installation.md)
* [uso Básico](basic-usage.md)
Uso
-----
* [Yii widgets](usage-widgets.md)
* [Html helper](helper-html.md)
* [Asset Bundles](asset-bundles.md)
Tópicos Adicionais
-----------------
* [Usando arquivos .sass do Bootstrap diretamente](topics-sass.md)

View File

@ -0,0 +1,14 @@
Asset Bundles
=============
Bootstrap é uma solução complexa para front-end, o qual inclue CSS, JavaScript, fontes e assim por diante.
A fim de permitir que você tenha controle mais flexível sobre componentes Bootstrap , esta extensão fornece vários asset bundles. Eles são:
- [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] - Contém apenas arquivos CSS.
- [[yii\bootstrap4\BootstrapPluginAsset|BootstrapPluginAsset]] - Depende de [[yii\bootstrap4\BootstrapAsset]], contem os arquivos JavaScript.
Necessidades de aplicações específicas podem exigir utilização de pacotes diferentes ( ou a combinação bundle).
Se você precisa apenas de estilos CSS, [[yii\bootstrap4\BootstrapAsset]] será o suficiente para você. No entanto , se
você quiser usar Bootstrap JavaScript, você precisa se registrar [[yii\bootstrap4\BootstrapPluginAsset]].
> Tip: a maioria dos widgets [[yii\bootstrap4\BootstrapPluginAsset]] registram automaticamente.

View File

@ -0,0 +1,17 @@
Uso Básico
===========
O Yii Não registra os componentes básicos do bootstrap em código PHP visto que esse HTML é muito simples, por si só.
Você pode encontrar detalhes sobre como usar o básico no [site documentação do Bootstrap] (http://getbootstrap.com/css/). O Yii ainda fornece uma
forma conveniente para incluir assets de bootstrap em suas páginas com uma única linha adicionado ao arquivo `AppAsset.php` localizado no seu
diretório `@app/assets`:
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // this line
];
```
Usando bootstrap através Yii assets lhe permite minimizar os seus recursos/fontes e combinar com seus próprios recursos/fontes quando
necessário.

View File

@ -0,0 +1,18 @@
Bootstrap introduz construções HTML mais consistentes e esqueletos, que permitem a criação de diferentes efeitos visuais. Apenas o mais complexos deles são cobertos por os widgets fornecidos com esta extensão . O restante deverá ser escrito manualmente usando escrita HTML direta. No entanto, vários casos especiais de marcação Bootstrap são cobertos pelo helper [[\yii\bootstrap4\Html]]. [[\yii\bootstrap4\Html]] é uma versão melhorada de [[\yii\helpers\Html]] dedicada à quem precisa do Bootstrap. Ele fornece vários métodos úteis :
icon() - allows rendering of Glyphicon icons
staticControl() - allows rendering of form "static controls"
[[\yii\bootstrap4\Html]] herda toda funcionalidade disponível em [[\yii\helpers\Html]] e pode ser usado como um substituto , para que você não precisa de ambos dentro de seus arquivos de views . Por exemplo:
<?php
use yii\bootstrap4\Html;
?>
<?= Button::widget([
'label' => Html::icon('approve') . Html::encode('Save & apply'),
'encodeLabel' => false,
'options' => ['class' => 'btn-primary'],
]); ?>
Atenção: Não confunda [[\yii\bootstrap4\Html]] e [[\yii\helpers\Html]], tenha o cuidado de que classe você está usando dentro de seus arquivos de views.

View File

@ -0,0 +1,20 @@
Instalação
============
## Instalando através do composer
A maneira recomendada para instalar esta extensão é através do [composer](http://getcomposer.org/download/).
Então rode
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
Ou Adicione
```
"yiisoft/yii2-bootstrap": "~1.0.0"
```
na sessão de requirimentos do seu arquivo `composer.json`.

View File

@ -0,0 +1,18 @@
Usando arquivos .sass diretamente do Bootstrap
===========================================
Se você quiser incluir o [css do Bootstrap diretamente em seus arquivos sass] (http://getbootstrap.com/getting-started/#customizing)
talvez você precise desativar os arquivos css do Bootstrap originais que são carregados.
Você pode fazer isso definindo a propriedade css do [[yii \ inicialização \ BootstrapAsset | BootstrapAsset]] e deixe estar vazio.
Para isso, você precisa configurar o `assetManager` [application component](https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-application-components.md)
do seguinte modo:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [],
]
]
]
```

View File

@ -0,0 +1,23 @@
Yii widgets
===========
A maioria dos componentes complexos do bootstrap são envolvidos em widgets Yii para permitir uma sintaxe mais robusta e integrar-se com
características estruturais do framework. Todos widgets pertencem ao namespace `\yii\bootstrap4`:
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]

27
docs/guide-ru/README.md Normal file
View File

@ -0,0 +1,27 @@
Расширение Twitter Bootstrap для Yii 2
======================================
Расширение включает поддержку разметки и компонентов фреймворка [Bootstrap 4](http://getbootstrap.com/) (также известного как "Twitter Bootstrap"). Bootstrap является прекрасным, отзывчивым фреймворком, который может значительно ускорить процесс разработки на стороне клиента.
Ядро Bootstrap представлено двумя частями:
- CSS основа, такая как система разметки, типографика, вспомогательные классы, и утилиты адаптивности.
- Готовые к использованию компоненты, такие как формы, меню, нумерация страниц, модальные окна, вкладки и т.д.
Как начать
----------
* [Установка](installation.md)
* [Основы использования](basic-usage.md)
Использование
------------
* [Виджеты Yii](usage-widgets.md)
* [Класс-помощник Html](helper-html.md)
* [Asset Bundles](asset-bundles.md)
Дополнительно
-------------
* [Использование .sass файлов Bootstrap напрямую](topics-sass.md)

View File

@ -0,0 +1,11 @@
Asset Bundles
=============
Bootstrap - это комплексное front-end решение, включающее CSS, JavaScript, шрифты и т.д. Для того чтобы обеспечить гибкий контроль над компонентами Bootstrap, расширение предоставляет несколько Asset Bundles. Вот они:
- [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] - содержит CSS файлы.
- [[yii\bootstrap4\BootstrapPluginAsset|BootstrapPluginAsset]] - зависит от [[yii\bootstrap4\BootstrapAsset]], содержащий javascript файлы.
Конкретные приложения могут потребовать различного использования. Если вам нужны только CSS-стили, то пакета [[yii\bootstrap4\BootstrapAsset]] будет достаточно. Тем не менее, если вы хотите использовать Bootstrap JavaScript, вам необходимо зарегистрировать [[yii\bootstrap4\BootstrapPluginAsset]].
> Tip: большинство виджетов регистрируются с помощью [[yii\bootstrap4\BootstrapPluginAsset]] автоматически.

View File

@ -0,0 +1,13 @@
Базовое использование
===========
Yii не оборачивает базовый Bootstrap в PHP код, поскольку HTML, в этом случае, прост сам по себе. Вы можете найти подробную информацию о возможностях Bootstrap в [официальной документации](http://getbootstrap.com/css/). Тем не менее, Yii обеспечивает удобный способ включения Bootstrap assets на страницах вашего приложения добавлением одной строки в файл `AppAsset.php`, расположенный в директории `@app/assets`:
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // подключение Bootstrap
];
```
Использование загрузки Bootstrap через Yii Asset Manager позволяет минимизировать ресурсы и объединить с вашими собственными ресурсами, когда это будет необходимо.

View File

@ -0,0 +1,22 @@
Класс-помощник Html
===================
Bootstrap предоставляет множество последовательных HTML конструкции и каркасов, которые позволяют создавать различные визуальные эффекты. Только самые сложные из них передставлены виджетами, поставляемые с данным расширением. Остальные должны быть собраны вручную, используя HTML напрямую. Тем не менее, несколько специальных Bootstrap разметок предоставляются в помощнике [[\yii\bootstrap4\Html]]. [[\yii\bootstrap4\Html]] является расширенной версией [[\yii\helpers\Html]], удовлетворяющей потребности Bootstrap. Он предоставляет несколько полезных методов:
- `icon()` - позволяет отображать иконки Glyphicon
- `staticControl()` - позволяет отображать "статические элементы управления" формы
[[\yii\bootstrap4\Html]] наследует все функциональные возможности, доступные в [[\yii\helpers\Html]], и может быть использован в качестве замены в ваших представлениях. Например:
```php
<?php
use yii\bootstrap4\Html;
?>
<?= Button::widget([
'label' => Html::icon('approve') . Html::encode('Save & apply'),
'encodeLabel' => false,
'options' => ['class' => 'btn-primary'],
]); ?>
```
> Attention: не путайте [[\yii\bootstrap4\Html]] и [[\yii\helpers\Html]]! Следите за тем какой класс вы используете в своих представлениях.

View File

@ -0,0 +1,20 @@
Установка
=========
## Получение расширения через Composer
Предпочтительный способ установки расширения - через [Composer](http://getcomposer.org/download/).
Для этого запустите команду
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
или добавьте
```
"yiisoft/yii2-bootstrap": "~1.0.0"
```
в секцию **require** вашего `composer.json`.

View File

@ -0,0 +1,14 @@
Использование .sass файлов Bootstrap напрямую
=============================================
Если вы хотите включить [Bootstrap CSS непосредственно в ваши sass-файлы](http://getbootstrap.com/getting-started/#customizing), вам может понадобиться исключить исходные css-файлы Bootstrap из загрузки. Вы можете сделать это, установив пустым свойство `css` пакета [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]]. Для этого вам необходимо настроить [компонент приложения](https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-application-components.md) `assetManager` следующим образом:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [], // исключение исходных css-файлов из загрузки
]
]
]
```

View File

@ -0,0 +1,50 @@
Виджеты Yii
===========
Большинство сложных Bootstrap компонентов обернуты в виджеты Yii, чтобы обеспечить более надежный синтаксис и интеграцию с особенностями фреймворка. Все виджеты относятся к пространству имен `\yii\bootstrap4`:
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]
## Настройка CSS классов виджетов <span id="customizing-css-classes"></span>
Виджеты позволяют быстро создавать HTML Bootstrap компоненты, которые требуют CSS классы Bootstrap. Классы по умолчанию, для конкретного компонента, будут добавлены автоматически виджетом, и необязательные классы, которые вы можете настроить, как правило, поддерживаются через свойства виджета.
Например, вы можете использовать [[yii\bootstrap4\Button::options]] чтобы настроить внешний вид кнопки. Класс `btn`, который требуется для кнопки, будет добавлен автоматически. Все, что вам нужно, это указать конкретный класс кнопки:
```php
echo Button::widget([
'label' => 'Action',
'options' => ['class' => 'btn-primary'], // создаст класс "btn btn-primary"
]);
```
Тем не менее, иногда вам может понадобиться заменить классы по умолчанию альтернативными. Например, виджет [[yii\bootstrap4\ButtonGroup]] использует класс `btn-group` для контейнера `div` по умолчанию, но вам, возможно, придётся использовать `btn-group-vertical` чтобы выровнять кнопки по вертикали. Добавление `btn-group-vertical` в параметр `class` приведет к неправильному результату. Для того, чтобы переопределить классы виджета по умолчанию, необходимо указать параметр `class` как массив, содержащий определение класса, настроенное в ключе `widget`:
```php
echo ButtonGroup::widget([
'options' => [
'class' => ['widget' => 'btn-group-vertical'] // replaces 'btn-group' with 'btn-group-vertical'
],
'buttons' => [
['label' => 'A'],
['label' => 'B'],
]
]);
```

27
docs/guide-uk/README.md Normal file
View File

@ -0,0 +1,27 @@
Розширення Twitter Bootstrap для Yii 2
======================================
З коробки Yii включає підтримку розмітки [Bootstrap 4](http://getbootstrap.com/) та компонентів фреймворку
(також відомий як "Twitter Bootstrap"). Bootstrap є чудовим, адаптивним фреймворком, який може значно прискорити
процес розробки клієнтської частини сайту.
Ядро Bootstrap представлене двома частинами:
- Основи CSS, такі як система макету сітки, типографія, допоміжні класи і адаптивні утиліти.
- Готові до використання компоненти, такі як форми, меню, нумерація сторінок (pagination), модальні вікна, вкладки (tabs) і т.д.
Початок роботи
--------------
* [Встановлення](installation.md)
* [Основи використання](basic-usage.md)
Використання
------------
* [Віджети Yii](usage-widgets.md)
Додаткові теми
--------------
* [Використання .sass файлів в Bootstrap](topics-sass.md)

View File

@ -0,0 +1,16 @@
Основи використання
===================
Yii не загортає основи bootstrap в код PHP, оскільки в цьому випадку, сам по собі HTML є дуже простим.
Ви можете знайти детальну інформацію щодо використання основ на [сайті документації bootstrap](http://getbootstrap.com/css/).
Проте Yii забезпечує зручний спосіб підключення ресурсів bootstrap до ваших сторінок за допомогою додання всього одного рядка до файлу
`AppAsset.php`, розташованого в каталозі `@app/assets`:
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // цей рядок
];
```
Використання bootstrap через менеджер ресурсів Yii дозволяє мінімізувати свої ресурси і обʼєднати із вашими власними ресурсами коли це необхідно.

View File

@ -0,0 +1,20 @@
Встановлення
============
## Отримання пакету Composer
Кращим способом для встановлення даного розширення є встановлення через [composer](http://getcomposer.org/download/).
Запустіть
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
або додайте
```
"yiisoft/yii2-bootstrap": "~1.0.0"
```
до потрібного розділу вашого файлу `composer.json`.

View File

@ -0,0 +1,18 @@
Використання .sass файлів в Bootstrap
=====================================
Якщо ви хочете включити [CSS Bootstrap напряму до ваших sass файлів](http://getbootstrap.com/getting-started/#customizing)
вам необхідно відключити завантаження оригінальних css файлів bootstrap.
Ви можете зробити це, встановивши CSS властивість [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] порожньою.
Для цього вам необхідно налаштувати [компонент додатка](https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-application-components.md)
`assetManager` наступним чином:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [],
]
]
]
```

View File

@ -0,0 +1,23 @@
Віджети Yii
===========
Найбільш складні компоненти bootstrap загорнуті в віджети Yii, щоб забезпечити більш надійний синтаксис
та інтегрувати його з можливостями фреймворку. Всі віджети належать до простору імен `\yii\bootstrap4`:
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]

View File

@ -0,0 +1,29 @@
基于Yii 2 的 Twitter Bootstrap 扩展
=====================================
扩展包括对 [Bootstrap 3](http://getbootstrap.com/) 标记和组件框架的支持
也称为“Twitter Bootstrap”。 Bootstrap是一个优秀的响应式框架可以大大加快
客户端的开发过程。
Bootstrap的核心由两部分组成
- 基础CSS样式如栅格化布局排版帮助类和响应式工具。
- 开箱即用的组件,如表单,菜单,分页,模态框,标签等。
起步
---------------
* [安装](installation.md)
* [基本用法](basic-usage.md)
使用
-----
* [Yii 小部件](usage-widgets.md)
* [Html 助手](helper-html.md)
* [Asset Bundles资源包](asset-bundles.md)
其他
-----------------
* [直接使用Bootstrap的.sass文件](topics-sass.md)

View File

@ -0,0 +1,14 @@
资源包
=============
Bootstrap是一个复杂的前端解决方案其中包括 CSS JavaScript ,字体等。
为了灵活的控制 Bootstrap 组件,此扩展提供了多个资源包。
如下:
- [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] - 只包含主要的 CSS 文件.
- [[yii\bootstrap4\BootstrapPluginAsset|BootstrapPluginAsset]] - 包含 javascript 文件, 依赖于 [[yii\bootstrap4\BootstrapAsset]] .
特定的应用可能需要加载不同的资源包,(或者资源包组合).
如果只需要 CSS 文件, 引入 [[yii\bootstrap4\BootstrapAsset]] 即可. 但是, 如果需要使用 Bootstrap 的 JavaScript, 则需要引入 [[yii\bootstrap4\BootstrapPluginAsset]].
> 提示:大多数小部件会自动注册到 [[yii\bootstrap4\BootstrapPluginAsset]] 。

View File

@ -0,0 +1,13 @@
使用
===========
Yii不会将 bootstrap 合并到PHP代码中因为HTML本身是非常简单的。猛击 [bootstrap 文档页](http://getbootstrap.com/css/) 查看如何使用 bootstrap. 但是 Yii 还是提供了在框架中更为方便的管理和使用 bootstrap的方式`@app/assets` 路径下的 `AppAsset.php` 文件中,添加如下代码即可:
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // this line
];
```
通过 Yii 的资源管理器asset manager引入 bootstrap ,可最小化的引入 bootstrap 并在需要时合并自定义资源文件一起使用。

View File

@ -0,0 +1,27 @@
Html 助手
===========
Bootstrap 引入了许多一致的 HTML 结构和骨架,允许创建不同的视觉效果。
只有最复杂的部分由此扩展提供的小部件覆盖。 其余应使用直接 HTML 手动组合。
但是, 有些特殊的 Bootstrap 标签被 [[\yii\bootstrap4\Html]] 重载.
[[\yii\bootstrap4\Html]] 是基于 Bootstrap 的 [[\yii\helpers\Html]] 增强版.
它提供了很多实用的方法,例如:
- `icon()` - 生成Glyphicon图标
- `staticControl()` - 生成表单静态组件 "static controls"
[[\yii\bootstrap4\Html]] 继承了 [[\yii\helpers\Html]] 的所有功能,所以不需要在视图文件中同时引入这两个文件,如果需要,仅使用 [[\yii\bootstrap4\Html]] 即可.
例如:
```php
<?php
use yii\bootstrap4\Html;
?>
<?= Button::widget([
'label' => Html::icon('approve') . Html::encode('Save & apply'),
'encodeLabel' => false,
'options' => ['class' => 'btn-primary'],
]); ?>
```
> 注意: 不要混淆 [[\yii\bootstrap4\Html]] 和 [[\yii\helpers\Html]], 一定注意你在视图中引入和使用的类.

View File

@ -0,0 +1,18 @@
安装
============
## 获取 Composer 包
安装此扩展的首选方式是通过 [composer](http://getcomposer.org/download/).
直接运行
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
或者在项目目录的 `composer.json` 文件中添加如下代码
```
"yiisoft/yii2-bootstrap": "~1.0.0"
```

View File

@ -0,0 +1,17 @@
直接使用Bootstrap的.sass文件
=======================================
如果引入 [直接使用Bootstrap的.sass文件](http://getbootstrap.com/getting-started/#customizing)
则需要禁用原始加载的 css 文件.
通过设置 [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] 的 css 属性为空即可.
为此,需要配置 `assetManager` [应用组件](https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-application-components.md) 为如下:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [],
]
]
]
```

View File

@ -0,0 +1,54 @@
Yii 小部件
===========
大多数复杂的 bootstrap 组件被包装到 Yii 小部件中,以允许更强大的语法并与框架特性集成。 所有小部件都在命名空间 `\yii\bootstrap4` 下:
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]
## 自定义小部件CSS类 <span id="customizing-css-classes"></span>
这些小部件可以快速构建基于 bootstrap CSS 样式的 bootstrap 组件,并直接生成 HTML 代码。
特定组件的默认样式是自动添加的,也可以通过修改部件属性添加自定义样式类。
例如, 使用 [[yii\bootstrap4\Button::options]] 创建按钮。
按钮中的 `btn` 样式将会被自动添加。只要再添加自己所需的按钮样式即可:
```php
echo Button::widget([
'label' => 'Action',
'options' => ['class' => 'btn-primary'], // produces class "btn btn-primary"
]);
```
但是,有的时候需要将默认样式替换为自定义样式。
例如, 小部件 [[yii\bootstrap4\ButtonGroup]] 默认使用 'btn-group' 类作为 div 容器的默认样式,但是我们希望使用 'btn-group-vertical' 作为默认样式以实现按钮组的垂直居中。
直接在 'class' 选项中添加 'btn-group-vertical' 是替换不了 'btn-group' 的。
为了重载组件的默认样式,需要在 'class' 选项中的 'widget' 选项中定义即可:
```php
echo ButtonGroup::widget([
'options' => [
'class' => ['widget' => 'btn-group-vertical'] // replaces 'btn-group' with 'btn-group-vertical'
],
'buttons' => [
['label' => 'A'],
['label' => 'B'],
]
]);
```

31
docs/guide/README.md Normal file
View File

@ -0,0 +1,31 @@
Twitter Bootstrap Extension for Yii 2
=====================================
The extension includes support for the [Bootstrap 5](http://getbootstrap.com/) markup and components framework
(also known as "Twitter Bootstrap"). Bootstrap is an excellent, responsive framework that can greatly speed up the
client-side of your development process.
The core of Bootstrap is represented by two parts:
- CSS basics, such as a grid layout system, typography, helper classes, and responsive utilities.
- Ready to use components, such as forms, menus, pagination, modal boxes, tabs etc.
Getting Started
---------------
* [Installation](installation.md)
* [Assets Setup](assets-setup.md)
* [Basic Usage](basic-usage.md)
Usage
-----
* [Yii widgets](usage-widgets.md)
* [Html helper](helper-html.md)
* [Asset Bundles](asset-bundles.md)
Additional topics
-----------------
* [Using the .sass files of Bootstrap directly](topics-sass.md)
* [Migrating from yii2-bootstrap](migrating-yii2-bootstrap.md)

View File

@ -0,0 +1,16 @@
Asset Bundles
=============
Bootstrap is a complex front-end solution, which includes CSS, JavaScript, fonts and so on.
In order to allow you the most flexible control over Bootstrap components, this extension provides several asset bundles.
They are:
- [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] - contains only the main CSS files.
- [[yii\bootstrap4\BootstrapPluginAsset|BootstrapPluginAsset]] - depends on [[yii\bootstrap4\BootstrapAsset]], contains the javascript files.
Particular application needs may require different bundle (or bundle combination) usage.
If you only need CSS styles, [[yii\bootstrap4\BootstrapAsset]] will be enough for you. However, if
you intend to use Bootstrap JavaScript, you will need to register [[yii\bootstrap4\BootstrapPluginAsset]]
as well.
> Tip: most of the widgets register [[yii\bootstrap4\BootstrapPluginAsset]] automatically.

176
docs/guide/assets-setup.md Normal file
View File

@ -0,0 +1,176 @@
Assets Setup
============
This extensions relies on [Bower](http://bower.io/) and/or [NPM](https://www.npmjs.org/) packages for the asset installation.
Before using this package you should decide in which way you will install those packages in your project.
## Using asset-packagist repository
You can setup [asset-packagist.org](https://asset-packagist.org) as package source for the Bootstrap assets.
In the `composer.json` of your project, add the following lines:
```json
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
```
Adjust `@npm` and `@bower` in you application configuration:
```php
return [
//...
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
//...
];
```
## Using composer asset plugin
Install [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/) globally, using following command:
```
composer global require "fxp/composer-asset-plugin:^1.4.0"
```
Add the following lines to `composer.json` of your project to adjust directories where the installed packages
will be placed, if you want to publish them using Yii:
```json
"extra": {
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
```
Then you can run composer install/update command to pick up Bootstrap assets.
> Note: `fxp/composer-asset-plugin` significantly slows down the `composer update` command in comparison
to asset-packagist.
## Using Bower/NPM client directly
You can install Bootstrap assets directly via Bower or NPM client.
In the `package.json` of your project, add the following lines:
```json
{
...
"dependencies": {
"bootstrap": "4.2.1",
...
}
...
}
```
In the `composer.json` of your project, add the following lines in order to prevent redundant Bootstrap asset installation:
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
## Using CDN
You may use Bootstrap assets from [official CDN](https://www.bootstrapcdn.com).
In the `composer.json` of your project, add the following lines in order to prevent redundant Bootstrap asset installation:
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
Configure 'assetManager' application component, overriding Bootstrap asset bundles with CDN links:
```php
return [
'components' => [
'assetManager' => [
// override bundles to use CDN :
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'sourcePath' => null,
'baseUrl' => 'https://stackpath.bootstrapcdn.com/bootstrap/4.2.1',
'css' => [
'css/bootstrap.min.css'
],
],
'yii\bootstrap4\BootstrapPluginAsset' => [
'sourcePath' => null,
'baseUrl' => 'https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1',
'js' => [
'js/bootstrap.bundle.min.js'
],
],
],
],
// ...
],
// ...
];
```
## Compiling from the .sass files
If you want to customize the Bootstrap CSS source directly, you may want to compile it from source *.sass files.
In such case installing Bootstrap assets from Composer or Bower/NPM makes no sense, since you can not modify files
inside 'vendor' directory.
You'll have to download Bootstrap assets manually and place them somewhere inside your project source code,
for example in the 'assets/source/bootstrap' folder.
In the `composer.json` of your project, add the following lines in order to prevent redundant Bootstrap asset installation:
```json
"replace": {
"npm-asset/bootstrap": ">=4.2.1"
},
```
Configure 'assetManager' application component, overriding Bootstrap asset bundles:
```php
return [
'components' => [
'assetManager' => [
// override bundles to use local project files :
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'sourcePath' => '@app/assets/source/bootstrap/dist',
'css' => [
YII_ENV_DEV ? 'css/bootstrap.css' : 'css/bootstrap.min.css',
],
],
'yii\bootstrap4\BootstrapPluginAsset' => [
'sourcePath' => '@app/assets/source/bootstrap/dist',
'js' => [
YII_ENV_DEV ? 'js/bootstrap.js' : 'js/bootstrap.min.js',
]
],
],
],
// ...
],
// ...
];
```
After you make changes to Bootstrap's source files, make sure to [compile them](https://getbootstrap.com/docs/4.1/getting-started/build-tools/), eg. using `npm run dist`.

17
docs/guide/basic-usage.md Normal file
View File

@ -0,0 +1,17 @@
Basic Usage
===========
Yii doesn't wrap the bootstrap basics into PHP code since HTML is very simple by itself in this case. You can find details
about using the basics at [bootstrap documentation website](http://getbootstrap.com/css/). Still Yii provides a
convenient way to include bootstrap assets in your pages with a single line added to `AppAsset.php` located in your
`@app/assets` directory:
```php
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap4\BootstrapAsset', // this line
];
```
Using bootstrap through Yii asset manager allows you to minimize its resources and combine with your own resources when
needed.

30
docs/guide/helper-html.md Normal file
View File

@ -0,0 +1,30 @@
Html helper
===========
Bootstrap introduces many consistent HTML constructions and skeletons, which allow creating different visual effects.
Only the most complex of them are covered by the widgets provided with this extension. The rest should be composed manually
using direct HTML composition.
However, several special Bootstrap markup cases are covered by the [[\yii\bootstrap4\Html]] helper.
[[\yii\bootstrap4\Html]] is an enhanced version of the regular [[\yii\helpers\Html]] dedicated to the Bootstrap needs.
It provides some useful methods like:
- `staticControl()` - allows rendering of form "[static controls](https://getbootstrap.com/docs/4.1/components/forms/#readonly-plain-text)"
As [[\yii\bootstrap4\Html]] extends [[\yii\helpers\Html]], it can be used as a substitute, so you don't need them both
inside your view files.
For example:
```php
<?php
use yii\bootstrap4\Html;
?>
<?= Button::widget([
'label' => Html::icon('approve') . Html::encode('Save & apply'),
'encodeLabel' => false,
'options' => ['class' => 'btn-primary'],
]); ?>
```
> Attention: do not confuse [[\yii\bootstrap4\Html]] and [[\yii\helpers\Html]], be careful of which class
you are using inside your views.

View File

@ -0,0 +1,20 @@
Installation
============
## Getting Composer package
The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
Either run
```
php composer.phar require --prefer-dist yiisoft/yii2-bootstrap4
```
or add
```
"yiisoft/yii2-bootstrap4": "~1.0.0"
```
to the require section of your `composer.json` file.

View File

@ -0,0 +1,107 @@
Migrating from yii2-bootstrap
=============================
yii2-bootstrap5 is a major rewrite of the entire project (according Bootstrap 5 to Bootstrap 4 migration guide).
The most notable changes are summarized below:
## General
* The namespace is `yii\bootstrap5` instead of `yii\bootstrap4`
* `npm` package is used instead of `bower`
* There is no theme asset any more
* No `popper.js` is needed any more (gets delivered with bootstrap js bundle)
## Widgets / Classes
* [[yii\bootstrap\Collapse|Collapse]] was renamed to [[yii\bootstrap5\Accordion|Accordion]]
* [[yii\bootstrap\BootstrapThemeAsset|BootstrapThemeAsset]] was removed
* [[yii\bootstrap5\Breadcrumbs|Breadcrumbs]] was added (Bootstrap 5 implementation of [[yii\widgets\Breadcrumbs]])
* [[yii\bootstrap5\ButtonToolbar|ButtonToolbar]] was added (https://getbootstrap.com/docs/4.3/components/button-group/#button-toolbar)
### BaseHtml
Removed method `icon`. Since there are no glyphicons bundled any more, this method makes no sense. Consider using
[Font Awesome Widget](https://github.com/rmrevin/yii2-fontawesome) or
[Font Awesome Inline Widget](https://github.com/YiiRocks/yii2-fontawesome-inline) as alternative.
### ActiveField
Following properties were renamed:
* `$checkboxTemplate` became `$checkTemplate`,
* `$horizontalCheckboxTemplate` became `$checkHorizontalTemplate`,
* `$horizontalRadioTemplate` became `$radioHorizontalTemplate`
The properties `$inlineCheckboxListTemplate` and `$inlineRadioListTemplate` were removed. There is a new template called
`$checkEnclosedTemplate`. In bootstrap 4 the checkboxes are not enclosed any more (by default).
### ActiveForm
There are some new constants [[yii\bootstrap5\ActiveForm::LAYOUT_DEFAULT]], [[yii\bootstrap5\ActiveForm::LAYOUT_HORIZONTAL]]
and [[yii\bootstrap5\ActiveForm::LAYOUT_INLINE]]. They're supposed to make layout selection easier and refactoring more
failsafe if the strings change at any time.
### Breadcrumbs
This class got introduced to render breadcrumbs with correct classes and attributes to fulfill bootstrap needs. It's
fully compatible with [[yii\widgets\Breadcrumbs]]
### ButtonDropdown
There is a new property called `$direction` which makes it possible to open the menu at e.g. the right side of the button.
There are some new constants [[yii\bootstrap5\ButtonDropdown::DIRECTION_DOWN]], [[yii\bootstrap5\ButtonDropdown::DIRECTION_LEFT]],
[[yii\bootstrap5\ButtonDropdown::DIRECTION_RIGHT]] and [[yii\bootstrap5\ButtonDropdown::DIRECTION_UP]] to make direction
selection easier.
There is a new property called `$renderContainer`. If it's set to `false`, the dropdown wrapping div will not be rendered.
Following properties were renamed:
* `$containerOptions` became `$options`,
* `$options` became `$buttonOptions`
### ButtonToolbar
This new class makes it possible to render a button toolbar. See https://getbootstrap.com/docs/4.3/components/button-group/#button-toolbar
for more information.
### Carousel
There is a new property called `$crossfade`. It controls the animation between slides. If it's set to `true`, there will
be an crossfade animation instead of a slide animation.
### LinkPager
This new class is the bootstrap version of [[yii\widgets\LinkPager]]. It renders a pagination in bootstrap style. See
https://getbootstrap.com/docs/4.3/components/pagination/ for more information.
### Modal
Following properties were renamed:
* `$header` became `$title`,
* `$headerOptions` became `$titleOptions`
It isn't necessary to write the `<h2 class="modal-title></h2>` any more. It will be rendered automatically.
### Nav
The `$dropdDownCaret` property was removed. This is only controllable via (S)CSS now. See
https://getbootstrap.com/docs/4.3/getting-started/theming/#sass-options
### NavBar
Following properties were renamed:
* `$containerOptions` became `$collapseOptions`
Removed property `$headerContent`. There is no navbar header any more. The toggler is now customizable so the properties
`$togglerContent` and `$togglerOptions` were introduced.
### Tabs
Introduces property `$panes`. It makes it possible to define pane contents via separate property instead of
`$items[0]['content']`. The index of the panes array corresponds to the index of the items. E.g. `$items[0]` belongs
to `$panes[0]`.
### ToggleButtonGroup
There are some new constants [[yii\bootstrap5\ToggleButtonGroup::TYPE_CHECKBOX]] and
[[yii\bootstrap5\ToggleButtonGroup::TYPE_RADIO]] to make type selection easier and refactoring more failsafe if the
strings change at any time.

17
docs/guide/topics-sass.md Normal file
View File

@ -0,0 +1,17 @@
Using the .sass files of Bootstrap directly
===========================================
If you want to include the [Bootstrap css directly in your sass files](http://getbootstrap.com/getting-started/#customizing)
you may need to disable the bootstrap css files loaded by this extension.
You can do this by setting the css property of [[yii\bootstrap4\BootstrapAsset|BootstrapAsset]] to be empty.
For this, you need to configure the `assetManager` [application component](https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-application-components.md) as follows:
```php
'assetManager' => [
'bundles' => [
'yii\bootstrap4\BootstrapAsset' => [
'css' => [],
]
]
]
```

View File

@ -0,0 +1,91 @@
Yii widgets
===========
Most complex bootstrap components are wrapped into Yii widgets to allow more robust syntax and integrate with
framework features. All widgets belong to `\yii\bootstrap4` namespace:
- [[yii\bootstrap4\Accordion|Accordion]]
- [[yii\bootstrap4\ActiveField|ActiveField]]
- [[yii\bootstrap4\ActiveForm|ActiveForm]]
- [[yii\bootstrap4\Alert|Alert]]
- [[yii\bootstrap4\Breadcrumbs|Breadcrumbs]]
- [[yii\bootstrap4\Button|Button]]
- [[yii\bootstrap4\ButtonDropdown|ButtonDropdown]]
- [[yii\bootstrap4\ButtonGroup|ButtonGroup]]
- [[yii\bootstrap4\ButtonToolbar|ButtonToolbar]]
- [[yii\bootstrap4\Carousel|Carousel]]
- [[yii\bootstrap4\Dropdown|Dropdown]]
- [[yii\bootstrap4\Modal|Modal]]
- [[yii\bootstrap4\Nav|Nav]]
- [[yii\bootstrap4\NavBar|NavBar]]
- [[yii\bootstrap4\Progress|Progress]]
- [[yii\bootstrap4\Tabs|Tabs]]
- [[yii\bootstrap4\ToggleButtonGroup|ToggleButtonGroup]]
## Customizing widget CSS classes <span id="customizing-css-classes"></span>
The widgets allow quick composition of the HTML for the bootstrap components that require the bootstrap CSS classes.
The default classes for a particular component will be added automatically by the widget, and the optional classes that you may want to customize are usually supported through the properties of the widget.
For example, you may use [[yii\bootstrap4\Button::options]] to customize the appearance of a button.
The class 'btn' which is required for a button will be added automatically, so you don't need to worry about it.
All you need is specify a particular button class:
```php
echo Button::widget([
'label' => 'Action',
'options' => ['class' => 'btn-primary'], // produces class "btn btn-primary"
]);
```
However, sometimes you may need to replace the default classes with the alternative ones.
For example, the widget [[yii\bootstrap4\ButtonGroup]] uses 'btn-group' class for the container div by default,
but you may need to use 'btn-group-vertical' instead to align the buttons vertically.
Using a plain 'class' option simply adds 'btn-group-vertical' to 'btn-group', which will produce an incorrect result.
In order to override the default classes of a widget, you need to specify the 'class' option as an array that contains the customized class definition under the 'widget' key:
```php
echo ButtonGroup::widget([
'options' => [
'class' => ['widget' => 'btn-group-vertical'] // replaces 'btn-group' with 'btn-group-vertical'
],
'buttons' => [
['label' => 'A'],
['label' => 'B'],
]
]);
```
## Navbar widget <span id="navbar-widget"></span>
The navbar widget has its peculiarities. You should define at which breakpoint the navbar collapses and the generic
style of navbar (color scheme).
You can change the color scheme and the collapse breakpoint with css classes. If not defined, the scheme defaults to
`navbar-light bg-light` and the breakpoint to `navbar-expand-lg`. For more information, see [Bootstrap documentation](https://getbootstrap.com/docs/4.2/components/navbar/):
```php
Navbar::begin([
'options' => [
'class' => ['navbar-dark', 'bg-dark', 'navbar-expand-md']
]
]);
[...]
Navbar::end();
```
If you'd like to flip the brand (icon) and toggle button positions in mobile navigation, you can do this like this:
```php
Navbar::begin([
'brandOptions' => [
'class' => ['order-1']
],
'togglerOptions' => [
'class' => ['order-0']
]
]);
[...]
Navbar::end();
```

14
phpunit.xml.dist Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit bootstrap="./tests/bootstrap.php"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="false">
<testsuites>
<testsuite name="Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@ -195,7 +195,7 @@ class ButtonDropdown extends Widget
protected function renderDropdown(): string protected function renderDropdown(): string
{ {
$config = $this->dropdown; $config = $this->dropdown;
$config['clientOptions'] = false; $config['clientOptions'] = [];
$config['view'] = $this->getView(); $config['view'] = $this->getView();
/** @var Widget $dropdownClass */ /** @var Widget $dropdownClass */
$dropdownClass = $this->dropdownClass; $dropdownClass = $this->dropdownClass;

View File

@ -60,7 +60,7 @@ class LinkPager extends Widget
/** /**
* @var string the CSS class for the each page button. * @var string the CSS class for the each page button.
*/ */
public string $pageCssClass; public string $pageCssClass = 'page-item';
/** /**
* @var string the CSS class for the "first" page button. * @var string the CSS class for the "first" page button.
*/ */
@ -226,7 +226,7 @@ class LinkPager extends Widget
[$beginPage, $endPage] = $this->getPageRange(); [$beginPage, $endPage] = $this->getPageRange();
for ($i = $beginPage; $i <= $endPage; ++$i) { for ($i = $beginPage; $i <= $endPage; ++$i) {
$buttons[] = $this->renderPageButton( $buttons[] = $this->renderPageButton(
$i + 1, (string)($i + 1),
$i, $i,
'', '',
$this->disableCurrentPageButton && $i == $currentPage, $this->disableCurrentPageButton && $i == $currentPage,
@ -252,7 +252,7 @@ class LinkPager extends Widget
$lastPageLabel = $this->lastPageLabel === true ? $pageCount : $this->lastPageLabel; $lastPageLabel = $this->lastPageLabel === true ? $pageCount : $this->lastPageLabel;
if ($lastPageLabel !== false) { if ($lastPageLabel !== false) {
$buttons[] = $this->renderPageButton( $buttons[] = $this->renderPageButton(
$lastPageLabel, (string)$lastPageLabel,
$pageCount - 1, $pageCount - 1,
$this->lastPageCssClass, $this->lastPageCssClass,
$currentPage >= $pageCount - 1, $currentPage >= $pageCount - 1,

View File

@ -136,7 +136,7 @@ class Nav extends Widget
public function renderItems(): string public function renderItems(): string
{ {
$items = []; $items = [];
foreach ($this->items as $i => $item) { foreach ($this->items as $item) {
if (isset($item['visible']) && !$item['visible']) { if (isset($item['visible']) && !$item['visible']) {
continue; continue;
} }
@ -211,7 +211,7 @@ class Nav extends Widget
'options' => ArrayHelper::getValue($parentItem, 'dropdownOptions', []), 'options' => ArrayHelper::getValue($parentItem, 'dropdownOptions', []),
'items' => $items, 'items' => $items,
'encodeLabels' => $this->encodeLabels, 'encodeLabels' => $this->encodeLabels,
'clientOptions' => false, 'clientOptions' => [],
'view' => $this->getView(), 'view' => $this->getView(),
]); ]);
} }
@ -228,7 +228,7 @@ class Nav extends Widget
if (is_array($child) && !ArrayHelper::getValue($child, 'visible', true)) { if (is_array($child) && !ArrayHelper::getValue($child, 'visible', true)) {
continue; continue;
} }
if ($this->isItemActive($child)) { if (is_array($child) && $this->isItemActive($child)) {
ArrayHelper::setValue($items[$i], 'active', true); ArrayHelper::setValue($items[$i], 'active', true);
if ($this->activateParents) { if ($this->activateParents) {
$active = true; $active = true;

325
tests/AccordionTest.php Normal file
View File

@ -0,0 +1,325 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\Accordion;
use yii\widgets\ActiveForm;
/**
* @group bootstrap5
*/
class AccordionTest extends TestCase
{
public function testRender()
{
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
[
'label' => 'Collapsible Group Item #1',
'content' => [
'test content1',
'test content2'
],
],
[
'label' => 'Collapsible Group Item #2',
'content' => 'Das ist das Haus vom Nikolaus',
'contentOptions' => [
'class' => 'testContentOptions'
],
'options' => [
'class' => 'testClass',
'id' => 'testId'
],
'footer' => 'Footer'
],
[
'label' => '<h1>Collapsible Group Item #3</h1>',
'content' => [
'<h2>test content1</h2>',
'<h2>test content2</h2>'
],
'contentOptions' => [
'class' => 'testContentOptions2'
],
'options' => [
'class' => 'testClass2',
'id' => 'testId2'
],
'encode' => false,
'footer' => 'Footer2'
],
[
'label' => '<h1>Collapsible Group Item #4</h1>',
'content' => [
'<h2>test content1</h2>',
'<h2>test content2</h2>'
],
'contentOptions' => [
'class' => 'testContentOptions3'
],
'options' => [
'class' => 'testClass3',
'id' => 'testId3'
],
'encode' => true,
'footer' => 'Footer3'
],
]
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="card"><div id="w0-collapse0-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w1" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse0" aria-expanded="true" aria-controls="w0-collapse0">Collapsible Group Item #1</button>
</h5></div>
<div id="w0-collapse0" class="collapse show" aria-labelledby="w0-collapse0-heading" data-parent="#w0">
<ul class="list-group">
<li class="list-group-item">test content1</li>
<li class="list-group-item">test content2</li>
</ul>
</div></div>
<div id="testId" class="testClass card"><div id="w0-collapse1-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w2" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse1" aria-expanded="false" aria-controls="w0-collapse1">Collapsible Group Item #2</button>
</h5></div>
<div id="w0-collapse1" class="testContentOptions collapse" aria-labelledby="w0-collapse1-heading" data-parent="#w0">
<div class="card-body">Das ist das Haus vom Nikolaus</div>
<div class="card-footer">Footer</div>
</div></div>
<div id="testId2" class="testClass2 card"><div id="w0-collapse2-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w3" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse2" aria-expanded="false" aria-controls="w0-collapse2"><h1>Collapsible Group Item #3</h1></button>
</h5></div>
<div id="w0-collapse2" class="testContentOptions2 collapse" aria-labelledby="w0-collapse2-heading" data-parent="#w0">
<ul class="list-group">
<li class="list-group-item"><h2>test content1</h2></li>
<li class="list-group-item"><h2>test content2</h2></li>
</ul>
<div class="card-footer">Footer2</div>
</div></div>
<div id="testId3" class="testClass3 card"><div id="w0-collapse3-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w4" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse3" aria-expanded="false" aria-controls="w0-collapse3">&lt;h1&gt;Collapsible Group Item #4&lt;/h1&gt;</button>
</h5></div>
<div id="w0-collapse3" class="testContentOptions3 collapse" aria-labelledby="w0-collapse3-heading" data-parent="#w0">
<ul class="list-group">
<li class="list-group-item"><h2>test content1</h2></li>
<li class="list-group-item"><h2>test content2</h2></li>
</ul>
<div class="card-footer">Footer3</div>
</div></div>
</div>
HTML
, $output);
}
public function testLabelKeys()
{
ob_start();
$form = ActiveForm::begin(['action' => '/something']);
ActiveForm::end();
ob_end_clean();
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
'Item1' => 'Content1',
'Item2' => [
'content' => 'Content2',
],
[
'label' => 'Item3',
'content' => 'Content3',
],
'FormField' => $form->field(new DynamicModel(['test']), 'test',['template' => '{input}']),
]
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="card"><div id="w0-collapse0-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w1" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse0" aria-expanded="true" aria-controls="w0-collapse0">Item1</button>
</h5></div>
<div id="w0-collapse0" class="collapse show" aria-labelledby="w0-collapse0-heading" data-parent="#w0">
<div class="card-body">Content1</div>
</div></div>
<div class="card"><div id="w0-collapse1-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w2" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse1" aria-expanded="false" aria-controls="w0-collapse1">Item2</button>
</h5></div>
<div id="w0-collapse1" class="collapse" aria-labelledby="w0-collapse1-heading" data-parent="#w0">
<div class="card-body">Content2</div>
</div></div>
<div class="card"><div id="w0-collapse2-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w3" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse2" aria-expanded="false" aria-controls="w0-collapse2">Item3</button>
</h5></div>
<div id="w0-collapse2" class="collapse" aria-labelledby="w0-collapse2-heading" data-parent="#w0">
<div class="card-body">Content3</div>
</div></div>
<div class="card"><div id="w0-collapse3-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w4" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse3" aria-expanded="false" aria-controls="w0-collapse3">FormField</button>
</h5></div>
<div id="w0-collapse3" class="collapse" aria-labelledby="w0-collapse3-heading" data-parent="#w0">
<div class="card-body"><div class="form-group field-dynamicmodel-test">
<input type="text" id="dynamicmodel-test" class="form-control" name="DynamicModel[test]">
</div></div>
</div></div>
</div>
HTML
, $output);
}
public function testExpandOptions()
{
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
'Item1' => 'Content1',
'Item2' => [
'content' => 'Content2',
'expand' => true,
],
]
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="card"><div id="w0-collapse0-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w1" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse0" aria-expanded="false" aria-controls="w0-collapse0">Item1</button>
</h5></div>
<div id="w0-collapse0" class="collapse" aria-labelledby="w0-collapse0-heading" data-parent="#w0">
<div class="card-body">Content1</div>
</div></div>
<div class="card"><div id="w0-collapse1-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w2" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse1" aria-expanded="true" aria-controls="w0-collapse1">Item2</button>
</h5></div>
<div id="w0-collapse1" class="collapse show" aria-labelledby="w0-collapse1-heading" data-parent="#w0">
<div class="card-body">Content2</div>
</div></div>
</div>
HTML
, $output);
}
public function invalidItemsProvider()
{
return [
[ ['content'] ], // only content without label key
[ [[]] ], // only content array without label
[ [['content' => 'test']] ], // only content array without label
];
}
/**
* @dataProvider invalidItemsProvider
* @expectedException \yii\base\InvalidConfigException
*/
public function testMissingLabel($items)
{
Accordion::widget([
'items' => $items,
]);
}
/**
* @see https://github.com/yiisoft/yii2/issues/8357
*/
public function testRenderObject()
{
$template = ['template' => '{input}'];
ob_start();
$form = ActiveForm::begin(['action' => '/something']);
ActiveForm::end();
ob_end_clean();
$model = new data\Singer;
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
[
'label' => 'Collapsible Group Item #1',
'content' => $form->field($model, 'firstName', $template)
],
]
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="card"><div id="w0-collapse0-heading" class="card-header"><h5 class="mb-0"><button type="button" id="w1" class="btn-link btn" data-toggle="collapse" data-target="#w0-collapse0" aria-expanded="true" aria-controls="w0-collapse0">Collapsible Group Item #1</button>
</h5></div>
<div id="w0-collapse0" class="collapse show" aria-labelledby="w0-collapse0-heading" data-parent="#w0">
<div class="card-body"><div class="form-group field-singer-firstname">
<input type="text" id="singer-firstname" class="form-control" name="Singer[firstName]">
</div></div>
</div></div>
</div>
HTML
, $output);
}
public function testAutoCloseItems()
{
$items = [
[
'label' => 'Item 1',
'content' => 'Content 1',
],
[
'label' => 'Item 2',
'content' => 'Content 2',
],
];
$output = Accordion::widget([
'items' => $items
]);
$this->assertContains('data-parent="', $output);
$output = Accordion::widget([
'autoCloseItems' => false,
'items' => $items
]);
$this->assertNotContains('data-parent="', $output);
}
/**
* @depends testRender
*/
public function testItemToggleTag()
{
$items = [
[
'label' => 'Item 1',
'content' => 'Content 1',
],
[
'label' => 'Item 2',
'content' => 'Content 2',
],
];
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => $items,
'itemToggleOptions' => [
'tag' => 'a',
'class' => 'custom-toggle',
],
]);
$this->assertContains('<h5 class="mb-0"><a type="button" class="custom-toggle" href="#w0-collapse0" ', $output);
$this->assertNotContains('<button', $output);
$output = Accordion::widget([
'items' => $items,
'itemToggleOptions' => [
'tag' => 'a',
'class' => ['widget' => 'custom-toggle'],
],
]);
$this->assertContains('<h5 class="mb-0"><a type="button" class="custom-toggle" href="#w1-collapse0" ', $output);
$this->assertNotContains('collapse-toggle', $output);
}
}

View File

@ -0,0 +1,241 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use Yii;
use yii\base\DynamicModel;
use yii\bootstrap5\ActiveField;
use yii\bootstrap5\ActiveForm;
use yii\bootstrap5\Html;
use yii\helpers\UnsetArrayValue;
class ActiveFieldDefaultFormCheckTest extends TestCase
{
/**
* @var ActiveField
*/
private $_activeField;
/**
* @var DynamicModel
*/
private $_helperModel;
/**
* @var ActiveForm
*/
private $_helperForm;
/**
* @var string
*/
private $_attributeName = 'attributeName';
protected function setUp()
{
// dirty way to have Request object not throwing exception when running testHomeLinkNull()
$_SERVER['SCRIPT_FILENAME'] = 'index.php';
$_SERVER['SCRIPT_NAME'] = 'index.php';
$this->mockWebApplication([
'container' => [
'definitions' => [
'yii\bootstrap5\ActiveField' => [
'checkTemplate' => "<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>",
'radioTemplate' => "<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>",
'checkHorizontalTemplate' => "{beginWrapper}\n<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>\n{endWrapper}",
'radioHorizontalTemplate' => "{beginWrapper}\n<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>\n{endWrapper}",
'checkOptions' => [
'class' => ['widget' => 'form-check-input'],
'labelOptions' => [
'class' => ['widget' => 'form-check-label']
],
'wrapperOptions' => [
'class' => ['widget' => 'form-check']
]
],
'radioOptions' => [
'class' => ['widget' => 'form-check-input'],
'labelOptions' => [
'class' => ['widget' => 'form-check-label']
],
'wrapperOptions' => [
'class' => ['widget' => 'form-check']
]
]
]
]
]
]);
$this->_helperModel = new DynamicModel(['attributeName']);
ob_start();
$this->_helperForm = ActiveForm::begin(['action' => '/something']);
ActiveForm::end();
ob_end_clean();
$this->_activeField = Yii::createObject([
'class' => 'yii\bootstrap5\ActiveField',
'form' => $this->_helperForm
]);
$this->_activeField->model = $this->_helperModel;
$this->_activeField->attribute = $this->_attributeName;
}
public function testDefaultCheckboxByConfig()
{
Html::$counter = 0;
$this->_activeField->inline = true;
$html = $this->_activeField->checkbox()->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<div class="form-check">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="checkbox" id="dynamicmodel-attributename" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testDefaultRadioByConfig()
{
Html::$counter = 0;
$this->_activeField->inline = true;
$html = $this->_activeField->radio()->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<div class="form-check">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="radio" id="dynamicmodel-attributename" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testDefaultCheckboxListByConfig()
{
Html::$counter = 0;
$html = $this->_activeField->checkboxList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename"><div class="form-check">
<input type="checkbox" id="i0" class="form-check-input" name="DynamicModel[attributeName][]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="checkbox" id="i1" class="form-check-input" name="DynamicModel[attributeName][]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testDefaultRadioListByConfig()
{
Html::$counter = 0;
$html = $this->_activeField->radioList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" role="radiogroup"><div class="form-check">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[attributeName]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testHorizontalLayout()
{
Html::$counter = 0;
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'checkbox', 'gridRadios']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_HORIZONTAL
]);
echo $form->field($model, 'attributeName');
echo $form->field($model, 'checkbox')->checkbox(['wrapperOptions' => ['class' => ['widget' => new UnsetArrayValue()]]]);
echo $form->field($model, 'gridRadios')->radioList([
'option1' => 'First radio',
'option2' => 'Second radio',
'option3' => 'Third radio'
]);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-group row field-dynamicmodel-attributename">
<label class="col-sm-2 col-form-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="col-sm-10">
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]">
<div class="invalid-feedback "></div>
</div>
</div>
HTML;
$expected2 = <<<HTML
<div class="form-group row field-dynamicmodel-checkbox">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input type="hidden" name="DynamicModel[checkbox]" value="0"><input type="checkbox" id="dynamicmodel-checkbox" class="form-check-input" name="DynamicModel[checkbox]" value="1">
<label class="form-check-label" for="dynamicmodel-checkbox">Checkbox</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
HTML;
$expected3 = <<<HTML
<div class="form-group row field-dynamicmodel-gridradios">
<label class="col-sm-2 col-form-label">Grid Radios</label>
<div class="col-sm-10">
<input type="hidden" name="DynamicModel[gridRadios]" value=""><div id="dynamicmodel-gridradios" role="radiogroup"><div class="form-check">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[gridRadios]" value="option1">
<label class="form-check-label" for="i0">First radio</label>
</div>
<div class="form-check">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[gridRadios]" value="option2">
<label class="form-check-label" for="i1">Second radio</label>
</div>
<div class="form-check">
<input type="radio" id="i2" class="form-check-input" name="DynamicModel[gridRadios]" value="option3">
<label class="form-check-label" for="i2">Third radio</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
}

336
tests/ActiveFieldTest.php Normal file
View File

@ -0,0 +1,336 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\ActiveField;
use yii\bootstrap5\ActiveForm;
use yii\bootstrap5\Html;
class ActiveFieldTest extends TestCase
{
/**
* @var ActiveField
*/
private $activeField;
/**
* @var DynamicModel
*/
private $helperModel;
/**
* @var ActiveForm
*/
private $helperForm;
/**
* @var string
*/
private $attributeName = 'attributeName';
protected function setUp()
{
// dirty way to have Request object not throwing exception when running testHomeLinkNull()
$_SERVER['SCRIPT_FILENAME'] = "index.php";
$_SERVER['SCRIPT_NAME'] = "index.php";
parent::setUp();
$this->helperModel = new DynamicModel(['attributeName']);
ob_start();
$this->helperForm = ActiveForm::begin(['action' => '/something']);
ActiveForm::end();
ob_end_clean();
$this->activeField = new ActiveField(['form' => $this->helperForm]);
$this->activeField->model = $this->helperModel;
$this->activeField->attribute = $this->attributeName;
}
public function testFileInput()
{
Html::$counter = 0;
$html = $this->activeField->fileInput()->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label for="dynamicmodel-attributename">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><input type="file" id="dynamicmodel-attributename" class="form-control-file" name="DynamicModel[attributeName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
// Tests :
public function testRadioList()
{
Html::$counter = 0;
$html = $this->activeField->radioList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" role="radiogroup"><div class="custom-control custom-radio">
<input type="radio" id="i0" class="custom-control-input" name="DynamicModel[attributeName]" value="1">
<label class="custom-control-label" for="i0">name1</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="i1" class="custom-control-input" name="DynamicModel[attributeName]" value="2">
<label class="custom-control-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRadioError()
{
Html::$counter = 0;
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->radio()->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<div class="custom-control custom-radio">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="radio" id="dynamicmodel-attributename" class="custom-control-input is-invalid" name="DynamicModel[attributeName]" value="1" aria-invalid="true">
<label class="custom-control-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRadioListError()
{
Html::$counter = 0;
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->radioList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" class="is-invalid" role="radiogroup" aria-invalid="true"><div class="custom-control custom-radio">
<input type="radio" id="i0" class="custom-control-input" name="DynamicModel[attributeName]" value="1">
<label class="custom-control-label" for="i0">name1</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="i1" class="custom-control-input" name="DynamicModel[attributeName]" value="2">
<label class="custom-control-label" for="i1">name2</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxList()
{
Html::$counter = 0;
$html = $this->activeField->checkboxList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename"><div class="custom-control custom-checkbox">
<input type="checkbox" id="i0" class="custom-control-input" name="DynamicModel[attributeName][]" value="1">
<label class="custom-control-label" for="i0">name1</label>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" id="i1" class="custom-control-input" name="DynamicModel[attributeName][]" value="2">
<label class="custom-control-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxError()
{
Html::$counter = 0;
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->checkbox()->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<div class="custom-control custom-checkbox">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="checkbox" id="dynamicmodel-attributename" class="custom-control-input is-invalid" name="DynamicModel[attributeName]" value="1" aria-invalid="true">
<label class="custom-control-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxListError()
{
Html::$counter = 0;
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->checkboxList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" class="is-invalid" aria-invalid="true"><div class="custom-control custom-checkbox">
<input type="checkbox" id="i0" class="custom-control-input" name="DynamicModel[attributeName][]" value="1">
<label class="custom-control-label" for="i0">name1</label>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" id="i1" class="custom-control-input" name="DynamicModel[attributeName][]" value="2">
<label class="custom-control-label" for="i1">name2</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRadioListInline()
{
Html::$counter = 0;
$this->activeField->inline = true;
$html = $this->activeField->radioList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" role="radiogroup"><div class="custom-control custom-radio custom-control-inline">
<input type="radio" id="i0" class="custom-control-input" name="DynamicModel[attributeName]" value="1">
<label class="custom-control-label" for="i0">name1</label>
</div>
<div class="custom-control custom-radio custom-control-inline">
<input type="radio" id="i1" class="custom-control-input" name="DynamicModel[attributeName]" value="2">
<label class="custom-control-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxListInline()
{
Html::$counter = 0;
$this->activeField->inline = true;
$html = $this->activeField->checkboxList([1 => 'name1', 2 => 'name2'])->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label>Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename"><div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" id="i0" class="custom-control-input" name="DynamicModel[attributeName][]" value="1">
<label class="custom-control-label" for="i0">name1</label>
</div>
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" id="i1" class="custom-control-input" name="DynamicModel[attributeName][]" value="2">
<label class="custom-control-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
* @depends testRadioList
*
* @see https://github.com/yiisoft/yii2-bootstrap/issues/81
*/
public function testRadioListItemOptions()
{
Html::$counter = 0;
$content = $this->activeField->radioList([1 => 'name1', 2 => 'name2'], [
'itemOptions' => [
'data-attribute' => 'test'
]
])->render();
$this->assertContains('data-attribute="test"', $content);
}
/**
* @depends testCheckboxList
*
* @see https://github.com/yiisoft/yii2-bootstrap/issues/81
*/
public function testCheckboxListItemOptions()
{
Html::$counter = 0;
$content = $this->activeField->checkboxList([1 => 'name1', 2 => 'name2'], [
'itemOptions' => [
'data-attribute' => 'test'
]
])->render();
$this->assertContains('data-attribute="test"', $content);
}
/**
*
*/
public function testCustomRadio()
{
Html::$counter = 0;
$this->activeField->inline = true;
$html = $this->activeField->radio()->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<div class="custom-control custom-radio">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="radio" id="dynamicmodel-attributename" class="custom-control-input" name="DynamicModel[attributeName]" value="1">
<label class="custom-control-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
*
*/
public function testCustomCheckbox()
{
Html::$counter = 0;
$this->activeField->inline = true;
$html = $this->activeField->checkbox()->render();
$expectedHtml = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<div class="custom-control custom-checkbox">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="checkbox" id="dynamicmodel-attributename" class="custom-control-input" name="DynamicModel[attributeName]" value="1">
<label class="custom-control-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
}

321
tests/ActiveFormTest.php Normal file
View File

@ -0,0 +1,321 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\ActiveForm;
use yii\bootstrap5\Html;
use yiiunit\extensions\bootstrap5\data\User;
/**
* Tests for ActiveForm widget
*
* @group bootstrap5
*/
class ActiveFormTest extends TestCase
{
protected function setUp()
{
// dirty way to have Request object not throwing exception when running testFormNoRoleAttribute()
$_SERVER['REQUEST_URI'] = "index.php";
parent::setUp();
}
public function testDefaultLayout()
{
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'radios']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_DEFAULT
]);
echo $form->field($model, 'attributeName');
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label for="dynamicmodel-attributename">Attribute Name</label>
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
}
public function testHorizontalLayout()
{
Html::$counter = 0;
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'checkbox', 'gridRadios']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_HORIZONTAL
]);
echo $form->field($model, 'attributeName');
echo $form->field($model, 'checkbox')->checkbox();
echo $form->field($model, 'gridRadios')->radioList([
'option1' => 'First radio',
'option2' => 'Second radio',
'option3' => 'Third radio'
]);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-group row field-dynamicmodel-attributename">
<label class="col-sm-2 col-form-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="col-sm-10">
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]">
<div class="invalid-feedback "></div>
</div>
</div>
HTML;
$expected2 = <<<HTML
<div class="form-group row field-dynamicmodel-checkbox">
<div class="col-sm-10 offset-sm-2">
<div class="custom-control custom-checkbox">
<input type="hidden" name="DynamicModel[checkbox]" value="0"><input type="checkbox" id="dynamicmodel-checkbox" class="custom-control-input" name="DynamicModel[checkbox]" value="1">
<label class="custom-control-label" for="dynamicmodel-checkbox">Checkbox</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
HTML;
$expected3 = <<<HTML
<div class="form-group row field-dynamicmodel-gridradios">
<label class="col-sm-2 col-form-label">Grid Radios</label>
<div class="col-sm-10">
<input type="hidden" name="DynamicModel[gridRadios]" value=""><div id="dynamicmodel-gridradios" role="radiogroup"><div class="custom-control custom-radio">
<input type="radio" id="i0" class="custom-control-input" name="DynamicModel[gridRadios]" value="option1">
<label class="custom-control-label" for="i0">First radio</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="i1" class="custom-control-input" name="DynamicModel[gridRadios]" value="option2">
<label class="custom-control-label" for="i1">Second radio</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="i2" class="custom-control-input" name="DynamicModel[gridRadios]" value="option3">
<label class="custom-control-label" for="i2">Third radio</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
/**
* @depends testHorizontalLayout
*/
public function testHorizontalLayoutTemplateOverride()
{
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['checkboxName']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_HORIZONTAL
]);
echo $form->field($model, 'checkboxName')->checkbox(['template' => "<div class=\"offset-lg-1 col-lg-3\">\n{input}\n{label}\n</div>\n<div class=\"col-lg-8\">{error}</div>"]);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="offset-lg-1 col-lg-3">
<input type="hidden" name="DynamicModel[checkboxName]" value="0"><input type="checkbox" id="dynamicmodel-checkboxname" class="custom-control-input" name="DynamicModel[checkboxName]" value="1">
<label class="custom-control-label" for="dynamicmodel-checkboxname">Checkbox Name</label>
</div>
<div class="col-lg-8"><div class="invalid-feedback "></div></div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
}
public function testInlineLayout()
{
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'selectName', 'checkboxName']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_INLINE
]);
echo $form->field($model, 'attributeName');
echo $form->field($model, 'selectName')->listBox([
'1' => 'One',
'2' => 'Two',
'3' => 'Three'
]);
echo $form->field($model, 'checkboxName')->checkbox();
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-group field-dynamicmodel-attributename">
<label class="sr-only" for="dynamicmodel-attributename">Attribute Name</label>
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]" placeholder="Attribute Name">
</div>
HTML;
$expected2 = <<<HTML
<div class="form-group field-dynamicmodel-selectname">
<label for="dynamicmodel-selectname">Select Name</label>
<input type="hidden" name="DynamicModel[selectName]" value=""><select id="dynamicmodel-selectname" class="form-control" name="DynamicModel[selectName]" size="4" placeholder>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
HTML;
$expected3 = <<<HTML
<div class="form-group field-dynamicmodel-checkboxname">
<div class="custom-control custom-checkbox">
<input type="hidden" name="DynamicModel[checkboxName]" value="0"><input type="checkbox" id="dynamicmodel-checkboxname" class="custom-control-input" name="DynamicModel[checkboxName]" value="1">
<label class="sr-only custom-control-label" for="dynamicmodel-checkboxname">Checkbox Name</label>
</div>
</div>
HTML;
$this->assertContainsWithoutLE('<form id="w0" class="form-inline"', $out);
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
public function testHintRendering()
{
ActiveForm::$counter = 0;
ob_start();
$model = new User();
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_DEFAULT
]);
echo $form->field($model, 'firstName');
echo $form->field($model, 'lastName');
echo $form->field($model, 'username');
echo $form->field($model, 'password')->passwordInput();
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-group field-user-firstname">
<label for="user-firstname">First Name</label>
<input type="text" id="user-firstname" class="form-control" name="User[firstName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$expected2 = <<<HTML
<div class="form-group field-user-lastname">
<label for="user-lastname">Last Name</label>
<input type="text" id="user-lastname" class="form-control" name="User[lastName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$expected3 = <<<HTML
<div class="form-group field-user-username required">
<label for="user-username">Username</label>
<input type="text" id="user-username" class="form-control" name="User[username]" aria-required="true">
<small class="form-text text-muted">Your username must be at least 4 characters long</small>
<div class="invalid-feedback"></div>
</div>
HTML;
$expected4 = <<<HTML
<div class="form-group field-user-password required">
<label for="user-password">Password</label>
<input type="password" id="user-password" class="form-control" name="User[password]" aria-required="true">
<small class="form-text text-muted">Your password must be 8-20 characters long, contain letters and numbers, and must not contain spaces, special characters, or emoji.</small>
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
$this->assertContainsWithoutLE($expected4, $out);
}
/**
* Fixes #128
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/128
*/
public function testInputTemplate()
{
$model = new User();
$model->validate();
ActiveForm::$counter = 0;
ob_start();
$form = ActiveForm::begin();
echo $form->field($model, 'username', ['inputTemplate' => '{input}']);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-group field-user-username required">
<label for="user-username">Username</label>
<input type="text" id="user-username" class="form-control is-invalid" name="User[username]" aria-required="true" aria-invalid="true">
<small class="form-text text-muted">Your username must be at least 4 characters long</small>
<div class="invalid-feedback">Username cannot be blank.</div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
}
/**
* Fixes #196
*/
public function testFormNoRoleAttribute()
{
$form = ActiveForm::widget();
$this->assertNotContains('role="form"', $form);
}
public function testErrorSummaryRendering()
{
ActiveForm::$counter = 0;
ob_start();
$model = new User();
$model->validate();
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_DEFAULT
]);
echo $form->errorSummary($model);
ActiveForm::end();
$out = ob_get_clean();
$this->assertContainsWithoutLE('<div class="alert alert-danger"', $out);
}
}

56
tests/AlertTest.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Alert;
/**
* Tests for Alert widget
*
* @group bootstrap5
*/
class AlertTest extends TestCase
{
public function testNormalAlert()
{
Alert::$counter = 0;
$html = Alert::widget([
'body' => '<strong>Holy guacamole!</strong> You should check in on some of those fields below.',
'options' => [
'class' => ['alert-warning']
]
]);
$expectedHtml = <<<HTML
<div id="w0" class="alert-warning alert alert-dismissible" role="alert">
<strong>Holy guacamole!</strong> You should check in on some of those fields below.
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span></button>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
* @depends testNormalAlert
*/
public function testDismissibleAlert()
{
Alert::$counter = 0;
$html = Alert::widget([
'body' => "Message1",
]);
$expectedHtml = <<<HTML
<div id="w0" class="alert alert-dismissible" role="alert">
Message1
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span></button>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
}

33
tests/BreadcrumbsTest.php Normal file
View File

@ -0,0 +1,33 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Breadcrumbs;
/**
* @group bootstrap5
*/
class BreadcrumbsTest extends TestCase
{
public function testRender()
{
Breadcrumbs::$counter = 0;
$out = Breadcrumbs::widget([
'homeLink' => ['label' => 'Home', 'url' => '#'],
'links' => [
['label' => 'Library', 'url' => '#'],
['label' => 'Data']
]
]);
$expected = <<<HTML
<nav aria-label="breadcrumb"><ol id="w0" class="breadcrumb"><li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item"><a href="#">Library</a></li>
<li class="breadcrumb-item active" aria-current="page">Data</li>
</ol></nav>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\ButtonDropdown;
/**
* @group bootstrap5
*/
class ButtonDropdownTest extends TestCase
{
public function testContainerOptions()
{
$containerClass = 'testClass';
ButtonDropdown::$counter = 0;
$out = ButtonDropdown::widget([
'direction' => ButtonDropdown::DIRECTION_UP,
'options' => [
'class' => $containerClass,
],
'label' => 'Action',
'dropdown' => [
'items' => [
['label' => 'DropdownA', 'url' => '/'],
['label' => 'DropdownB', 'url' => '#'],
],
],
]);
$this->assertContains("$containerClass dropup btn-group", $out);
}
public function testDirection()
{
ButtonDropdown::$counter = 0;
$out = ButtonDropdown::widget([
'direction' => ButtonDropdown::DIRECTION_LEFT,
'label' => 'Action',
'dropdown' => [
'items' => [
['label' => 'ItemA', 'url' => '#'],
['label' => 'ItemB', 'url' => '#'],
],
],
]);
$expected = <<<EXPECTED
<div id="w0" class="dropleft btn-group"><button id="w0-button" class="btn dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Action</button>
<div id="w1" class="dropdown-menu"><a class="dropdown-item" href="#">ItemA</a>
<a class="dropdown-item" href="#">ItemB</a></div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testSplit()
{
ButtonDropdown::$counter = 0;
$out = ButtonDropdown::widget([
'direction' => ButtonDropdown::DIRECTION_DOWN,
'label' => 'Split dropdown',
'split' => true,
'dropdown' => [
'items' => [
['label' => 'ItemA', 'url' => '#'],
['label' => 'ItemB', 'url' => '#']
]
]
]);
$expected = <<<EXPECTED
<div id="w0" class="dropdown btn-group"><button id="w1" class="btn">Split dropdown</button>
<button id="w0-button" class="btn dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="sr-only">Toggle Dropdown</span></button>
<div id="w2" class="dropdown-menu"><a class="dropdown-item" href="#">ItemA</a>
<a class="dropdown-item" href="#">ItemB</a></div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
}

33
tests/ButtonGroupTest.php Normal file
View File

@ -0,0 +1,33 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Button;
use yii\bootstrap5\ButtonGroup;
/**
* @group bootstrap5
*/
class ButtonGroupTest extends TestCase
{
public function testContainerOptions()
{
ButtonGroup::$counter = 0;
$out = ButtonGroup::widget([
'buttons' => [
['label' => 'button-A'],
['label' => 'button-B', 'visible' => true],
['label' => 'button-C', 'visible' => false],
Button::widget(['label' => 'button-D']),
],
]);
$expected = <<<HTML
<div id="w1" class="btn-group" role="group"><button type="button" id="w2" class="btn">button-A</button>
<button type="button" id="w3" class="btn">button-B</button>
<button id="w0" class="btn">button-D</button></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

106
tests/ButtonToolbarTest.php Normal file
View File

@ -0,0 +1,106 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\ButtonGroup;
use yii\bootstrap5\ButtonToolbar;
/**
* @group bootstrap5
*/
class ButtonToolbarTest extends TestCase
{
public function testContainerOptions()
{
ButtonToolbar::$counter = 0;
$out = ButtonToolbar::widget([
'options' => [
'aria-label' => 'Toolbar with button groups'
],
'buttonGroups' => [
ButtonGroup::widget([
'options' => [
'aria-label' => 'First group',
'class' => ['mr-2']
],
'buttons' => [
['label' => '1'],
['label' => '2'],
['label' => '3'],
['label' => '4']
]
]),
[
'options' => [
'aria-label' => 'Second group'
],
'buttons' => [
['label' => '5'],
['label' => '6'],
['label' => '7']
]
]
]
]);
$expected = <<<HTML
<div id="w5" class="btn-toolbar" aria-label="Toolbar with button groups" role="toolbar"><div id="w0" class="mr-2 btn-group" aria-label="First group" role="group"><button type="button" id="w1" class="btn">1</button>
<button type="button" id="w2" class="btn">2</button>
<button type="button" id="w3" class="btn">3</button>
<button type="button" id="w4" class="btn">4</button></div>
<div id="w6" class="btn-group" aria-label="Second group" role="group"><button type="button" id="w7" class="btn">5</button>
<button type="button" id="w8" class="btn">6</button>
<button type="button" id="w9" class="btn">7</button></div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testAdditionalContent()
{
ButtonToolbar::$counter = 0;
$addHtml = <<<HTML
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text" id="btnGroupAddon">@</div>
</div>
<input type="text" class="form-control" placeholder="Input group example" aria-label="Input group example" aria-describedby="btnGroupAddon">
</div>
HTML;
$out = ButtonToolbar::widget([
'options' => [
'aria-label' => 'Toolbar with button groups'
],
'buttonGroups' => [
[
'options' => [
'aria-label' => 'First group',
'class' => ['mr-2']
],
'buttons' => [
['label' => '1'],
['label' => '2'],
['label' => '3'],
['label' => '4']
]
],
$addHtml
]
]);
$expected = <<<HTML
<div id="w0" class="btn-toolbar" aria-label="Toolbar with button groups" role="toolbar"><div id="w1" class="mr-2 btn-group" aria-label="First group" role="group"><button type="button" id="w2" class="btn">1</button>
<button type="button" id="w3" class="btn">2</button>
<button type="button" id="w4" class="btn">3</button>
<button type="button" id="w5" class="btn">4</button></div>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text" id="btnGroupAddon">@</div>
</div>
<input type="text" class="form-control" placeholder="Input group example" aria-label="Input group example" aria-describedby="btnGroupAddon">
</div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

95
tests/CarouselTest.php Normal file
View File

@ -0,0 +1,95 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Carousel;
/**
* @group bootstrap5
*/
class CarouselTest extends TestCase
{
function testContainerOptions()
{
Carousel::$counter = 0;
$out = Carousel::widget([
'items' => [
[
'content' => '<img src="https://via.placeholder.com/800x400?text=First+slide" class="d-block w-100">',
'caption' => '<h5>First slide label</h5><p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block']
]
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Second+slide" class="d-block w-100">',
'caption' => '<h5>Second slide label</h5><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block']
]
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Third+slide" class="d-block w-100">',
'caption' => '<h5>Third slide label</h5><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block']
]
]
]
]);
$expected = <<<HTML
<div id="w0" class="carousel slide" data-bs-ride="carousel">
<ol class="carousel-indicators"><li class="active" data-target="#w0" data-slide-to="0"></li>
<li data-target="#w0" data-slide-to="1"></li>
<li data-target="#w0" data-slide-to="2"></li></ol>
<div class="carousel-inner"><div class="carousel-item active"><img src="https://via.placeholder.com/800x400?text=First+slide" class="d-block w-100">
<div class="d-none d-md-block carousel-caption"><h5>First slide label</h5><p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p></div></div>
<div class="carousel-item"><img src="https://via.placeholder.com/800x400?text=Second+slide" class="d-block w-100">
<div class="d-none d-md-block carousel-caption"><h5>Second slide label</h5><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p></div></div>
<div class="carousel-item"><img src="https://via.placeholder.com/800x400?text=Third+slide" class="d-block w-100">
<div class="d-none d-md-block carousel-caption"><h5>Third slide label</h5><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p></div></div></div>
<a class="carousel-control-prev" href="#w0" data-slide="prev" role="button"><span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></a>
<a class="carousel-control-next" href="#w0" data-slide="next" role="button"><span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Next</span></a>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @depends testContainerOptions
*/
public function testCrossfade()
{
Carousel::$counter = 0;
$out = Carousel::widget([
'crossfade' => true,
'items' => [
[
'content' => '<img src="https://via.placeholder.com/800x400?text=First+slide" class="d-block w-100">',
'caption' => '<h5>First slide label</h5><p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block']
]
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Second+slide" class="d-block w-100">',
'caption' => '<h5>Second slide label</h5><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block']
]
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Third+slide" class="d-block w-100">',
'caption' => '<h5>Third slide label</h5><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block']
]
]
]
]);
$this->assertContains('class="carousel slide carousel-fade"', $out);
}
}

248
tests/DropdownTest.php Normal file
View File

@ -0,0 +1,248 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Dropdown;
/**
* Tests for Dropdown widget
*
* @group bootstrap5
*/
class DropdownTest extends TestCase
{
public function testIds()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'items' => [
[
'label' => 'Page1'
],
[
'label' => 'Dropdown1',
'url' => '#test',
'items' => [
['label' => 'Page2'],
['label' => 'Page3'],
]
],
[
'label' => 'Dropdown2',
'visible' => false,
'items' => [
['label' => 'Page4', 'content' => 'Page4'],
['label' => 'Page5', 'content' => 'Page5'],
]
]
]
]
);
$expected = <<<EXPECTED
<div id="w0" class="dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" href="#test" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button">Dropdown1</a>
<div id="w1" class="dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div>
</div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testSubMenuOptions()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'submenuOptions' => [
'class' => 'submenu-list',
],
'items' => [
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page1', 'content' => 'Page2'],
['label' => 'Page2', 'content' => 'Page3'],
]
],
'-',
[
'label' => 'Dropdown2',
'items' => [
['label' => 'Page3', 'content' => 'Page4'],
['label' => 'Page4', 'content' => 'Page5'],
],
'submenuOptions' => [
'class' => 'submenu-override',
],
]
]
]
);
$expected = <<<EXPECTED
<div id="w0" class="dropdown-menu"><div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button">Dropdown1</a>
<div id="w1" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<h6 class="dropdown-header">Page2</h6></div>
</div>
<div class="dropdown-divider"></div>
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button">Dropdown2</a>
<div id="w2" class="submenu-override dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page3</h6>
<h6 class="dropdown-header">Page4</h6></div>
</div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testActive()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'submenuOptions' => [
'class' => 'submenu-list',
],
'items' => [
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page1', 'content' => 'Page2'],
['label' => 'Page2', 'content' => 'Page3'],
]
],
'-',
[
'label' => 'Dropdown2',
'items' => [
['label' => 'Page3', 'content' => 'Page3', 'url' => '/', 'active' => true],
['label' => 'Page4', 'content' => 'Page4'],
],
]
]
]
);
$expected = <<<HTML
<div id="w0" class="dropdown-menu"><div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button">Dropdown1</a>
<div id="w1" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<h6 class="dropdown-header">Page2</h6></div>
</div>
<div class="dropdown-divider"></div>
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button">Dropdown2</a>
<div id="w2" class="submenu-list dropdown-submenu dropdown-menu"><a class="dropdown-item active" href="/">Page3</a>
<h6 class="dropdown-header">Page4</h6></div>
</div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testDisabled()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'submenuOptions' => [
'class' => 'submenu-list',
],
'items' => [
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page1', 'content' => 'Page2'],
['label' => 'Page2', 'content' => 'Page3'],
],
'disabled' => true
],
'-',
[
'label' => 'Dropdown2',
'items' => [
['label' => 'Page3', 'content' => 'Page3'],
['label' => 'Page4', 'content' => 'Page4'],
],
]
]
]
);
$expected = <<<HTML
<div id="w0" class="dropdown-menu"><div class="dropdown" aria-expanded="false">
<a class="dropdown-item disabled dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button" tabindex="-1" aria-disabled="true">Dropdown1</a>
<div id="w1" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<h6 class="dropdown-header">Page2</h6></div>
</div>
<div class="dropdown-divider"></div>
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button">Dropdown2</a>
<div id="w2" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page3</h6>
<h6 class="dropdown-header">Page4</h6></div>
</div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testForms()
{
Dropdown::$counter = 0;
$form = <<<HTML
<form class="px-4 py-3">
<div class="form-group">
<label for="exampleDropdownFormEmail1">Email address</label>
<input type="email" class="form-control" id="exampleDropdownFormEmail1" placeholder="email@example.com">
</div>
<div class="form-group">
<label for="exampleDropdownFormPassword1">Password</label>
<input type="password" class="form-control" id="exampleDropdownFormPassword1" placeholder="Password">
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="dropdownCheck">
<label class="form-check-label" for="dropdownCheck">
Remember me
</label>
</div>
<button type="submit" class="btn btn-primary">Sign in</button>
</form>
HTML;
$out = Dropdown::widget([
'items' => [
$form,
'-',
['label' => 'New around here? Sign up', 'url' => '#'],
['label' => 'Forgot password?', 'url' => '#']
]
]);
$expected = <<<HTML
<div id="w0" class="dropdown-menu"><form class="px-4 py-3">
<div class="form-group">
<label for="exampleDropdownFormEmail1">Email address</label>
<input type="email" class="form-control" id="exampleDropdownFormEmail1" placeholder="email@example.com">
</div>
<div class="form-group">
<label for="exampleDropdownFormPassword1">Password</label>
<input type="password" class="form-control" id="exampleDropdownFormPassword1" placeholder="Password">
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="dropdownCheck">
<label class="form-check-label" for="dropdownCheck">
Remember me
</label>
</div>
<button type="submit" class="btn btn-primary">Sign in</button>
</form>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">New around here? Sign up</a>
<a class="dropdown-item" href="#">Forgot password?</a></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

145
tests/HtmlTest.php Normal file
View File

@ -0,0 +1,145 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\Html;
/**
* @group bootstrap5
*/
class HtmlTest extends TestCase
{
/**
* @return array
*/
public function dataProviderStaticControl()
{
return [
[
'foo',
[],
'<input type="text" class="form-control-plaintext" value="foo" readonly>'
],
[
'<html>',
[],
'<input type="text" class="form-control-plaintext" value="&lt;html&gt;" readonly>'
]
];
}
/**
* @dataProvider dataProviderStaticControl
*
* @param string $value
* @param array $options
* @param string $expectedHtml
*/
public function testStaticControl($value, array $options, $expectedHtml)
{
$this->assertEquals($expectedHtml, Html::staticControl($value, $options));
}
public function testRadioList()
{
$this->assertEquals('<div></div>', Html::radioList('test'));
$dataItems = [
'value1' => 'text1',
'value2' => 'text2',
];
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="radio" id="i0" class="form-check-input" name="test" value="value1">
<label class="form-check-label" for="i0">text1</label></div>
<div class="form-check"><input type="radio" id="i1" class="form-check-input" name="test" value="value2" checked>
<label class="form-check-label" for="i1">text2</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $dataItems));
Html::$counter = 0;
$expected = <<<'EOD'
<div>0<label>text1 <input type="radio" name="test" value="value1"></label>
1<label>text2 <input type="radio" name="test" value="value2" checked></label></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $dataItems, [
'item' => function ($index, $label, $name, $checked, $value) {
return $index . Html::label($label . ' ' . Html::radio($name, $checked, ['value' => $value]));
},
]));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="radio" id="i0" class="form-check-input" name="test" value="value">
<label class="form-check-label" for="i0">label&amp;</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', [], ['value' => 'label&']));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="radio" id="i0" class="form-check-input" name="test" value="value">
<label class="form-check-label" for="i0">label&</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', [], ['value' => 'label&'], ['encode' => false]));
}
public function testCheckboxList()
{
$this->assertEquals('<div></div>', Html::checkboxList('test'));
$dataItems = [
'value1' => 'text1',
'value2' => 'text2',
];
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="checkbox" id="i0" class="form-check-input" name="test[]" value="value1">
<label class="form-check-label" for="i0">text1</label></div>
<div class="form-check"><input type="checkbox" id="i1" class="form-check-input" name="test[]" value="value2" checked>
<label class="form-check-label" for="i1">text2</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $dataItems));
Html::$counter = 0;
$expected = <<<'EOD'
<div>0<label>text1 <input type="checkbox" name="test[]" value="value1"></label>
1<label>text2 <input type="checkbox" name="test[]" value="value2" checked></label></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $dataItems, [
'item' => function ($index, $label, $name, $checked, $value) {
return $index . Html::label($label . ' ' . Html::checkbox($name, $checked, ['value' => $value]));
},
]));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="checkbox" id="i0" class="form-check-input" name="test[]" value="value" checked>
<label class="form-check-label" for="i0">label&amp;</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', 'value', ['value' => 'label&']));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="checkbox" id="i0" class="form-check-input" name="test[]" value="value" checked>
<label class="form-check-label" for="i0">label&</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', 'value', ['value' => 'label&'], ['encode' => false]));
}
public function testError()
{
$model = new DynamicModel();
$model->addError('foo', 'Some error message.');
$this->assertEquals('<div class="invalid-feedback">Some error message.</div>', Html::error($model, 'foo'));
$this->assertEquals('<div class="custom-class">Some error message.</div>', Html::error($model, 'foo', ['class' => 'custom-class']));
$this->assertEquals('<div>Some error message.</div>', Html::error($model, 'foo', ['class' => null]));
$this->assertEquals('<p class="invalid-feedback">Some error message.</p>', Html::error($model, 'foo', ['tag' => 'p']));
}
}

154
tests/LinkPagerTest.php Normal file
View File

@ -0,0 +1,154 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\LinkPager;
use yii\data\Pagination;
use yii\helpers\ReplaceArrayValue;
use yii\helpers\StringHelper;
/**
* @group bootstrap5
*/
class LinkPagerTest extends TestCase
{
protected function setUp()
{
parent::setUp();
$this->mockWebApplication([
'components' => [
'urlManager' => [
'scriptUrl' => '/',
],
],
]);
}
/**
* Get pagination.
* @param int $page
* @return Pagination
*/
private function getPagination($page)
{
$pagination = new Pagination();
$pagination->setPage($page);
$pagination->totalCount = 500;
$pagination->route = 'test';
return $pagination;
}
public function testFirstLastPageLabels()
{
$pagination = $this->getPagination(5);
$output = LinkPager::widget([
'pagination' => $pagination,
'firstPageLabel' => true,
'lastPageLabel' => true,
]);
$this->assertContains('<li class="page-item first"><a class="page-link" href="/?r=test&amp;page=1" data-page="0">1</a></li>', $output);
$this->assertContains('<li class="page-item last"><a class="page-link" href="/?r=test&amp;page=25" data-page="24">25</a></li>', $output);
$output = LinkPager::widget([
'pagination' => $pagination,
'firstPageLabel' => 'First',
'lastPageLabel' => 'Last',
]);
$this->assertContains('<li class="page-item first"><a class="page-link" href="/?r=test&amp;page=1" data-page="0">First</a></li>', $output);
$this->assertContains('<li class="page-item last"><a class="page-link" href="/?r=test&amp;page=25" data-page="24">Last</a></li>', $output);
$output = LinkPager::widget([
'pagination' => $pagination,
'firstPageLabel' => false,
'lastPageLabel' => false,
]);
$this->assertNotContains('<li class="page-item first">', $output);
$this->assertNotContains('<li class="page-item last">', $output);
}
public function testDisabledPageElementOptions()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(0),
'disabledListItemSubTagOptions' => ['class' => ['foo-bar']],
]);
$this->assertContains('<li class="page-item prev disabled"><a class="page-link foo-bar"', $output);
}
/**
* @depends testDisabledPageElementOptions
*/
public function testOverrideDisabledPageElementOptions()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(0),
'disabledListItemSubTagOptions' => ['class' => new ReplaceArrayValue(['foo-bar'])],
]);
$this->assertContains('<li class="page-item prev disabled"><a class="foo-bar"', $output);
}
public function testDisableCurrentPageButton()
{
$pagination = $this->getPagination(5);
$output = LinkPager::widget([
'pagination' => $pagination,
'disableCurrentPageButton' => false,
]);
$this->assertContains('<li class="page-item active"><a class="page-link" href="/?r=test&amp;page=6" data-page="5">6</a></li>', $output);
$output = LinkPager::widget([
'pagination' => $pagination,
'disableCurrentPageButton' => true,
]);
$this->assertContains('<li class="page-item active disabled"><a class="page-link" href="/?r=test&amp;page=6" data-page="5" tabindex="-1">6</a></li>', $output);
}
public function testOptionsWithTagOption()
{
LinkPager::$counter = 0;
$output = LinkPager::widget([
'pagination' => $this->getPagination(5),
'options' => [
'tag' => 'div',
],
]);
$this->assertTrue(StringHelper::startsWith($output, '<div id="w0">'));
$this->assertTrue(StringHelper::endsWith($output, '</div>'));
}
public function testLinkWrapOptions()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(1),
'linkContainerOptions' => [
'tag' => 'div',
'class' => 'my-class',
],
]);
$this->assertContains(
'<div class="my-class page-item"><a class="page-link" href="/?r=test&amp;page=3" data-page="2">3</a></div>',
$output
);
$this->assertContains(
'<div class="my-class page-item active"><a class="page-link" href="/?r=test&amp;page=2" data-page="1">2</a></div>',
$output
);
}
/**
* @see https://github.com/yiisoft/yii2/issues/15536
*/
public function testShouldTriggerInitEvent()
{
$initTriggered = false;
LinkPager::widget([
'pagination' => $this->getPagination(1),
'on init' => function () use (&$initTriggered) {
$initTriggered = true;
}
]);
$this->assertTrue($initTriggered);
}
}

195
tests/ModalTest.php Normal file
View File

@ -0,0 +1,195 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Html;
use yii\bootstrap5\Modal;
/**
* @group bootstrap5
*/
class ModalTest extends TestCase
{
public function testBodyOptions()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'bodyOptions' => ['class' => 'modal-body test', 'style' => 'text-align:center;']
]);
$expected = <<<HTML
<div id="w0" class="fade modal" role="dialog" tabindex="-1" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body test" style="text-align:center;">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @depends testBodyOptions
*/
public function testContainerOptions()
{
Modal::$counter = 0;
ob_start();
Modal::begin([
'title' => 'Modal title',
'footer' => Html::button('Close', [
'type' => 'button',
'class' => ['btn', 'btn-secondary'],
'data' => [
'dismiss' => 'modal'
]
]) . "\n" . Html::button('Save changes', [
'type' => 'button',
'class' => ['btn', 'btn-primary']
])
]);
echo '<p>Woohoo, you\'re reading this text in a modal!</p>';
Modal::end();
$out = ob_get_clean();
$expected = <<<HTML
<div id="w0" class="fade modal" role="dialog" tabindex="-1" aria-hidden="true" aria-labelledby="w0-label">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 id="w0-label" class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<p>Woohoo, you're reading this text in a modal!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testTriggerButton()
{
Modal::$counter = 0;
ob_start();
Modal::begin([
'toggleButton' => [
'class' => ['btn', 'btn-primary'],
'label' => 'Launch demo modal'
],
'title' => 'Modal title',
'footer' => Html::button('Close', [
'type' => 'button',
'class' => ['btn', 'btn-secondary']
]) . "\n" . Html::button('Save changes', [
'type' => 'button',
'class' => ['btn', 'btn-primary']
])
]);
echo '<p>Woohoo, you\'re reading this text in a modal!</p>';
Modal::end();
$out = ob_get_clean();
$this->assertContains('<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#w0">Launch demo modal</button>',
$out);
}
public function testDialogOptions()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'dialogOptions' => ['class' => 'test', 'style' => 'text-align:center;']
]);
$expected = <<<HTML
<div id="w0" class="fade modal" role="dialog" tabindex="-1" aria-hidden="true">
<div class="test modal-dialog" role="document" style="text-align:center;">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testCenterVertical()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'centerVertical'=>true
]);
$expected = <<<HTML
<div id="w0" class="fade modal" role="dialog" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testScrollable()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'scrollable'=>true
]);
$expected = <<<HTML
<div id="w0" class="fade modal" role="dialog" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

129
tests/NavBarTest.php Normal file
View File

@ -0,0 +1,129 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Nav;
use yii\bootstrap5\NavBar;
/**
* Tests for NavBar widget
*
* @group bootstrap5
*/
class NavBarTest extends TestCase
{
public function testRender()
{
NavBar::$counter = 0;
$out = NavBar::widget([
'brandLabel' => 'My Company',
'brandUrl' => '/',
'options' => [
'class' => 'navbar-inverse navbar-static-top navbar-frontend',
],
]);
$expected = <<<EXPECTED
<nav id="w0" class="navbar-inverse navbar-static-top navbar-frontend navbar">
<div class="container">
<a class="navbar-brand" href="/">My Company</a>
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#w0-collapse" aria-controls="w0-collapse" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div id="w0-collapse" class="collapse navbar-collapse">
</div>
</div>
</nav>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testBrandImage()
{
$out = NavBar::widget([
'brandImage' => '/images/test.jpg',
'brandUrl' => '/',
]);
$this->assertContains('<a class="navbar-brand" href="/"><img src="/images/test.jpg" alt=""></a>', $out);
}
public function testBrandLink()
{
$out = NavBar::widget([
'brandLabel' => 'Yii Framework',
'brandUrl' => false,
]);
$this->assertContains('<a class="navbar-brand" href="/index.php">Yii Framework</a>', $out);
}
public function testBrandSpan()
{
$out = NavBar::widget([
'brandLabel' => 'Yii Framework',
'brandUrl' => null,
]);
$this->assertContains('<span class="navbar-brand">Yii Framework</span>', $out);
}
/**
* @depends testRender
*/
public function testNavAndForm() {
NavBar::$counter = 0;
ob_start();
NavBar::begin([
'brandLabel' => 'My Company',
'brandUrl' => '/',
'options' => [
],
]);
echo Nav::widget([
'options' => [
'class' => ['mr-auto']
],
'items' => [
['label' => 'Home', 'url' => '#'],
['label' => 'Link', 'url' => '#'],
['label' => 'Dropdown', 'items' => [
['label' => 'Action', 'url' => '#'],
['label' => 'Another action', 'url' => '#'],
'-',
['label' => 'Something else here', 'url' => '#'],
]]
]
]);
echo <<<HTML
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
HTML;
NavBar::end();
$out = ob_get_clean();
$expected = <<<EXPECTED
<nav id="w0" class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="/">My Company</a>
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#w0-collapse" aria-controls="w0-collapse" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div id="w0-collapse" class="collapse navbar-collapse">
<ul id="w1" class="mr-auto nav"><li class="nav-item"><a class="nav-link" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">Link</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Dropdown</a><div id="w2" class="dropdown-menu"><a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a></div></li></ul><form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form></div>
</div>
</nav>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
}

368
tests/NavTest.php Normal file
View File

@ -0,0 +1,368 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Nav;
/**
* Tests for Nav widget
*
* @group bootstrap5
*/
class NavTest extends TestCase
{
protected function setUp()
{
$this->mockWebApplication([
'components' => [
'request' => [
'class' => 'yii\web\Request',
'scriptUrl' => '/base/index.php',
'hostInfo' => 'http://example.com/',
'url' => '/base/index.php&r=site%2Fcurrent&id=42'
],
'urlManager' => [
'class' => 'yii\web\UrlManager',
'baseUrl' => '/base',
'scriptUrl' => '/base/index.php',
'hostInfo' => 'http://example.com/',
]
],
]);
}
public function testIds()
{
Nav::$counter = 0;
$out = Nav::widget(
[
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page2', 'content' => 'Page2'],
['label' => 'Page3', 'content' => 'Page3'],
]
],
[
'label' => 'Dropdown2',
'visible' => false,
'items' => [
['label' => 'Page4', 'content' => 'Page4'],
['label' => 'Page5', 'content' => 'Page5'],
]
]
]
]
);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Page1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Dropdown1</a><div id="w1" class="dropdown-menu"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testRenderDropdownWithDropdownOptions()
{
Nav::$counter = 0;
$out = Nav::widget(
[
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Dropdown1',
'dropdownOptions' => ['class' => 'test', 'data-id' => 't1', 'id' => 'test1'],
'items' => [
['label' => 'Page2', 'content' => 'Page2'],
['label' => 'Page3', 'content' => 'Page3'],
]
],
[
'label' => 'Dropdown2',
'visible' => false,
'items' => [
['label' => 'Page4', 'content' => 'Page4'],
['label' => 'Page5', 'content' => 'Page5'],
]
]
]
]
);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Page1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Dropdown1</a><div id="test1" class="test dropdown-menu" data-id="t1"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testEmptyItems()
{
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Page1',
'items' => null,
],
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page2', 'content' => 'Page2'],
['label' => 'Page3', 'content' => 'Page3'],
],
],
[
'label' => 'Page4',
'items' => [],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Page1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Dropdown1</a><div id="w1" class="dropdown-menu"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div></li>
<li class="nav-item"><a class="nav-link" href="#">Page4</a></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testActive()
{
$this->mockAction('site', 'users');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Main',
'url' => ['site/index'],
],
[
'label' => 'Admin',
'items' => [
['label' => 'Users', 'url' => ['site/users']],
['label' => 'Roles', 'url' => ['site/roles']],
['label' => 'Statuses', 'url' => ['site/statuses']]
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="/base/index.php?r=site%2Findex">Main</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Admin</a><div id="w1" class="dropdown-menu"><a class="dropdown-item active" href="/base/index.php?r=site%2Fusers">Users</a>
<a class="dropdown-item" href="/base/index.php?r=site%2Froles">Roles</a>
<a class="dropdown-item" href="/base/index.php?r=site%2Fstatuses">Statuses</a></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testExplicitActive()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'activateItems' => false,
'items' => [
[
'label' => 'Item1',
'active' => true,
],
[
'label' => 'Item2',
'url' => ['site/index'],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Item1</a></li>
<li class="nav-item"><a class="nav-link" href="/base/index.php?r=site%2Findex">Item2</a></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testImplicitActive()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Item1',
'active' => true,
],
[
'label' => 'Item2',
'url' => ['site/index'],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link active" href="#">Item1</a></li>
<li class="nav-item"><a class="nav-link active" href="/base/index.php?r=site%2Findex">Item2</a></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testExplicitActiveSubitems()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'activateItems' => false,
'items' => [
[
'label' => 'Item1',
],
[
'label' => 'Item2',
'items' => [
['label' => 'Page2', 'content' => 'Page2', 'url' => ['site/index']],
['label' => 'Page3', 'content' => 'Page3', 'active' => true],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Item1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Item2</a><div id="w1" class="dropdown-menu"><a class="dropdown-item" href="/base/index.php?r=site%2Findex">Page2</a>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testImplicitActiveSubitems()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Item1',
],
[
'label' => 'Item2',
'items' => [
['label' => 'Page2', 'content' => 'Page2', 'url' => ['site/index']],
['label' => 'Page3', 'content' => 'Page3', 'active' => true],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Item1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Item2</a><div id="w1" class="dropdown-menu"><a class="dropdown-item active" href="/base/index.php?r=site%2Findex">Page2</a>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
public function testDisabled()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Item1',
'disabled' => true
],
[
'label' => 'Item2',
'items' => [
['label' => 'Page2', 'content' => 'Page2', 'url' => ['site/index'], 'disabled' => true],
['label' => 'Page3', 'content' => 'Page3', 'active' => true],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Item1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-toggle="dropdown">Item2</a><div id="w1" class="dropdown-menu"><a class="dropdown-item disabled" href="/base/index.php?r=site%2Findex" tabindex="-1" aria-disabled="true">Page2</a>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/96
* @see https://github.com/yiisoft/yii2-bootstrap/issues/157
*/
public function testDeepActivateParents()
{
Nav::$counter = 0;
$out = Nav::widget([
'activateParents' => true,
'items' => [
[
'label' => 'Dropdown',
'items' => [
[
'label' => 'Sub-dropdown',
'items' => [
['label' => 'Page', 'content' => 'Page', 'active' => true],
],
],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="dropdown nav-item"><a class="dropdown-toggle nav-link active" href="#" data-toggle="dropdown">Dropdown</a><div id="w1" class="dropdown-menu"><div class="dropdown active" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="button">Sub-dropdown</a>
<div id="w2" class="dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page</h6></div>
</div></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
}

98
tests/ProgressTest.php Normal file
View File

@ -0,0 +1,98 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Progress;
/**
* @group bootstrap5
*/
class ProgressTest extends TestCase
{
public function testSimpleRender()
{
Progress::$counter = 0;
$out = Progress::widget([
'label' => 'Progress',
'percent' => 25,
'barOptions' => ['class' => 'bg-warning']
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="bg-warning progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width: 25%;">Progress</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testRender()
{
Progress::$counter = 0;
$out = Progress::widget([
'bars' => [
['label' => 'Progress', 'percent' => 25]
]
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width: 25%;">Progress</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @depends testRender
*/
public function testMultiple()
{
Progress::$counter = 0;
$out = Progress::widget([
'bars' => [
['label' => '', 'percent' => 15],
['label' => '', 'percent' => 30, 'options' => ['class' => ['bg-success']]],
['label' => '', 'percent' => 20, 'options' => ['class' => ['bg-info']]]
]
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="15" aria-valuemin="0" aria-valuemax="100" style="width: 15%;"></div>
<div class="bg-success progress-bar" role="progressbar" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100" style="width: 30%;"></div>
<div class="bg-info progress-bar" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%;"></div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/121
*/
public function testRussianLocaleRendering()
{
$this->mockWebApplication([
'language' => 'ru-RU',
'sourceLanguage' => 'en-US',
]);
Progress::$counter = 0;
$out = Progress::widget([
'bars' => [
['label' => 'Progress', 'percent' => 25]
]
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width: 25%;">Progress</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

408
tests/TabsTest.php Normal file
View File

@ -0,0 +1,408 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Tabs;
use yii\helpers\Html;
/**
* Tests for Tabs widget
*
* @group bootstrap5
*/
class TabsTest extends TestCase
{
public function testRoleTablist()
{
Tabs::$counter = 0;
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Page2',
'content' => 'Page2',
],
]
]);
$this->assertContainsWithoutLE('<ul id="w0" class="nav nav-tabs" role="tablist">', $out);
}
/**
* Each tab should have a corresponding unique ID
*
* @see https://github.com/yiisoft/yii2/issues/6150
*/
public function testIds()
{
Tabs::$counter = 0;
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page2', 'content' => 'Page2'],
['label' => 'Page3', 'content' => 'Page3'],
]
],
[
'label' => 'Dropdown2',
'items' => [
['label' => 'Page4', 'content' => 'Page4'],
['label' => 'Page5', 'content' => 'Page5'],
]
],
[
'label' => $extAnchor1 = 'External link',
'url' => $extUrl1 = ['//other/route'],
],
[
'label' => 'Dropdown3',
'items' => [
[
'label' => $extAnchor2 = 'External Dropdown Link',
'url' => $extUrl2 = ['//other/dropdown/route']
],
]
],
]
]);
$page1 = 'w0-tab0';
$page2 = 'w0-dd1-tab0';
$page3 = 'w0-dd1-tab1';
$page4 = 'w0-dd2-tab0';
$page5 = 'w0-dd2-tab1';
$shouldContain = [
'w0', // nav widget container
"#$page1", // Page1
'w1', // Dropdown1
"$page2", // Page2
"$page3", // Page3
'w2', // Dropdown2
"#$page4", // Page4
"#$page5", // Page5
'w3', // Dropdown3
// containers
"id=\"$page1\"",
"id=\"$page2\"",
"id=\"$page3\"",
"id=\"$page4\"",
"id=\"$page5\"",
Html::a($extAnchor1, $extUrl1, ['class' => 'nav-link']),
Html::a($extAnchor2, $extUrl2, [/*'tabindex' => -1, */
'class' => 'dropdown-item'
]),
];
foreach ($shouldContain as $string) {
$this->assertContainsWithoutLE($string, $out);
}
}
public function testVisible()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'InvisiblePage',
'content' => 'Invisible Page Content',
'visible' => false
],
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page2', 'content' => 'Page2'],
['label' => 'InvisibleItem', 'content' => 'Invisible Item Content', 'visible' => false],
['label' => 'Page3', 'content' => 'Page3'],
['label' => 'External Link', 'url' => ['//other/dropdown/route']],
['label' => 'Invisible External Link', 'url' => ['//other/dropdown/route'], 'visible' => false],
]
],
]
]);
$this->assertNotContains('InvisiblePage', $html);
$this->assertNotContains('Invisible Page Content', $html);
$this->assertNotContains('InvisibleItem', $html);
$this->assertNotContains('Invisible Item Content', $html);
$this->assertNotContains('Invisible External Link', $html);
}
public function testDisabled()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
'disabled' => true
],
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'DisabledPage',
'content' => 'Disabled Page Content',
'disabled' => true
],
[
'label' => 'Dropdown1',
'items' => [
['label' => 'Page2', 'content' => 'Page2'],
['label' => 'DisabledItem', 'content' => 'Disabled Item Content', 'disabled' => true],
['label' => 'Page3', 'content' => 'Page3'],
['label' => 'External Link', 'url' => ['//other/dropdown/route']],
['label' => 'Disabled External Link', 'url' => ['//other/dropdown/route'], 'disabled' => true],
]
],
]
]);
$this->assertContains(
'<li class="nav-item"><a class="nav-link disabled" href="#w0-tab0" data-toggle="tab" role="tab" aria-controls="w0-tab0" tabindex="-1" aria-disabled="true">Page1</a></li>',
$html
);
$this->assertContains(
'<li class="nav-item"><a class="nav-link active" href="#w0-tab1" data-toggle="tab" role="tab" aria-controls="w0-tab1" aria-selected="true">Page2</a></li>',
$html
);
$this->assertContains(
'<li class="nav-item"><a class="nav-link disabled" href="#w0-tab2" data-toggle="tab" role="tab" aria-controls="w0-tab2" tabindex="-1" aria-disabled="true">DisabledPage</a></li>',
$html
);
$this->assertContains(
'<a class="dropdown-item disabled" href="#w0-dd3-tab1" data-toggle="tab" role="tab" aria-controls="w0-dd3-tab1" tabindex="-1" aria-disabled="true">DisabledItem</a>',
$html
);
$this->assertContains(
'<a class="dropdown-item disabled" href="/index.php?r=other%2Fdropdown%2Froute" tabindex="-1" aria-disabled="true">Disabled External Link</a>',
$html
);
}
public function testItem()
{
$checkTag = 'article';
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Page2',
'content' => 'Page2',
],
],
'itemOptions' => ['tag' => $checkTag],
'renderTabContent' => true,
]);
$this->assertContains('<' . $checkTag, $out);
}
public function testTabContentOptions()
{
$checkAttribute = "test_attribute";
$checkValue = "check_attribute";
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1'
]
],
'tabContentOptions' => [
$checkAttribute => $checkValue
]
]);
$this->assertContains($checkAttribute . '=', $out);
$this->assertContains($checkValue, $out);
}
public function testActivateFirstVisibleTab()
{
$html = Tabs::widget([
'id' => 'mytab',
'items' => [
[
'label' => 'Tab 1',
'content' => 'some content',
'visible' => false
],
[
'label' => 'Tab 2',
'content' => 'some content',
'disabled' => true
],
[
'label' => 'Tab 3',
'content' => 'some content'
],
[
'label' => 'Tab 4',
'content' => 'some content'
]
]
]);
$this->assertNotContains(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab0" data-toggle="tab" role="tab" aria-controls="mytab-tab0" aria-selected="true">Tab 1</a></li>',
$html
);
$this->assertNotContains(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab1" data-toggle="tab" role="tab" aria-controls="mytab-tab1" aria-selected="true">Tab 2</a></li>',
$html
);
$this->assertContains(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab2" data-toggle="tab" role="tab" aria-controls="mytab-tab2" aria-selected="true">Tab 3</a></li>',
$html
);
}
public function testActivateTab()
{
$html = Tabs::widget([
'id' => 'mytab',
'items' => [
[
'label' => 'Tab 1',
'content' => 'some content',
'visible' => false
],
[
'label' => 'Tab 2',
'content' => 'some content'
],
[
'label' => 'Tab 3',
'content' => 'some content',
'active' => true
],
[
'label' => 'Tab 4',
'content' => 'some content'
]
]
]);
$this->assertContains(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab2" data-toggle="tab" role="tab" aria-controls="mytab-tab2" aria-selected="true">Tab 3</a></li>',
$html
);
}
public function testTabLabelEncoding()
{
$html = Tabs::widget([
'encodeLabels' => false,
'id' => 'mytab',
'items' => [
[
'label' => 'Tab 1<span>encoded</span>',
'content' => 'some content',
'encode' => true,
],
[
'label' => 'Tab 2<span>not encoded</span>',
'content' => 'some content',
],
[
'label' => 'Tab 3<span>not encoded too</span>',
'content' => 'some content',
],
]
]);
$this->assertContains('&lt;span&gt;encoded&lt;/span&gt;', $html);
$this->assertContains('<span>not encoded</span>', $html);
$this->assertContains('<span>not encoded too</span>', $html);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/108#issuecomment-465219339
*/
public function testIdRendering()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'options' => ['id' => 'pane1'],
'label' => 'Tab 1',
'content' => '<div>Content 1</div>',
],
[
'label' => 'Tab 2',
'content' => '<div>Content 2</div>',
],
],
]);
$expected = <<<HTML
<ul id="w0" class="nav nav-tabs" role="tablist"><li class="nav-item"><a class="nav-link active" href="#pane1" data-toggle="tab" role="tab" aria-controls="pane1" aria-selected="true">Tab 1</a></li>
<li class="nav-item"><a class="nav-link" href="#w0-tab1" data-toggle="tab" role="tab" aria-controls="w0-tab1" aria-selected="false">Tab 2</a></li></ul>
<div class="tab-content"><div id="pane1" class="tab-pane active"><div>Content 1</div></div>
<div id="w0-tab1" class="tab-pane"><div>Content 2</div></div></div>
HTML;
$this->assertEquals($expected, $html);
}
public function testHeaderOptions()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'label' => 'Tab 1',
'content' => '<div>Content 1</div>',
],
[
'label' => 'Tab 2',
'content' => '<div>Content 2</div>',
'headerOptions' => ['class' => 'col-6'],
],
[
'label' => 'Link',
'url' => 'http://www.example.com/',
'headerOptions' => ['class' => 'col-3'],
],
],
'options' => ['class' => 'row'],
'headerOptions' => ['class' => 'col'],
]);
$expected = <<<HTML
<ul id="w0" class="row nav nav-tabs" role="tablist"><li class="col nav-item"><a class="nav-link active" href="#w0-tab0" data-toggle="tab" role="tab" aria-controls="w0-tab0" aria-selected="true">Tab 1</a></li>
<li class="col-6 nav-item"><a class="nav-link" href="#w0-tab1" data-toggle="tab" role="tab" aria-controls="w0-tab1" aria-selected="false">Tab 2</a></li>
<li class="col-3 nav-item"><a class="nav-link" href="http://www.example.com/">Link</a></li></ul>
<div class="tab-content"><div id="w0-tab0" class="tab-pane active"><div>Content 1</div></div>
<div id="w0-tab1" class="tab-pane"><div>Content 2</div></div></div>
HTML;
$this->assertEquals($expected, $html);
}
}

122
tests/TestCase.php Normal file
View File

@ -0,0 +1,122 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use Yii;
use yii\base\Action;
use yii\base\Module;
use yii\di\Container;
use yii\helpers\ArrayHelper;
use yii\web\Controller;
/**
* This is the base class for all yii framework unit tests.
*/
class TestCase extends \PHPUnit\Framework\TestCase
{
/**
* Asserting two strings equality ignoring line endings
*
* @param string $expected
* @param string $actual
*/
public function assertEqualsWithoutLE(string $expected, string $actual)
{
$expected = str_replace("\r\n", "\n", $expected);
$actual = str_replace("\r\n", "\n", $actual);
$this->assertEquals($expected, $actual);
}
/**
* Asserting two strings equality ignoring line endings
*
* @param string $needle
* @param string $haystack
*/
public function assertContainsWithoutLE(string $needle, string $haystack)
{
$needle = str_replace("\r\n", "\n", $needle);
$haystack = str_replace("\r\n", "\n", $haystack);
$this->assertContains($needle, $haystack);
}
/**
* {@inheritDoc}
*/
protected function setUp()
{
parent::setUp();
$this->mockWebApplication();
}
/**
* {@inheritDoc}
*/
protected function tearDown()
{
parent::tearDown();
$this->destroyApplication();
}
/**
* @param array $config
* @param string $appClass
*/
protected function mockWebApplication(array $config = [], string $appClass = '\yii\web\Application')
{
new $appClass(ArrayHelper::merge([
'id' => 'testapp',
'basePath' => __DIR__,
'vendorPath' => dirname(__DIR__) . '/vendor',
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
'components' => [
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ . '/index.php',
'scriptUrl' => '/index.php',
]
]
], $config));
}
/**
* Mocks controller action with parameters
*
* @param string $controllerId
* @param string $actionID
* @param string|null $moduleID
* @param array $params
*/
protected function mockAction(string $controllerId, string $actionID, string $moduleID = null, array $params = [])
{
Yii::$app->controller = $controller = new Controller($controllerId, Yii::$app);
$controller->actionParams = $params;
$controller->action = new Action($actionID, $controller);
if ($moduleID !== null) {
$controller->module = new Module($moduleID);
}
}
/**
* Removes controller
*/
protected function removeMockedAction()
{
Yii::$app->controller = null;
}
/**
* Destroys application in Yii::$app by setting it to null.
*/
protected function destroyApplication()
{
Yii::$app = null;
Yii::$container = new Container();
}
}

125
tests/ToastTest.php Normal file
View File

@ -0,0 +1,125 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Toast;
/**
* @group bootstrap5
*/
class ToastTest extends TestCase
{
public function testBodyOptions()
{
Toast::$counter = 0;
$out = Toast::widget([
'bodyOptions' => ['class' => 'toast-body test', 'style' => ['text-align' => 'center']]
]);
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto"></strong>
<button type="button" class="ml-2 mb-1 close" aria-label="Close" data-dismiss="toast">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="toast-body test" style="text-align: center;">
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @depends testBodyOptions
*/
public function testContainerOptions()
{
Toast::$counter = 0;
ob_start();
Toast::begin([
'title' => 'Toast title',
'dateTime' => time() - 60
]);
echo 'Woohoo, you\'re reading this text in a toast!';
Toast::end();
$out = ob_get_clean();
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto">Toast title</strong>
<small class="text-muted">a minute ago</small>
<button type="button" class="ml-2 mb-1 close" aria-label="Close" data-dismiss="toast">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="toast-body">
Woohoo, you're reading this text in a toast!
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testDateTimeOptions()
{
Toast::$counter = 0;
$out = Toast::widget([
'title' => 'Toast title',
'dateTime' => time() - 60,
'dateTimeOptions' => ['class' => ['toast-date-time'], 'style' => ['text-align' => 'right']]
]);
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto">Toast title</strong>
<small class="toast-date-time text-muted" style="text-align: right;">a minute ago</small>
<button type="button" class="ml-2 mb-1 close" aria-label="Close" data-dismiss="toast">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="toast-body">
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testTitleOptions()
{
Toast::$counter = 0;
$out = Toast::widget([
'title' => 'Toast title',
'titleOptions' => ['tag' => 'h5', 'style' => ['text-align' => 'left']]
]);
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<h5 class="mr-auto" style="text-align: left;">Toast title</h5>
<button type="button" class="ml-2 mb-1 close" aria-label="Close" data-dismiss="toast">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="toast-body">
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,94 @@
<?php
namespace yiiunit\extensions\bootstrap5;
use yii\base\Model;
use yii\bootstrap5\Html;
use yii\bootstrap5\ToggleButtonGroup;
/**
* @group bootstrap5
*/
class ToggleButtonGroupTest extends TestCase
{
public function testCheckbox()
{
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_CHECKBOX,
'model' => new ToggleButtonGroupTestModel(),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$expectedHtml = <<<HTML
<input type="hidden" name="ToggleButtonGroupTestModel[value]" value=""><div id="togglebuttongrouptestmodel-value" class="btn-group-toggle" data-toggle="buttons"><label class="btn btn-secondary" for="i0"><input type="checkbox" id="i0" name="ToggleButtonGroupTestModel[value][]" value="1" autocomplete="off">item 1</label>
<label class="btn btn-secondary" for="i1"><input type="checkbox" id="i1" name="ToggleButtonGroupTestModel[value][]" value="2" autocomplete="off">item 2</label></div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
* @depends testCheckbox
*/
public function testCheckboxChecked() {
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_CHECKBOX,
'model' => new ToggleButtonGroupTestModel(['value' => '2']),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$this->assertContains('<input type="checkbox" id="i1" name="ToggleButtonGroupTestModel[value][]" value="2" checked autocomplete="off">', $html);
}
public function testRadio()
{
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_RADIO,
'model' => new ToggleButtonGroupTestModel(),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$expectedHtml = <<<HTML
<input type="hidden" name="ToggleButtonGroupTestModel[value]" value=""><div id="togglebuttongrouptestmodel-value" class="btn-group-toggle" data-toggle="buttons"><label class="btn btn-secondary" for="i0"><input type="radio" id="i0" name="ToggleButtonGroupTestModel[value]" value="1" autocomplete="off">item 1</label>
<label class="btn btn-secondary" for="i1"><input type="radio" id="i1" name="ToggleButtonGroupTestModel[value]" value="2" autocomplete="off">item 2</label></div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
* @depends testRadio
*/
public function testRadioChecked() {
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_RADIO,
'model' => new ToggleButtonGroupTestModel(['value' => '2']),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$this->assertContains('<input type="radio" id="i1" name="ToggleButtonGroupTestModel[value]" value="2" checked autocomplete="off">', $html);
}
}
class ToggleButtonGroupTestModel extends Model
{
public $value;
}

2
tests/assets/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

14
tests/bootstrap.php Normal file
View File

@ -0,0 +1,14 @@
<?php
// ensure we get report on all possible php errors
error_reporting(-1);
const YII_ENABLE_ERROR_HANDLER = false;
const YII_DEBUG = true;
$_SERVER['SCRIPT_NAME'] = '/' . __DIR__;
$_SERVER['SCRIPT_FILENAME'] = __FILE__;
require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
Yii::setAlias('@yiiunit/extensions/bootstrap5', __DIR__);
Yii::setAlias('@yii/bootstrap5', dirname(__DIR__) . '/src');

View File

@ -0,0 +1,23 @@
<?php
namespace yiiunit\extensions\bootstrap5\data;
use yii\bootstrap5\ActiveField;
/**
* A customized extension from ActiveField
*
* @see \yiiunit\extensions\bootstrap5\ActiveFieldTest::testHorizontalCssClassesOverride()
*
* @author Michael Härtl <haertl.mike@gmail.com>
*/
class ExtendedActiveField extends ActiveField
{
public ?array $horizontalCssClasses = [
'offset' => 'col-md-offset-4',
'label' => 'col-md-4',
'wrapper' => 'col-md-6',
'error' => 'col-md-3',
'hint' => 'col-md-3',
];
}

27
tests/data/Singer.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace yiiunit\extensions\bootstrap5\data;
use yii\base\Model;
/**
* Class Singer
*
* @author Daniel Gomez Pan <pana_1990@hotmail.com>
*/
class Singer extends Model
{
public $firstName;
public $lastName;
public $test;
public function rules()
{
return [
[['lastName'], 'default', 'value' => 'Lennon'],
[['lastName'], 'required'],
[['underscore_style'], 'yii\captcha\CaptchaValidator'],
[['test'], 'required', 'when' => function($model) { return $model->firstName === 'cebe'; }],
];
}
}

41
tests/data/User.php Normal file
View File

@ -0,0 +1,41 @@
<?php
/**
* @package yii2-bootstrap5
* @author Simon Karlen <simi.albi@outlook.com>
*/
namespace yiiunit\extensions\bootstrap5\data;
use yii\base\Model;
class User extends Model
{
public $firstName;
public $lastName;
public $username;
public $password;
/**
* {@inheritdoc}
*/
public function rules()
{
return [
['username', 'string', 'min' => 4],
['password', 'string', 'min' => 8, 'max' => '20'],
[['username', 'password'], 'required']
];
}
/**
* {@inheritdoc}
*/
public function attributeHints()
{
return [
'username' => 'Your username must be at least 4 characters long',
'password' => 'Your password must be 8-20 characters long, contain letters and numbers, and must not contain spaces, special characters, or emoji.'
];
}
}