├── .gitignore ├── tests ├── assets │ └── .gitignore └── src │ ├── BaseBootstrap4BlockTestCase.php │ ├── BaseBootstrap4WidgetTestCase.php │ ├── tags │ └── TooltipTagTest.php │ ├── widgets │ ├── BreadcrumbsTest.php │ └── LinkPagerTest.php │ ├── blocks │ ├── ImageBlockTest.php │ └── CarouselBlockTest.php │ └── ActiveFormTest.php ├── src ├── blockgroups │ └── BootstrapGroup.php ├── BaseBootstrap4Block.php ├── Bootstrap4Asset.php ├── Module.php ├── grid │ ├── GridView.php │ └── ActionColumn.php ├── ActiveField.php ├── tags │ └── TooltipTag.php ├── widgets │ ├── Breadcrumbs.php │ └── LinkPager.php ├── views │ └── blocks │ │ ├── ImageBlock.php │ │ └── CarouselBlock.php ├── ActiveForm.php ├── blocks │ ├── ImageBlock.php │ └── CarouselBlock.php └── messages │ ├── pl │ └── bootstrap4.php │ ├── en │ └── bootstrap4.php │ ├── ru │ └── bootstrap4.php │ ├── de │ └── bootstrap4.php │ ├── id │ └── bootstrap4.php │ ├── pt │ └── bootstrap4.php │ └── fr │ └── bootstrap4.php ├── actions.phpunit.xml ├── LICENSE.md ├── composer.json ├── .github └── workflows │ └── tests.yml ├── README.md └── CHANGELOG.md /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/ 2 | /.buildpath 3 | /.project 4 | /.idea 5 | /vendor/ 6 | /luya 7 | composer.lock -------------------------------------------------------------------------------- /tests/assets/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Ignore everything in this directory 3 | * 4 | # Except this file 5 | !.gitignore -------------------------------------------------------------------------------- /src/blockgroups/BootstrapGroup.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class BootstrapGroup extends \luya\cms\base\BlockGroup 12 | { 13 | public function identifier() 14 | { 15 | return 'bootstrap4'; 16 | } 17 | 18 | public function label() 19 | { 20 | return 'Bootstrap 4'; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BaseBootstrap4Block.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 1.0.0 14 | */ 15 | abstract class BaseBootstrap4Block extends PhpBlock 16 | { 17 | /** 18 | * @inheritdoc 19 | */ 20 | public function getViewPath() 21 | { 22 | return dirname(__DIR__) . '/src/views/blocks'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Bootstrap4Asset.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class Bootstrap4Asset extends \yii\web\AssetBundle 12 | { 13 | public $js = [ 14 | ['//stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.bundle.min.js', 'integrity' => 'sha384-6khuMg9gaYr5AxOqhkVIODVIvm9ynTT5J4V1cfthmT+emCG6yVmEZsRHdxlotUnm', 'crossorigin' => 'anonymous'], 15 | ]; 16 | 17 | public $css = [ 18 | ['//stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css', 'integrity' => 'sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh', 'crossorigin' => 'anonymous'], 19 | ]; 20 | 21 | 22 | public $depends = [ 23 | 'yii\web\JqueryAsset', 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /actions.phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | ./tests 14 | 15 | 16 | 17 | 18 | ./vendor 19 | ./tests 20 | 21 | 22 | ./src 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Module.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class Module extends \luya\base\Module 16 | { 17 | /** 18 | * @inheritdoc 19 | */ 20 | public static function onLoad() 21 | { 22 | Yii::setAlias('@bootstrap4', static::staticBasePath()); 23 | 24 | self::registerTranslation('bootstrap4*', static::staticBasePath() . '/messages', [ 25 | 'bootstrap4' => 'bootstrap4.php', 26 | ]); 27 | } 28 | 29 | /** 30 | * Translations 31 | * 32 | * @param string $message 33 | * @param array $params 34 | * @return string 35 | */ 36 | public static function t($message, array $params = []) 37 | { 38 | return parent::baseT('bootstrap4', $message, $params); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/src/BaseBootstrap4BlockTestCase.php: -------------------------------------------------------------------------------- 1 | 'bootstrap4test', 13 | 'basePath' => dirname(__DIR__) . '/../', 14 | 'aliases' => [ 15 | '@app' => 'app_path', 16 | ], 17 | 'components' => [ 18 | 'assetManager' => [ 19 | 'basePath' => dirname(__DIR__) . '/assets', 20 | 'bundles' => [ 21 | 'yii\web\JqueryAsset' => false, 22 | 'luya\bootstrap4\Bootstrap4Asset' => false, 23 | ], 24 | ], 25 | 'storage' => [ 26 | 'class' => 'luya\admin\filesystem\DummyFileSystem', 27 | 'filesArray' => [], 28 | 'imagesArray' => [], 29 | ], 30 | ] 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/grid/GridView.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class GridView extends \yii\grid\GridView 14 | { 15 | /** 16 | * Apply class `table-responsive` if enabled. 17 | */ 18 | public $responsive = false; 19 | 20 | /** 21 | * @var array the HTML attributes for the grid table element. 22 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 23 | */ 24 | public $tableOptions = ['class' => 'table table-striped table-bordered']; 25 | 26 | /** 27 | * @inheritdoc 28 | */ 29 | public $pager = ['class' => LinkPager::class]; 30 | 31 | /** 32 | * @inheritdoc 33 | */ 34 | public function init() 35 | { 36 | parent::init(); 37 | 38 | if ($this->responsive) { 39 | $this->tableOptions['class'] = $this->tableOptions['class'] . ' table-responsive'; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/src/BaseBootstrap4WidgetTestCase.php: -------------------------------------------------------------------------------- 1 | 'bs4app', 15 | 'basePath' => dirname(__DIR__) . '/../', 16 | 'components' => [ 17 | 'assetManager' => [ 18 | 'basePath' => dirname(__DIR__) . '/assets', 19 | 'bundles' => [ 20 | 'yii\web\JqueryAsset' => false, 21 | 'luya\bootstrap4\Bootstrap4Asset' => false, 22 | ], 23 | ], 24 | 'storage' => [ 25 | 'class' => 'luya\admin\filesystem\DummyFileSystem', 26 | 'filesArray' => [], 27 | 'imagesArray' => [], 28 | ], 29 | 'composition' => null 30 | ] 31 | ]; 32 | } 33 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014-2021 Zephir Software Design AG. https://luya.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/ActiveField.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class ActiveField extends \yii\widgets\ActiveField 14 | { 15 | /** 16 | * @inheritdoc 17 | */ 18 | public $hintOptions = ['class' => 'form-text text-muted', 'tag' => 'small']; 19 | 20 | /** 21 | * @inheritdoc 22 | */ 23 | public $errorOptions = ['class' => 'invalid-feedback']; 24 | 25 | /** 26 | * Checkbox rendered as switch 27 | * 28 | * @param array $options 29 | * @return self 30 | * @see https://getbootstrap.com/docs/4.2/components/forms/#switches 31 | * @since 1.0.4 32 | */ 33 | public function checkboxSwitch($options = []) 34 | { 35 | $this->label(false); 36 | $this->parts['{input}'] = '
37 | '.Html::activeCheckbox($this->model, $this->attribute, array_merge(['label' => null, 'class' => 'custom-control-input'], $options)).' 38 | 39 |
'; 40 | 41 | return $this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/src/tags/TooltipTagTest.php: -------------------------------------------------------------------------------- 1 | 'mytestapp', 14 | 'basePath' => dirname(__DIR__), 15 | 'aliases' => [ 16 | '@app' => 'app_path', 17 | ], 18 | 'components' => [ 19 | 'assetManager' => [ 20 | 'basePath' => dirname(__DIR__) . '/../assets', 21 | 'bundles' => [ 22 | 'yii\web\JqueryAsset' => false, 23 | 'luya\bootstrap4\Bootstrap4Asset' => false, 24 | ], 25 | ], 26 | 'storage' => [ 27 | 'class' => 'luya\admin\filesystem\DummyFileSystem', 28 | 'filesArray' => [], 29 | 'imagesArray' => [], 30 | ], 31 | ] 32 | ]; 33 | } 34 | 35 | public function testTag() 36 | { 37 | $tag = new TooltipTag(); 38 | $this->assertSame('link', $tag->parse('link', 'text')); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/grid/ActionColumn.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.0 13 | */ 14 | class ActionColumn extends \yii\grid\ActionColumn 15 | { 16 | public function init() 17 | { 18 | // do not call parent is then the glyphicons button would be added 19 | $this->initBs4Icons('view', 'fa-search-plus'); 20 | $this->initBs4Icons('update', 'fa-edit'); 21 | $this->initBs4Icons('delete', 'fa-trash', [ 22 | 'data-confirm' => Yii::t('yii', 'Are you sure you want to delete this item?'), 23 | 'data-method' => 'post', 24 | ]); 25 | } 26 | 27 | protected function initBs4Icons($name, $iconName, $options = []) 28 | { 29 | if (!isset($this->buttons[$name]) && strpos($this->template, '{' . $name . '}') !== false) { 30 | $this->buttons[$name] = function ($url, $model, $key) use ($name, $iconName, $options) { 31 | $title = Yii::t('yii', ucfirst($name)); 32 | $options = array_merge([ 33 | 'title' => $title, 34 | 'aria-label' => $title, 35 | 'data-pjax' => '0', 36 | ], $options, $this->buttonOptions); 37 | $icon = Html::tag('i', '', ['class' => "fa $iconName", 'aria-hidden' => true]); 38 | return Html::a($icon, $url, $options); 39 | }; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "luyadev/luya-bootstrap4", 3 | "description": "Bootstrap4 Assets and Helper classes like ActiveForm for LUYA and Yii2.", 4 | "type": "luya-extension", 5 | "keywords": [ 6 | "php", 7 | "luya", 8 | "module", 9 | "cms", 10 | "yii2", 11 | "bootstrap", 12 | "bootstrap4", 13 | "twbs4", 14 | "luya-module", 15 | "bootstrap4", 16 | "bootstrap", 17 | "assets" 18 | ], 19 | "license": "MIT", 20 | "homepage": "https://luya.io", 21 | "authors": [ 22 | { 23 | "name": "Basil", 24 | "email": "git@nadar.io", 25 | "homepage": "https://github.com/nadar" 26 | } 27 | ], 28 | "support": { 29 | "issues": "https://github.com/luyadev/luya-bootstrap4/issues" 30 | }, 31 | "require": { 32 | "luyadev/luya-core": ">=1.6" 33 | }, 34 | "require-dev": { 35 | "luyadev/luya-testsuite": "^3.0", 36 | "luyadev/luya-module-cms": "^4.0", 37 | "luyadev/luya-module-admin": "^4.0" 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "luya\\bootstrap4\\": "src/" 42 | } 43 | }, 44 | "autoload-dev": { 45 | "psr-4": { 46 | "luya\\bootstrap4\\tests\\": "tests/" 47 | } 48 | }, 49 | "extra": { 50 | "luya": { 51 | "blocks": [ 52 | "src{{DS}}blocks" 53 | ] 54 | } 55 | }, 56 | "config": { 57 | "fxp-asset": { 58 | "enabled": false 59 | }, 60 | "allow-plugins": { 61 | "yiisoft/yii2-composer": true, 62 | "luyadev/luya-composer": true 63 | } 64 | }, 65 | "repositories": [ 66 | { 67 | "type": "composer", 68 | "url": "https://asset-packagist.org" 69 | } 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /src/tags/TooltipTag.php: -------------------------------------------------------------------------------- 1 | [ 16 | * 'tooltip' => ['class' => 'luya\bootstrap4\tags\TooltipTag'], 17 | * ], 18 | * ``` 19 | * 20 | * @author Basil Suter 21 | * @since 1.0.0 22 | */ 23 | class TooltipTag extends BaseTag 24 | { 25 | /** 26 | * @var string Whether it should possition: top, bottom, left, right. You can configure this while setup the tag. 27 | */ 28 | public $position = 'top'; 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function init() 34 | { 35 | parent::init(); 36 | $this->view->registerJs('$(\'[data-toggle="tooltip"]\').tooltip()', View::POS_READY); 37 | } 38 | 39 | /** 40 | * @inheritDoc 41 | */ 42 | public function example() 43 | { 44 | return 'tooltip[Tooltip on Top](This is the tooltip text!)'; 45 | } 46 | 47 | /** 48 | * @inheritDoc 49 | */ 50 | public function readme() 51 | { 52 | return 'Generate a Tooltip element over a text (span) Element.'; 53 | } 54 | 55 | /** 56 | * @inheritDoc 57 | */ 58 | public function parse($value, $sub) 59 | { 60 | return Html::tag('span', $value, [ 61 | 'data-toggle' => 'tooltip', 62 | 'title' => $sub, 63 | 'data-placement' => $this->position, 64 | 'class' => 'tooltip-info-span', 65 | ]); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/widgets/Breadcrumbs.php: -------------------------------------------------------------------------------- 1 | 12 | * 13 | * 14 | * 18 | * 23 | * ``` 24 | * 25 | * @author Basil Suter 26 | * @since 1.0.0 27 | */ 28 | class Breadcrumbs extends \yii\widgets\Breadcrumbs 29 | { 30 | /** 31 | * @var string the name of the breadcrumb container tag. 32 | */ 33 | public $tag = 'ol'; 34 | 35 | /** 36 | * @var array the HTML attributes for the breadcrumb container tag. 37 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 38 | */ 39 | public $options = ['class' => 'breadcrumb']; 40 | 41 | /** 42 | * @var string the template used to render each inactive item in the breadcrumbs. The token `{link}` 43 | * will be replaced with the actual HTML link for each inactive item. 44 | */ 45 | public $itemTemplate = "
  • {link}
  • \n"; 46 | 47 | /** 48 | * @var string the template used to render each active item in the breadcrumbs. The token `{link}` 49 | * will be replaced with the actual HTML link for each active item. 50 | */ 51 | public $activeItemTemplate = "
  • {link}
  • \n"; 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | env: 4 | DEFAULT_COMPOSER_FLAGS: "--prefer-dist --no-interaction" 5 | CC_TEST_REPORTER_ID: e5b2383e4b8cb691696f61c6de9d18afcb7fc53d36949295b35da1fb384d8632 6 | jobs: 7 | phpunit: 8 | name: PHP ${{ matrix.php }} on ${{ matrix.os }} 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | os: [ubuntu-latest] 14 | php: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] 15 | 16 | steps: 17 | ## checkout the repoistory 18 | - name: Checkout Repo 19 | uses: actions/checkout@v2 20 | 21 | ## Install(?) php 22 | - name: Install PHP 23 | uses: shivammathur/setup-php@v2 24 | with: 25 | php-version: ${{ matrix.php }} 26 | extensions: curl, dom, imagick, intl, mbstring, mcrypt, mysql, pdo, pdo_mysql, pdo_pgsql, pdo_sqlite, pgsql, sqlite 27 | ini-values: date.timezone='UTC' 28 | 29 | ## install composer 30 | - name: Install dependencies 31 | run: composer install $DEFAULT_COMPOSER_FLAGS 32 | 33 | ## run unit tests 34 | - name: PHP Unit tests for PHP 35 | run: vendor/bin/phpunit --verbose --configuration actions.phpunit.xml 36 | if: matrix.php == '8.1' || matrix.php == '8.0' || matrix.php == '7.4' || matrix.php == '7.3' || matrix.php == '7.2' || matrix.php == '7.0' 37 | 38 | ## unit test with coverage 39 | - name: PHP Unit tests for PHP 7.1 40 | run: vendor/bin/phpunit --verbose --coverage-clover=clover.xml --configuration actions.phpunit.xml 41 | if: matrix.php == '7.1' 42 | 43 | ## coverage 44 | - name: Code coverage 45 | run: | 46 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter 47 | chmod +x ./cc-test-reporter 48 | ./cc-test-reporter after-build -t clover 49 | if: matrix.php == '7.1' 50 | continue-on-error: true # if is fork -------------------------------------------------------------------------------- /src/views/blocks/ImageBlock.php: -------------------------------------------------------------------------------- 1 | extraValue('image'); 8 | * @param $this->varValue('align'); 9 | * @param $this->varValue('showCaption'); 10 | * @param $this->varValue('image'); 11 | * @param $this->cfgValue('lazyload'); 12 | * 13 | * @var $this \luya\cms\base\PhpBlockView 14 | */ 15 | use luya\lazyload\LazyLoad; 16 | 17 | $align = $this->varValue('align', 'left'); 18 | ?> 19 | 20 | extraValue('image', false)): ?> 21 |
    22 |
    23 | caption)) { 25 | $caption = $image->caption; 26 | } else { 27 | $caption = ''; 28 | } 29 | if ($this->cfgValue('lazyload', false)): 30 | $options['src'] = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='; 31 | if (!empty($caption)) { 32 | $options['alt'] = $caption; 33 | $options['title'] = $caption; 34 | } 35 | echo LazyLoad::widget([ 36 | 'src' => $image->source, 37 | 'extraClass' => 'figure-img img-fluid', 38 | 'width' => $image->itemArray['resolution_width'], 39 | 'height' => $image->itemArray['resolution_height'], 40 | 'options' => $options 41 | ]); 42 | else: ?> 43 | alt=""> 44 | 45 | varValue('showCaption', false) && !empty($caption)): ?> 46 |
    47 | 48 |
    49 |
    50 | 51 | -------------------------------------------------------------------------------- /src/ActiveForm.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | class ActiveForm extends \yii\widgets\ActiveForm 17 | { 18 | /** 19 | * @var string Using different style themes: 20 | * 21 | * + default: Default layout with labels at the top of the fields. 22 | * + horizontal: Horizontal layout set the labels left to the fields. 23 | */ 24 | public $layout = 'default'; 25 | 26 | /** 27 | * @var string Change the validation state to the input field. 28 | */ 29 | public $validationStateOn = self::VALIDATION_STATE_ON_INPUT; 30 | 31 | /** 32 | * @var string The error Summary alert class 33 | */ 34 | public $errorSummaryCssClass = 'error-summary alert alert-danger'; 35 | 36 | /** 37 | * @inheritdoc 38 | */ 39 | public $fieldClass = 'luya\bootstrap4\ActiveField'; 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public $errorCssClass = 'is-invalid'; 45 | 46 | /** 47 | * @inheritdoc 48 | */ 49 | public $successCssClass = 'is-valid'; 50 | 51 | /** 52 | * @inheritdoc 53 | */ 54 | public function init() 55 | { 56 | if ($this->layout == 'horizontal') { 57 | $this->provideHorizontalLayout(); 58 | } 59 | 60 | parent::init(); 61 | } 62 | 63 | /** 64 | * Change the configuration of the active field and form based on the horizontal inputs. 65 | * 66 | * Bootstrap 4 Example Output: 67 | * 68 | * ```php 69 | *
    70 | * 71 | *
    72 | * 73 | *
    74 | *
    75 | * ``` 76 | */ 77 | protected function provideHorizontalLayout() 78 | { 79 | $this->options = ['class' => 'form-group row']; 80 | $this->fieldConfig = [ 81 | 'options' => [ 82 | 'class' => 'form-group row', 83 | ], 84 | 'labelOptions' => [ 85 | 'class' => 'col-sm-2 col-form-label', 86 | ], 87 | 'template' => "{label}\n
    {input}\n{hint}\n{error}
    ", 88 | ]; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/src/widgets/BreadcrumbsTest.php: -------------------------------------------------------------------------------- 1 | assertContainsTrimmed('', ob_get_clean()); 17 | } 18 | 19 | public function testWidgetOutputWithoutLink() 20 | { 21 | $links = []; 22 | 23 | ob_start(); 24 | ob_implicit_flush(false); 25 | echo Breadcrumbs::widget(['links' => $links]); 26 | 27 | $this->assertContainsTrimmed('', ob_get_clean()); 28 | } 29 | 30 | public function testWidgetOutputWithOneLink() 31 | { 32 | $links = [ 33 | [ 34 | 'label' => 'Label 1', 35 | 'url' => 'link1' 36 | ] 37 | ]; 38 | 39 | ob_start(); 40 | ob_implicit_flush(false); 41 | echo Breadcrumbs::widget(['links' => $links]); 42 | 43 | $this->assertContainsTrimmed('', ob_get_clean()); 47 | } 48 | 49 | public function testWidgetOutputWithMultipleLinks() 50 | { 51 | $links = [ 52 | [ 53 | 'label' => 'Label 1', 54 | 'url' => 'link1' 55 | ], 56 | [ 57 | 'label' => 'Label 2', 58 | 'url' => 'link2' 59 | ], 60 | ]; 61 | 62 | ob_start(); 63 | ob_implicit_flush(false); 64 | echo Breadcrumbs::widget(['links' => $links]); 65 | 66 | $this->assertContainsTrimmed('', ob_get_clean()); 71 | } 72 | 73 | public function testWidgetOutputWithoutHomeLink() 74 | { 75 | $links = [ 76 | [ 77 | 'label' => 'Label 1', 78 | 'url' => 'link1' 79 | ], 80 | [ 81 | 'label' => 'Label 2', 82 | 'url' => 'link2' 83 | ], 84 | ]; 85 | 86 | ob_start(); 87 | ob_implicit_flush(false); 88 | echo Breadcrumbs::widget(['links' => $links, 'homeLink' => false]); 89 | 90 | $this->assertContainsTrimmed('', ob_get_clean()); 94 | } 95 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

    2 | LUYA Logo 3 |

    4 | 5 | # Bootstrap 4 6 | 7 | [![LUYA](https://img.shields.io/badge/Powered%20by-LUYA-brightgreen.svg)](https://luya.io) 8 | ![Tests](https://github.com/luyadev/luya-bootstrap4/workflows/Tests/badge.svg) 9 | [![Test Coverage](https://api.codeclimate.com/v1/badges/a5356371e27bf46c2329/test_coverage)](https://codeclimate.com/github/luyadev/luya-bootstrap4/test_coverage) 10 | [![Latest Stable Version](https://poser.pugx.org/luyadev/luya-bootstrap4/v/stable)](https://packagist.org/packages/luyadev/luya-bootstrap4) 11 | [![Total Downloads](https://poser.pugx.org/luyadev/luya-bootstrap4/downloads)](https://packagist.org/packages/luyadev/luya-bootstrap4) 12 | [![Forum Support](https://img.shields.io/badge/Slack-luyadev-yellowgreen.svg)](https://forum.luya.io/) 13 | 14 | Wrapper classes for new [Bootstrap 4](https://getbootstrap.com/) CSS Framework for [Yii](https://yiiframework.com) and/or [LUYA](https://luya.io). 15 | 16 | > As of Bootstrap 4, the grid is completely written in FLEX. Check the [Browser Support](https://caniuse.com/#search=flex) to decide if you want to use Bootstrap 4 for your project. 17 | 18 | This package contains the following components: 19 | 20 | + Widgets 21 | + ActiveForm Widget (Yii ActiveForm Widget matching the Bootstrap 4 form styles) 22 | + Breadcrumbs 23 | + LinkPager 24 | + ActiveField Widget 25 | + Grid View / Action Column 26 | + Tags 27 | + Tooltips 28 | + CMS Blocks 29 | + Image 30 | + Carousel 31 | + Asset File (contains precompiled bootstrap4 css and js files via cdn) 32 | 33 | ## Installation 34 | 35 | Add the package to your project via composer 36 | 37 | ```sh 38 | composer require luyadev/luya-bootstrap4:^1.0 39 | ``` 40 | 41 | ## Assets Bundle 42 | 43 | To use the css and js files of bootstrap just register the `Bootstrap4Asset` into your layout file with the following code of your layout.php file: 44 | 45 | ```php 46 | luya\bootstrap4\Bootstrap4Asset::register($this) 47 | ``` 48 | 49 | At the top section of your layout file. This will include all required css and js files to use bootstrap 4 and set the right depenecy with jquery. 50 | 51 | ## Active Form 52 | 53 | A common way to build forms is the use thy Yii ActiveForm widget, to match all bootstrap4 components use it like following: 54 | 55 | ```php 56 | 63 |

    Bootstrap 4 ActiveForm

    64 | 65 | field($model, 'username') ?> 66 | field($model, 'password')->passwordInput() ?> 67 | 'btn btn-primary-outline']) ?> 68 | 69 | ``` 70 | 71 | Tip: In order to style required fields with asterisks, you can use the following CSS: 72 | 73 | ```css 74 | div.required label.control-label:after { 75 | content: " *"; 76 | color: red; 77 | } 78 | ``` 79 | -------------------------------------------------------------------------------- /src/widgets/LinkPager.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class LinkPager extends \yii\widgets\LinkPager 12 | { 13 | /** 14 | * @var array HTML attributes for the pager container tag. 15 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 16 | */ 17 | public $options = ['class' => 'pagination']; 18 | 19 | /** 20 | * @var array HTML attributes for the link in a pager container tag. 21 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 22 | */ 23 | public $linkOptions = ['class' => 'page-link']; 24 | /** 25 | * @var string the CSS class for the each page button. 26 | * @since 2.0.7 27 | */ 28 | public $pageCssClass = 'page-item'; 29 | /** 30 | * @var string the CSS class for the "first" page button. 31 | */ 32 | public $firstPageCssClass = ''; 33 | /** 34 | * @var string the CSS class for the "last" page button. 35 | */ 36 | public $lastPageCssClass = ''; 37 | /** 38 | * @var string the CSS class for the "previous" page button. 39 | */ 40 | public $prevPageCssClass = 'page-item'; 41 | /** 42 | * @var string the CSS class for the "next" page button. 43 | */ 44 | public $nextPageCssClass = 'page-item'; 45 | /** 46 | * @var string the CSS class for the active (currently selected) page button. 47 | */ 48 | public $activePageCssClass = 'active'; 49 | /** 50 | * @var string the CSS class for the disabled page buttons. 51 | */ 52 | public $disabledPageCssClass = 'disabled'; 53 | 54 | /** 55 | * @inheritdoc 56 | */ 57 | public $disabledListItemSubTagOptions = ['class' => 'page-link', 'tag' => 'a']; 58 | 59 | /** 60 | * @var int maximum number of page buttons that can be displayed. Defaults to 10. 61 | */ 62 | public $maxButtonCount = 10; 63 | /** 64 | * @var string|bool the label for the "next" page button. Note that this will NOT be HTML-encoded. 65 | * If this property is false, the "next" page button will not be displayed. 66 | */ 67 | public $nextPageLabel = '»'; 68 | /** 69 | * @var string|bool the text label for the previous page button. Note that this will NOT be HTML-encoded. 70 | * If this property is false, the "previous" page button will not be displayed. 71 | */ 72 | public $prevPageLabel = '«'; 73 | /** 74 | * @var string|bool the text label for the "first" page button. Note that this will NOT be HTML-encoded. 75 | * If it's specified as true, page number will be used as label. 76 | * Default is false that means the "first" page button will not be displayed. 77 | */ 78 | public $firstPageLabel = false; 79 | /** 80 | * @var string|bool the text label for the "last" page button. Note that this will NOT be HTML-encoded. 81 | * If it's specified as true, page number will be used as label. 82 | * Default is false that means the "last" page button will not be displayed. 83 | */ 84 | public $lastPageLabel = false; 85 | } 86 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # LUYA BOOTSTRAP 4 CHANGELOG 2 | 3 | All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). 4 | In order to read more about upgrading and BC breaks have a look at the [UPGRADE Document](UPGRADE.md). 5 | 6 | ## 1.1.2 (9. December 2021) 7 | 8 | + Small changes in docs, translations, composer dependencies 9 | 10 | ## 1.1.1 (27. July 2021) 11 | 12 | + Allow LUYA Core Version 2.0 13 | 14 | ## 1.1.0 (28. July 2020) 15 | 16 | + [#30](https://github.com/luyadev/luya-bootstrap4/pull/30) Added widget tests 17 | + [#29](https://github.com/luyadev/luya-bootstrap4/pull/29) CarouselBlock: Added config variable to use LazyLoad; adjusted CarouselBlock tests 18 | + [#28](https://github.com/luyadev/luya-bootstrap4/issues/28) Image block: Added config variable to use LazyLoad; added `alt` and `title` attribute. 19 | + Adjust library requirements to `luyadev/luya-core >= 1.6` in composer dependencies. 20 | + Remove Travis and replaced by GitHub Actions 21 | 22 | ## 1.0.4 (6. May 2020) 23 | 24 | + Update CDN links from 4.3.1 to 4.4.1. 25 | + Added new `checkboxSwitch()` option for ActiveField in Bootstrap 4 Form Widget. 26 | + Added PHP 7.4 tests to Travis. 27 | 28 | ## 1.0.3 (22. October 2019) 29 | 30 | + [#25](https://github.com/luyadev/luya-bootstrap4/pull/26) Fixed bug with none unique accordion ids. 31 | + New PT translations. 32 | 33 | ## 1.0.2.2 (23. September 2019) 34 | 35 | + Fixed bug with Carousel block when multiple blocks are on the same Page. 36 | 37 | ## 1.0.2.1 (31. July 2019) 38 | 39 | + Fixed bug in carousel block when using indicators. 40 | 41 | ## 1.0.2 (6. June 2019) 42 | 43 | + Update to latest bootstrap 4.3.1 version. 44 | + Added field help info for carousel block. 45 | + Use {{DS}} separator for block paths. 46 | + [#22](https://github.com/luyadev/luya-bootstrap4/issues/22) Added the link (around the image). Changed the caption property away from image to slide. Added caption CSS class posibility. 47 | 48 | ## 1.0.1.1 (1. January 2019) 49 | 50 | + [#24](https://github.com/luyadev/luya-bootstrap4/issues/24) Fixed tooltip tag and added test. 51 | 52 | ## 1.0.1 (3. December 2018) 53 | 54 | + [#20](https://github.com/luyadev/luya-bootstrap4/pull/20) Russian translations. 55 | + [#19](https://github.com/luyadev/luya-bootstrap4/pull/19) Polish translations. 56 | + [#18](https://github.com/luyadev/luya-bootstrap4/issues/18) Update to Bootstrap version 4.1.3, use js bundle file. 57 | 58 | ## 1.0.0 (18. July 2018) 59 | 60 | + [#10](https://github.com/luyadev/luya-bootstrap4/issues/10) Update to Bootstrap 4.1 61 | + [#3](https://github.com/luyadev/luya-bootstrap4/issues/3) Use new Bootstrap 4 form validation classes. 62 | + [#7](https://github.com/luyadev/luya-bootstrap4/issues/7) Added Image block. 63 | + [#5](https://github.com/luyadev/luya-bootstrap4/issues/5) Add carousel block. 64 | + [#4](https://github.com/luyadev/luya-bootstrap4/issues/4) Move old blocks into luya legacy repo. 65 | 66 | ## 1.0.0-RC7 (28. January 2018) 67 | 68 | + Bootstrap 4 stable resources 69 | 70 | ## 1.0.0-RC6 (4. January 2018) 71 | 72 | + Bootstrap 4 beta 3 resources 73 | 74 | ## 1.0.0-RC5 (4. January 2018) 75 | 76 | + Bootstrap 4 beta 2 resources 77 | + Added block icons. 78 | + [#2](https://github.com/luyadev/luya-bootstrap4/issues/2) Fixed issue when using block without enable the module in the config, therefore the bootstrap4 alias is missing for the block view files. 79 | 80 | ## 1.0.0-RC4 (9. September 2017) 81 | 82 | + Fixed general issues for new LUYA RC4 release. 83 | -------------------------------------------------------------------------------- /src/blocks/ImageBlock.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 1.0.0 17 | */ 18 | class ImageBlock extends PhpBlock 19 | { 20 | /** 21 | * @var string The module where this block belongs to in order to find the view files. 22 | */ 23 | public $module = 'bootstrap4'; 24 | 25 | /** 26 | * @var bool Choose whether a block can be cached trough the caching component. Be carefull with caching container blocks. 27 | */ 28 | public $cacheEnabled = true; 29 | 30 | /** 31 | * @var int The cache lifetime for this block in seconds (3600 = 1 hour), only affects when cacheEnabled is true 32 | */ 33 | public $cacheExpiration = 3600; 34 | 35 | /** 36 | * @inheritDoc 37 | */ 38 | public function blockGroup() 39 | { 40 | return MediaGroup::class; 41 | } 42 | 43 | /** 44 | * @inheritDoc 45 | */ 46 | public function name() 47 | { 48 | return Module::t('block_image.block_name'); 49 | } 50 | 51 | /** 52 | * @inheritDoc 53 | */ 54 | public function icon() 55 | { 56 | return 'image'; // see the list of icons on: https://material.io/icons/ 57 | } 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public function config() 63 | { 64 | return [ 65 | 'vars' => [ 66 | ['var' => 'image', 'label' => Module::t('block_image.image'), 'type' => self::TYPE_IMAGEUPLOAD, 'options' => ['no_filter' => false]], 67 | ['var' => 'align', 'label' => Module::t('block_image.align'), 'type' => self::TYPE_SELECT, 'options' => BlockHelper::selectArrayOption(['left' => Module::t('block_image.align_left'), 'center' => Module::t('block_image.align_center'), 'right' => Module::t('block_image.align_right')])], 68 | ['var' => 'showCaption', 'label' => Module::t('block_image.show_caption'), 'type' => self::TYPE_CHECKBOX], 69 | ], 70 | 'cfgs' => [ 71 | ['var' => 'lazyload', 'label' => Module::t('block_image.lazyload'), 'type' => self::TYPE_CHECKBOX] 72 | ] 73 | ]; 74 | } 75 | 76 | /** 77 | * @inheritDoc 78 | */ 79 | public function extraVars() 80 | { 81 | return [ 82 | 'image' => BlockHelper::imageUpload($this->getVarValue('image'), false, true), 83 | ]; 84 | } 85 | 86 | /** 87 | * {@inheritDoc} 88 | * 89 | * @param {{extras.image}} 90 | * @param {{vars.align}} 91 | * @param {{vars.showCaption}} 92 | * @param {{vars.image}} 93 | */ 94 | public function admin() 95 | { 96 | return '
    97 |
    98 |
    99 | 100 |
    101 | {% if vars.showCaption and extras.image.caption %} 102 |

    {{extras.image.caption}}

    103 | {% endif %} 104 |
    105 |
    '; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/messages/pl/bootstrap4.php: -------------------------------------------------------------------------------- 1 | 'Lista plików', 7 | 'block_file_list.files_label' => 'Pliki', 8 | 'block_file_list.show_type_label' => 'Wyświetl typ pliku', 9 | 'block_file_list.show_type_icon' => 'Wyświetl ikonę typu pliku', 10 | 'block_file_list.show_file_size' => 'Wyświetlaj rozmiar pliku', 11 | 12 | 'block_image.block_name' => 'Obraz', 13 | 'block_image.image' => 'Obraz', 14 | 'block_image.align' => 'Pozycja obrazu', 15 | 'block_image.align_left' => 'W lewo', 16 | 'block_image.align_right' => 'Prawo', 17 | 'block_image.align_center' => 'Center', 18 | 'block_image.show_caption' => 'Pokaż podpis', 19 | 20 | 'block_layout.block_name' => 'Układ: wiersz', 21 | 'block_layout.content' => 'Treść wiersza', 22 | 23 | 'block_layout_column.block_name' => 'Układ: Kolumna', 24 | 'block_layout_column.column_count' => 'Rozmiar XS w górę', 25 | 'block_layout_column.column_count_sm' => 'Rozmiar SM up', 26 | 'block_layout_column.column_count_md' => 'Rozmiar MD w górę', 27 | 'block_layout_column.column_count_lg' => 'Rozmiar LG w górę', 28 | 'block_layout_column.column_count_xl' => 'Rozmiar XL w górę', 29 | 'block_layout_column.content' => 'Zawartość kolumny', 30 | 31 | 'block_carousel.items' => 'Slajdy', 32 | 'block_carousel.block_name' => 'Karuzela', 33 | 'block_carousel.title' => 'Tytuł', 34 | 'block_carousel.caption' => 'Podpis pod obrazem', 35 | 'block_carousel.image' => 'Obraz', 36 | 'block_carousel.image_link' => 'Link', 37 | 38 | 'block_image_text.block_name' => 'Obraz z tekstem', 39 | 'block_image_text.image_position' => 'Pozycja obrazu', 40 | 'block_image_text.left' => 'W lewo', 41 | 'block_image_text.right' => 'Right', 42 | 'block_image_text.center' => 'Wyśrodkowany', 43 | 'block_image_text.image_shape' => 'Kształt obrazu', 44 | 'block_image_text.no_shape' => 'Brak kształtu', 45 | 'block_image_text.rounded_corners' => 'Zaokrąglone rogi', 46 | 'block_image_text.thumbnail' => 'Miniatura z ramką', 47 | 'block_image_text.circle' => 'Circle', 48 | 'block_image_text.image' => 'Obraz', 49 | 'block_image_text.image.width' => 'Szerokość obrazu', 50 | 'block_image_text.image.caption' => 'Podpis obrazu', 51 | 'block_image_text.image.caption.visibility' => 'Pokaż podpis obrazu', 52 | 'block_image_text.help' => 'Dodaj obrazy i tekst do opakowania dynamicznego', 53 | 'block_image_text.no_text' => 'Żaden tekst nie został jeszcze dodany.', 54 | 'block_image_text.no_image' => 'Nie dodano jeszcze obrazu.', 55 | 'block_image_text.link' => 'Link do obrazu', 56 | 'block_image_text.file' => 'Załącz plik', 57 | 'block_image_text.file_download' => 'Pobierz plik za pomocą obrazu', 58 | 59 | 'block_inlinetext.name' => 'Blok tekstu śródliniowego', 60 | 'block_inlinetext.empty' => 'Żaden tekst nie został jeszcze dodany.', 61 | 'block_inlinetext.size-sm' => 'Rozmiar mobilny', 62 | 'block_inlinetext.size-md' => 'Rozmiar tabletu', 63 | 'block_inlinetext.size-lg' => 'Rozmiar pulpitu', 64 | 'block_inlinetext.size-full' => 'Pełna szerokość', 65 | 'block_inlinetext.size' => 'szerokość', 66 | 67 | 'block_inline_wrapper.label' => 'Umieść tu bloki wbudowane ...', 68 | 'block_inline_wrapper.name' => 'Blokada kontenera śródliniowego', 69 | 70 | 'block_carousel.config_controls' => 'Sterowanie', 71 | 'block_carousel.config_indicators' => 'Wskaźniki', 72 | 'block_carousel.config_crossfade' => 'Crossfade', 73 | 'block_carousel.config_interval' => 'Interval', 74 | 'block_carousel.config_keyboard' => 'Klawiatura', 75 | 'block_carousel.config_pause' => 'Pauza', 76 | 'block_carousel.config_ride' => 'Ride', 77 | 'block_carousel.config_wrap' => 'Zawijaj', 78 | 'block_carousel.config_row' => 'Wiersz', 79 | ]; 80 | -------------------------------------------------------------------------------- /src/messages/en/bootstrap4.php: -------------------------------------------------------------------------------- 1 | 'Files List', 7 | 'block_file_list.files_label' => 'Files', 8 | 'block_file_list.show_type_label' => 'Display file type', 9 | 'block_file_list.show_type_icon' => 'Display file type icon', 10 | 'block_file_list.show_file_size' => 'Display file size', 11 | 12 | 'block_image.block_name' => 'Image', 13 | 'block_image.image' => 'Image', 14 | 'block_image.align' => 'Image position', 15 | 'block_image.align_left' => 'Left', 16 | 'block_image.align_right' => 'Right', 17 | 'block_image.align_center' => 'Center', 18 | 'block_image.show_caption' => 'Show caption', 19 | 'block_image.lazyload' => 'LazyLoad', 20 | 21 | 'block_layout.block_name' => 'Layout: Row', 22 | 'block_layout.content' => 'Row content', 23 | 24 | 'block_layout_column.block_name' => 'Layout: Column', 25 | 'block_layout_column.column_count' => 'Size XS up', 26 | 'block_layout_column.column_count_sm' => 'Size SM up', 27 | 'block_layout_column.column_count_md' => 'Size MD up', 28 | 'block_layout_column.column_count_lg' => 'Size LG up', 29 | 'block_layout_column.column_count_xl' => 'Size XL up', 30 | 'block_layout_column.content' => 'Column content', 31 | 32 | 'block_carousel.items' => 'Slides', 33 | 'block_carousel.block_name' => 'Carousel', 34 | 'block_carousel.title' => 'Title', 35 | 'block_carousel.caption' => 'Image caption', 36 | 'block_carousel.image' => 'Image', 37 | 'block_carousel.image_link' => 'Link', 38 | 39 | 'block_image_text.block_name' => 'Image with Text', 40 | 'block_image_text.image_position' => 'Image position', 41 | 'block_image_text.left' => 'Left', 42 | 'block_image_text.right' => 'Right', 43 | 'block_image_text.center' => 'Centered', 44 | 'block_image_text.image_shape' => 'Image shape', 45 | 'block_image_text.no_shape' => 'No shape', 46 | 'block_image_text.rounded_corners' => 'Rounded corners', 47 | 'block_image_text.thumbnail' => 'Thumbnail with border', 48 | 'block_image_text.circle' => 'Circle', 49 | 'block_image_text.image' => 'Image', 50 | 'block_image_text.image.width' => 'Image width', 51 | 'block_image_text.image.caption' => 'Image caption', 52 | 'block_image_text.image.caption.visibility' => 'Show image caption', 53 | 'block_image_text.help' => 'Add Images and text into a dynamic layout wrapper', 54 | 'block_image_text.no_text' => 'No text has been added yet.', 55 | 'block_image_text.no_image' => 'No image has been added yet.', 56 | 'block_image_text.link' => 'Image link', 57 | 'block_image_text.file' => 'Attach file', 58 | 'block_image_text.file_download' => 'Download file via image', 59 | 60 | 'block_inlinetext.name'=> 'Inline Text Block', 61 | 'block_inlinetext.empty'=> 'No text has been added yet.', 62 | 'block_inlinetext.size-sm'=> 'Size mobile', 63 | 'block_inlinetext.size-md'=> 'Size tablet', 64 | 'block_inlinetext.size-lg'=> 'Size desktop', 65 | 'block_inlinetext.size-full'=> 'Full width', 66 | 'block_inlinetext.size'=> 'width', 67 | 68 | 'block_inline_wrapper.label'=>'Place inline blocks here ...', 69 | 'block_inline_wrapper.name'=>'Inline Block Container', 70 | 71 | 'block_carousel.config_block_css_class' => 'Block CSS Class', 72 | 'block_carousel.config_caption_css_class' => 'Caption CSS Class', 73 | 'block_carousel.config_controls' => 'Controls', 74 | 'block_carousel.config_indicators' => 'Indicators', 75 | 'block_carousel.config_crossfade' => 'Crossfade', 76 | 'block_carousel.config_interval' => 'Interval', 77 | 'block_carousel.config_keyboard' => 'Keyboard', 78 | 'block_carousel.config_pause' => 'Pause', 79 | 'block_carousel.config_ride' => 'Ride', 80 | 'block_carousel.config_wrap' => 'Wrap', 81 | 'block_carousel.config_row' => 'Row', 82 | 'block_carousel.lazyload' => 'LazyLoad' 83 | ]; 84 | -------------------------------------------------------------------------------- /src/messages/ru/bootstrap4.php: -------------------------------------------------------------------------------- 1 | 'Cписок файлов', 7 | 'block_file_list.files_label' => 'Файлы', 8 | 'block_file_list.show_type_label' => 'Показать тип файла', 9 | 'block_file_list.show_type_icon' => 'Показать иконку типа файла', 10 | 'block_file_list.show_file_size' => 'Показать размер файла', 11 | 12 | 'block_image.block_name' => 'Изображение', 13 | 'block_image.image' => 'Изображение', 14 | 'block_image.align' => 'Положение изображения', 15 | 'block_image.align_left' => 'Слева', 16 | 'block_image.align_right' => 'Справа', 17 | 'block_image.align_center' => 'По центру', 18 | 'block_image.show_caption' => 'Показывать заголовок', 19 | 20 | 'block_layout.block_name' => 'Макет: строка', 21 | 'block_layout.content' => 'Контент в строке', 22 | 23 | 'block_layout_column.block_name' => 'Макет: колонка', 24 | 'block_layout_column.column_count' => 'Размер XS up', 25 | 'block_layout_column.column_count_sm' => 'Размер SM up', 26 | 'block_layout_column.column_count_md' => 'Размер MD up', 27 | 'block_layout_column.column_count_lg' => 'Размер LG up', 28 | 'block_layout_column.column_count_xl' => 'Размер XL up', 29 | 'block_layout_column.content' => 'Контент в колонке', 30 | 31 | 'block_carousel.items' => 'Слайды', 32 | 'block_carousel.block_name' => 'Карусель', 33 | 'block_carousel.title' => 'Заголовок', 34 | 'block_carousel.caption' => 'Показывать заголовок', 35 | 'block_carousel.image' => 'Изображение', 36 | 'block_carousel.image_link' => 'Ссылка', 37 | 38 | 'block_image_text.block_name' => 'Изображение с текстом', 39 | 'block_image_text.image_position' => 'Позиция изображения', 40 | 'block_image_text.left' => 'Слева', 41 | 'block_image_text.right' => 'Справа', 42 | 'block_image_text.center' => 'По центру', 43 | 'block_image_text.image_shape' => 'Форма изображения', 44 | 'block_image_text.no_shape' => 'Нет формы', 45 | 'block_image_text.rounded_corners' => 'Округленные углы', 46 | 'block_image_text.thumbnail' => 'Миниатюра с рамкой', 47 | 'block_image_text.circle' => 'Круг', 48 | 'block_image_text.image' => 'Изображение', 49 | 'block_image_text.image.width' => 'Ширина изображения', 50 | 'block_image_text.image.caption' => 'Заголовок изображения', 51 | 'block_image_text.image.caption.visibility' => 'Отобразить заголовок изображения', 52 | 'block_image_text.help' => 'Добавление изображений и текста в динамическую обертку макета', 53 | 'block_image_text.no_text' => 'Текст еще не добавлен.', 54 | 'block_image_text.no_image' => 'Изображение еще не добавлено.', 55 | 'block_image_text.link' => 'Ссылка на изображение', 56 | 'block_image_text.file' => 'Прикрепить файл', 57 | 'block_image_text.file_download' => 'Загрузить файл через изображение', 58 | 59 | 'block_inlinetext.name'=> 'Встроенные текстовый блок', 60 | 'block_inlinetext.empty'=> 'Текст еще не был добавлен.', 61 | 'block_inlinetext.size-sm'=> 'Размер для мобильных устройств', 62 | 'block_inlinetext.size-md'=> 'Размер для планшетов', 63 | 'block_inlinetext.size-lg'=> 'Размер для настольных компьютеров', 64 | 'block_inlinetext.size-full'=> 'Полная ширина', 65 | 'block_inlinetext.size'=> 'ширина', 66 | 67 | 'block_inline_wrapper.label'=>'Разместить здесь встроенные блоки ...', 68 | 'block_inline_wrapper.name'=>'Контейнер встроенного блока', 69 | 70 | 'block_carousel.config_controls' => 'Элементы управления', 71 | 'block_carousel.config_indicators' => 'Индикатор', 72 | 'block_carousel.config_crossfade' => 'Перекрестное затухание', 73 | 'block_carousel.config_interval' => 'Интервал', 74 | 'block_carousel.config_keyboard' => 'Клавиатура', 75 | 'block_carousel.config_pause' => 'Пауза', 76 | 'block_carousel.config_ride' => 'Режим пролистывания', 77 | 'block_carousel.config_wrap' => 'Обертка', 78 | 'block_carousel.config_row' => 'Строка' 79 | ]; 80 | -------------------------------------------------------------------------------- /src/messages/de/bootstrap4.php: -------------------------------------------------------------------------------- 1 | 'Dateiliste', 7 | 'block_file_list.files_label' => 'Dateien', 8 | 'block_file_list.show_type_label' => 'Dateityp anzeigen', 9 | 'block_file_list.show_type_icon' => 'Dateityp-Icon anzeigen', 10 | 'block_file_list.show_file_size' => 'Dateigrösse anzeigen', 11 | 12 | 'block_image.block_name' => 'Bild', 13 | 'block_image.image' => 'Bild', 14 | 'block_image.align' => 'Bildposition', 15 | 'block_image.align_left' => 'Links', 16 | 'block_image.align_right' => 'Rechts', 17 | 'block_image.align_center' => 'Mittig', 18 | 'block_image.show_caption' => 'Bildlegende anzeigen', 19 | 'block_image.lazyload' => 'LazyLoad', 20 | 21 | 'block_layout.block_name' => 'Layout: Row', 22 | 'block_layout.content' => 'Row Inhalt', 23 | 24 | 'block_layout_column.block_name' => 'Layout: Column', 25 | 'block_layout_column.column_count' => 'Grösse XS aufwärts', 26 | 'block_layout_column.column_count_sm' => 'Grösse SM aufwärts', 27 | 'block_layout_column.column_count_md' => 'Grösse MD aufwärts', 28 | 'block_layout_column.column_count_lg' => 'Grösse LG aufwärts', 29 | 'block_layout_column.column_count_xl' => 'Grösse XL aufwärts', 30 | 'block_layout_column.content' => 'Column Inhalt', 31 | 32 | 'block_carousel.items' => 'Slides', 33 | 'block_carousel.block_name' => 'Carousel', 34 | 'block_carousel.title' => 'Titel', 35 | 'block_carousel.caption' => 'Bildunterschrift', 36 | 'block_carousel.image' => 'Bild', 37 | 'block_carousel.image_link' => 'Link', 38 | 39 | 'block_image_text.block_name' => 'Bild mit Text', 40 | 'block_image_text.image_position' => 'Bildposition', 41 | 'block_image_text.left' => 'Links', 42 | 'block_image_text.right' => 'Rechts', 43 | 'block_image_text.center' => 'Zentriert', 44 | 'block_image_text.image_shape' => 'Bildform', 45 | 'block_image_text.no_shape' => 'Keine Form', 46 | 'block_image_text.rounded_corners' => 'Abgerundete Ecken', 47 | 'block_image_text.thumbnail' => 'Thumbnail mit Umrandung', 48 | 'block_image_text.circle' => 'Kreis', 49 | 'block_image_text.image' => 'Bild', 50 | 'block_image_text.image.width' => 'Bildbreite', 51 | 'block_image_text.image.caption' => 'Bildlegende', 52 | 'block_image_text.image.caption.visibility' => 'Bildlegende anzeigen', 53 | 'block_image_text.help' => 'Bilder mit Text positionieren', 54 | 'block_image_text.no_text' => 'Es wurde noch kein Text hinzugefügt.', 55 | 'block_image_text.no_image' => 'Es wurde noch kein Bild hinzugefügt.', 56 | 'block_image_text.link' => 'Bild verlinken', 57 | 'block_image_text.file' => 'Datei', 58 | 'block_image_text.file_download' => 'Dateidownload via Bild', 59 | 60 | 'block_inlinetext.name'=> 'Inline Textblock', 61 | 'block_inlinetext.empty'=> 'Noch kein Text hinzugefügt', 62 | 'block_inlinetext.size-sm'=> 'Grösse Mobile', 63 | 'block_inlinetext.size-md'=> 'Grösse Tablet', 64 | 'block_inlinetext.size-lg'=> 'Grösse Desktop', 65 | 'block_inlinetext.size-full'=> 'Volle Breite', 66 | 'block_inlinetext.size'=> 'Breite', 67 | 68 | 'block_inline_wrapper.label'=>'Inline Blöcke hier platzieren ...', 69 | 'block_inline_wrapper.name'=>'Inline Textblock Raster', 70 | 71 | 'block_carousel.config_block_css_class' => 'Block CSS Klasse', 72 | 'block_carousel.config_caption_css_class' => 'Caption CSS Klasse', 73 | 'block_carousel.config_controls' => 'Controls', 74 | 'block_carousel.config_indicators' => 'Indicators', 75 | 'block_carousel.config_crossfade' => 'Crossfade', 76 | 'block_carousel.config_interval' => 'Interval', 77 | 'block_carousel.config_keyboard' => 'Keyboard', 78 | 'block_carousel.config_pause' => 'Pause', 79 | 'block_carousel.config_ride' => 'Ride', 80 | 'block_carousel.config_wrap' => 'Wrap', 81 | 'block_carousel.config_row' => 'Row', 82 | 'block_carousel.lazyload' => 'LazyLoad' 83 | ]; 84 | -------------------------------------------------------------------------------- /src/messages/id/bootstrap4.php: -------------------------------------------------------------------------------- 1 | 'List File', 7 | 'block_file_list.files_label' => 'File', 8 | 'block_file_list.show_type_label' => 'Tampilkan tipe file', 9 | 'block_file_list.show_type_icon' => 'Tampilkan tipe ikon file', 10 | 'block_file_list.show_file_size' => 'Tampilkan besar file', 11 | 12 | 'block_image.block_name' => 'Gambar', 13 | 'block_image.image' => 'Gambar', 14 | 'block_image.align' => 'Posisi Gambar', 15 | 'block_image.align_left' => 'Kiri', 16 | 'block_image.align_right' => 'Kanan', 17 | 'block_image.align_center' => 'Tengah', 18 | 'block_image.show_caption' => 'Tampilkan caption', 19 | 'block_image.lazyload' => 'LazyLoad', 20 | 21 | 'block_layout.block_name' => 'Layout: Baris', 22 | 'block_layout.content' => 'konten baris', 23 | 24 | 'block_layout_column.block_name' => 'Layout: Kolom', 25 | 'block_layout_column.column_count' => 'Ukuran XS up', 26 | 'block_layout_column.column_count_sm' => 'Ukuran SM up', 27 | 'block_layout_column.column_count_md' => 'Ukuran MD up', 28 | 'block_layout_column.column_count_lg' => 'Ukuran LG up', 29 | 'block_layout_column.column_count_xl' => 'Ukuran XL up', 30 | 'block_layout_column.content' => 'Konten kolom', 31 | 32 | 'block_carousel.items' => 'Slide', 33 | 'block_carousel.block_name' => 'Carousel', 34 | 'block_carousel.title' => 'Judul', 35 | 'block_carousel.caption' => 'Camption gambar', 36 | 'block_carousel.image' => 'Gambar', 37 | 'block_carousel.image_link' => 'Tautan', 38 | 39 | 'block_image_text.block_name' => 'Gambar dengan teks', 40 | 'block_image_text.image_position' => 'posisi gambar', 41 | 'block_image_text.left' => 'Kiri', 42 | 'block_image_text.right' => 'Kanan', 43 | 'block_image_text.center' => 'Tengah', 44 | 'block_image_text.image_shape' => 'Bentuk gambar', 45 | 'block_image_text.no_shape' => 'Tidak ada bentuk', 46 | 'block_image_text.rounded_corners' => 'Lengkungan tepi', 47 | 'block_image_text.thumbnail' => 'Gambar kecil dengan batasan', 48 | 'block_image_text.circle' => 'Lingkaran', 49 | 'block_image_text.image' => 'Gambar', 50 | 'block_image_text.image.width' => 'Lebar Gambar', 51 | 'block_image_text.image.caption' => 'Caption Gambar', 52 | 'block_image_text.image.caption.visibility' => 'Tampilkan caption image', 53 | 'block_image_text.help' => 'Add Images and text into a dynamic layout wrapper', 54 | 'block_image_text.no_text' => 'Tidak ada teks yang ditambahkan.', 55 | 'block_image_text.no_image' => 'Tidak ada gambar yang ditambahkan.', 56 | 'block_image_text.link' => 'Tautan gambar', 57 | 'block_image_text.file' => 'Menempel file', 58 | 'block_image_text.file_download' => 'Unduh file melalui gambar', 59 | 60 | 'block_inlinetext.name'=> 'Inline Text Block', 61 | 'block_inlinetext.empty'=> 'Tidak ada teks yang ditambahkan.', 62 | 'block_inlinetext.size-sm'=> 'Ukuran mobile', 63 | 'block_inlinetext.size-md'=> 'Ukuran tablet', 64 | 'block_inlinetext.size-lg'=> 'Ukuran desktop', 65 | 'block_inlinetext.size-full'=> 'Lebar penuh', 66 | 'block_inlinetext.size'=> 'Lebar', 67 | 68 | 'block_inline_wrapper.label'=>'Taruh inline blocks disini ...', 69 | 'block_inline_wrapper.name'=>'Inline Block Kontainer', 70 | 71 | 'block_carousel.config_block_css_class' => 'Block CSS Class', 72 | 'block_carousel.config_caption_css_class' => 'Caption CSS Class', 73 | 'block_carousel.config_controls' => 'Kontrol', 74 | 'block_carousel.config_indicators' => 'Indikator', 75 | 'block_carousel.config_crossfade' => 'Crossfade', 76 | 'block_carousel.config_interval' => 'Selang', 77 | 'block_carousel.config_keyboard' => 'Keyboard', 78 | 'block_carousel.config_pause' => 'Hentikan', 79 | 'block_carousel.config_ride' => 'Tunggangi', 80 | 'block_carousel.config_wrap' => 'Pindahkan', 81 | 'block_carousel.config_row' => 'Baris', 82 | 'block_carousel.lazyload' => 'LazyLoad' 83 | ]; 84 | -------------------------------------------------------------------------------- /src/messages/pt/bootstrap4.php: -------------------------------------------------------------------------------- 1 | 'Lista de arquivos', 7 | 'block_file_list.files_label' => 'Arquivos', 8 | 'block_file_list.show_type_label' => 'Mostrar tipo do arquivo', 9 | 'block_file_list.show_type_icon' => 'Mostrar icone do tipo do arquivo', 10 | 'block_file_list.show_file_size' => 'Mostrar tamanho do arquivo', 11 | 12 | 'block_image.block_name' => 'Imagem', 13 | 'block_image.image' => 'Imagem', 14 | 'block_image.align' => 'Posição da Imagem', 15 | 'block_image.align_left' => 'Esquerda', 16 | 'block_image.align_right' => 'Direita', 17 | 'block_image.align_center' => 'Centro', 18 | 'block_image.show_caption' => 'Mostrar legenda', 19 | 20 | 'block_layout.block_name' => 'Layout: Linhas', 21 | 'block_layout.content' => 'Conteúdo da linha', 22 | 23 | 'block_layout_column.block_name' => 'Layout: Coluna', 24 | 'block_layout_column.column_count' => 'Tamanho XS acima', 25 | 'block_layout_column.column_count_sm' => 'Tamanho SM acima', 26 | 'block_layout_column.column_count_md' => 'Tamanho MD acima', 27 | 'block_layout_column.column_count_lg' => 'Tamanho LG acima', 28 | 'block_layout_column.column_count_xl' => 'Tamanho XL acima', 29 | 'block_layout_column.content' => 'Conteúdo da coluna', 30 | 31 | 'block_carousel.items' => 'Slides', //not translated 32 | 'block_carousel.block_name' => 'Carrossel', 33 | 'block_carousel.title' => 'Título', 34 | 'block_carousel.caption' => 'Legenda da imagem', 35 | 'block_carousel.image' => 'Imagem', 36 | 'block_carousel.image_link' => 'Link', 37 | 38 | 'block_image_text.block_name' => 'Imagem com Texto', 39 | 'block_image_text.image_position' => 'Posição da Imagem', 40 | 'block_image_text.left' => 'Esquerda', 41 | 'block_image_text.right' => 'Direita', 42 | 'block_image_text.center' => 'Centro', 43 | 'block_image_text.image_shape' => 'Forma da Imagem', 44 | 'block_image_text.no_shape' => 'Sem forma', 45 | 'block_image_text.rounded_corners' => 'Bordas arredondadas', 46 | 'block_image_text.thumbnail' => 'Miniatura com borda', 47 | 'block_image_text.circle' => 'Círculo', 48 | 'block_image_text.image' => 'Imaem', 49 | 'block_image_text.image.width' => 'Largura da Imagem', 50 | 'block_image_text.image.caption' => 'Legenda da imagem', 51 | 'block_image_text.image.caption.visibility' => 'Mostrar legenda', 52 | 'block_image_text.help' => 'Adicionar Imagens e texto em um layout wrapper dinâmico', 53 | 'block_image_text.no_text' => 'Nenhum texto foi adicionado.', 54 | 'block_image_text.no_image' => 'Nenhuma imagem foi adicionada.', 55 | 'block_image_text.link' => 'Link da imagem', 56 | 'block_image_text.file' => 'Anexar arquivo', 57 | 'block_image_text.file_download' => 'Download do arquivo pela imagem', 58 | 59 | 'block_inlinetext.name'=> 'Bloco de Texto em linha', 60 | 'block_inlinetext.empty'=> 'Nenhum texto foi adicionado.', 61 | 'block_inlinetext.size-sm'=> 'Tamanho mobile', 62 | 'block_inlinetext.size-md'=> 'Tamanho tablet', 63 | 'block_inlinetext.size-lg'=> 'Tamanho desktop', 64 | 'block_inlinetext.size-full'=> 'Largura completa', 65 | 'block_inlinetext.size'=> 'largura', 66 | 67 | 'block_inline_wrapper.label'=>'Coloque os blocos em linha aqui ...', 68 | 'block_inline_wrapper.name'=>'Conteiner de Bloco em Linha', 69 | 70 | 'block_carousel.config_block_css_class' => 'Classe CSS do Bloco', 71 | 'block_carousel.config_caption_css_class' => 'Classe CSS da Legenda', 72 | 'block_carousel.config_controls' => 'Controles', 73 | 'block_carousel.config_indicators' => 'Indicadores', 74 | 'block_carousel.config_crossfade' => 'Crossfade', //no translated 75 | 'block_carousel.config_interval' => 'Intervalo', 76 | 'block_carousel.config_keyboard' => 'Teclado', 77 | 'block_carousel.config_pause' => 'Pausa', 78 | 'block_carousel.config_ride' => 'Direção', 79 | 'block_carousel.config_wrap' => 'Wrap', //not translated 80 | 'block_carousel.config_row' => 'Linha' 81 | ]; 82 | -------------------------------------------------------------------------------- /src/messages/fr/bootstrap4.php: -------------------------------------------------------------------------------- 1 | 'Liste des fichiers', 7 | 'block_file_list.files_label' => 'Fichiers', 8 | 'block_file_list.show_type_label' => 'Afficher le type des fichiers', 9 | 'block_file_list.show_type_icon' => 'Afficher l\'icon du type de fichier', 10 | 'block_file_list.show_file_size' => 'Afficher la taille du fichier', 11 | 12 | 'block_image.block_name' => 'Image', 13 | 'block_image.image' => 'Image', 14 | 'block_image.align' => 'Position de l\'image', 15 | 'block_image.align_left' => 'Gauche', 16 | 'block_image.align_right' => 'Droite', 17 | 'block_image.align_center' => 'Centre', 18 | 'block_image.show_caption' => 'Affficher la légende', 19 | 'block_image.lazyload' => 'Chargement différé', 20 | 21 | 'block_layout.block_name' => 'Disposition: Ligne', 22 | 'block_layout.content' => 'Contenu de la ligne', 23 | 24 | 'block_layout_column.block_name' => 'Disposition: Colonne', 25 | 'block_layout_column.column_count' => 'Taille XS et au dessus', 26 | 'block_layout_column.column_count_sm' => 'Taille SM et au dessus', 27 | 'block_layout_column.column_count_md' => 'Taille MD et au dessus', 28 | 'block_layout_column.column_count_lg' => 'Taille LG et au dessus', 29 | 'block_layout_column.column_count_xl' => 'Taille XL et au dessus', 30 | 'block_layout_column.content' => 'Contenu de la colonne', 31 | 32 | 'block_carousel.items' => 'Diapositives', 33 | 'block_carousel.block_name' => 'Carrousel', 34 | 'block_carousel.title' => 'Titre', 35 | 'block_carousel.caption' => 'Légende de l\'image', 36 | 'block_carousel.image' => 'Image', 37 | 'block_carousel.image_link' => 'Lien', 38 | 39 | 'block_image_text.block_name' => 'Image avec texte', 40 | 'block_image_text.image_position' => 'Position de l\'image', 41 | 'block_image_text.left' => 'Gauche', 42 | 'block_image_text.right' => 'Droite', 43 | 'block_image_text.center' => 'Centré', 44 | 'block_image_text.image_shape' => 'Forme de l\'image', 45 | 'block_image_text.no_shape' => 'Aucune forme', 46 | 'block_image_text.rounded_corners' => 'Coins arrondi', 47 | 'block_image_text.thumbnail' => 'Vignette avec bordure', 48 | 'block_image_text.circle' => 'Cercle', 49 | 'block_image_text.image' => 'Image', 50 | 'block_image_text.image.width' => 'Largeur de l\'image', 51 | 'block_image_text.image.caption' => 'Légende', 52 | 'block_image_text.image.caption.visibility' => 'Afficher la légende', 53 | 'block_image_text.help' => 'Ajouter des images et du texte dans un dispositif de mise en page dynamique ', 54 | 'block_image_text.no_text' => 'Aucun texte n\'a été ajouté pour le moment.', 55 | 'block_image_text.no_image' => 'Aucune image n\'a été ajoutée pour le moment.', 56 | 'block_image_text.link' => 'Lien de l\'image', 57 | 'block_image_text.file' => 'Pièce jointe', 58 | 'block_image_text.file_download' => 'Télécharger le fichier via l\'image', 59 | 60 | 'block_inlinetext.name'=> 'Bloc de texte en ligne', 61 | 'block_inlinetext.empty'=> 'Aucun texte n\'a été ajouté pour le moment.', 62 | 'block_inlinetext.size-sm'=> 'Taille mobile', 63 | 'block_inlinetext.size-md'=> 'Taille tablette', 64 | 'block_inlinetext.size-lg'=> 'Taille ordinateur', 65 | 'block_inlinetext.size-full'=> 'Plein écran', 66 | 'block_inlinetext.size'=> 'largeur', 67 | 68 | 'block_inline_wrapper.label'=>'Placez les blocs en ligne ici ...', 69 | 'block_inline_wrapper.name'=>'Conteneur de bloc en ligne', 70 | 71 | 'block_carousel.config_block_css_class' => 'Classe css de block', 72 | 'block_carousel.config_caption_css_class' => 'Classe CSS de la légende', 73 | 'block_carousel.config_controls' => 'Contrôles', 74 | 'block_carousel.config_indicators' => 'Indicateurs', 75 | 'block_carousel.config_crossfade' => 'Fondu', 76 | 'block_carousel.config_interval' => 'Interval', 77 | 'block_carousel.config_keyboard' => 'Clavier', 78 | 'block_carousel.config_pause' => 'Pause', 79 | 'block_carousel.config_ride' => 'Monter', 80 | 'block_carousel.config_wrap' => 'Envelopper', 81 | 'block_carousel.config_row' => 'Ligne', 82 | 'block_carousel.lazyload' => 'Chargement différé' 83 | ]; 84 | -------------------------------------------------------------------------------- /src/views/blocks/CarouselBlock.php: -------------------------------------------------------------------------------- 1 | extraValue('images'); 8 | $indicators = null; 9 | $counter = 0; 10 | 11 | if (!empty($images)): 12 | $this->registerJs("$('.carousel').carousel(".$this->extraValue('jsConfig', '').");"); 13 | $id = $this->extraValue('id'); 14 | $hasImages = false; 15 | foreach ($images as $image) { 16 | if (isset($image['image'])) { 17 | $hasImages = true; 18 | break; 19 | } 20 | } 21 | if ($hasImages): ?> 22 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /tests/src/blocks/ImageBlockTest.php: -------------------------------------------------------------------------------- 1 | assertSame('', $this->renderFrontendNoSpace()); 16 | } 17 | 18 | public function testDefaultOutput() 19 | { 20 | $this->block->addExtraVar('image', (object) ['source' => 'luya.jpg', 'caption' => 'Test']); 21 | 22 | $this->assertContainsTrimmed(' 23 |
    24 |
    25 | Test 26 |
    27 |
    ', $this->renderFrontendNoSpace()); 28 | } 29 | 30 | public function testAlignCenter() 31 | { 32 | $this->block->setVarValues(['align' => 'center']); 33 | $this->block->addExtraVar('image', (object) ['source' => 'luya.jpg', 'caption' => 'Test']); 34 | 35 | $this->assertContainsTrimmed(' 36 |
    37 |
    38 | Test 39 |
    40 |
    ', $this->renderFrontendNoSpace()); 41 | } 42 | 43 | public function testAlignRight() 44 | { 45 | $this->block->setVarValues(['align' => 'right']); 46 | $this->block->addExtraVar('image', (object) ['source' => 'luya.jpg', 'caption' => 'Test']); 47 | 48 | $this->assertContainsTrimmed(' 49 |
    50 |
    51 | Test 52 |
    53 |
    ', $this->renderFrontendNoSpace()); 54 | } 55 | 56 | public function testAlignRightCaption() 57 | { 58 | $this->block->setVarValues(['align' => 'right', 'showCaption' => true]); 59 | $this->block->addExtraVar('image', (object) ['source' => 'luya.jpg', 'caption' => 'Test']); 60 | 61 | $this->assertContainsTrimmed(' 62 |
    63 |
    64 | Test 65 |
    Test
    66 |
    67 |
    ', $this->renderFrontendNoSpace()); 68 | } 69 | 70 | public function testCaptionConfigSetWithEmptyCaptionValue() 71 | { 72 | $this->block->setVarValues(['align' => 'center', 'showCaption' => true]); 73 | $this->block->addExtraVar('image', (object) ['source' => 'luya.jpg']); 74 | 75 | $this->assertContainsTrimmed(' 76 |
    77 |
    78 | 79 |
    80 |
    ', $this->renderFrontendNoSpace()); 81 | } 82 | 83 | public function testLazyLoad() 84 | { 85 | $this->block->addExtraVar('image', (object) ['source' => 'luya.jpg', 'caption' => 'Test', 'itemArray' => [ 'resolution_width' => 2, 'resolution_height' => 1]]); 86 | $this->block->setCfgValues(['lazyload' => 1]); 87 | 88 | $this->assertContainsTrimmed('
    Test
    ', $this->renderFrontendNoSpace()); 89 | } 90 | 91 | 92 | public function testLazyLoadWithEmptyCaption() 93 | { 94 | $this->block->setVarValues(['align' => 'left', 'showCaption' => true]); 95 | $this->block->addExtraVar('image', (object) ['source' => 'luya.jpg', 'itemArray' => [ 'resolution_width' => 2, 'resolution_height' => 1]]); 96 | $this->block->setCfgValues(['lazyload' => 1]); 97 | 98 | $this->assertContainsTrimmed('
    ', $this->renderFrontendNoSpace()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/src/ActiveFormTest.php: -------------------------------------------------------------------------------- 1 | 'bs4app', 16 | 'basePath' => dirname(__DIR__) . '/../', 17 | 'components' => [ 18 | 'assetManager' => [ 19 | 'basePath' => dirname(__DIR__) . '/assets', 20 | 'bundles' => [ 21 | 'yii\web\JqueryAsset' => false, 22 | 'luya\bootstrap4\Bootstrap4Asset' => false, 23 | ], 24 | ], 25 | 'storage' => [ 26 | 'class' => 'luya\admin\filesystem\DummyFileSystem', 27 | 'filesArray' => [], 28 | 'imagesArray' => [], 29 | ], 30 | ] 31 | ]; 32 | } 33 | 34 | public function testActiveFormLayout() 35 | { 36 | Yii::setAlias('@webroot', dirname(__DIR__)); 37 | $model = new StubModel(); 38 | ob_start(); 39 | ob_implicit_flush(false); 40 | 41 | $form = ActiveForm::begin(['layout' => 'horizontal']); 42 | echo $form->field($model, 'firstname'); 43 | ActiveForm::end(); 44 | 45 | $this->assertContainsTrimmed(' 46 |
    47 | 48 |
    49 | 50 |
    51 |
    52 |
    ', ob_get_clean()); 53 | } 54 | public function testCheckboxSwitch() 55 | { 56 | Yii::setAlias('@webroot', dirname(__DIR__)); 57 | $model = new StubModel(); 58 | ob_start(); 59 | ob_implicit_flush(false); 60 | 61 | $form = ActiveForm::begin(['layout' => 'horizontal']); 62 | echo $form->field($model, 'firstname')->checkboxSwitch(); 63 | ActiveForm::end(); 64 | 65 | $this->assertContainsTrimmed(' 66 |
    ', ob_get_clean()); 67 | } 68 | 69 | public function testActiveFormValidationError() 70 | { 71 | Yii::setAlias('@webroot', dirname(__DIR__)); 72 | $model = new StubModel(); 73 | $model->addError('firstname', 'Some error!'); 74 | ob_start(); 75 | ob_implicit_flush(false); 76 | 77 | $form = ActiveForm::begin(['layout' => 'horizontal']); 78 | echo $form->field($model, 'firstname'); 79 | ActiveForm::end(); 80 | ob_get_clean(); 81 | 82 | $this->assertContainsTrimmed(' 83 |
    84 | 85 |
    86 | 87 |
    Some error!
    88 |
    89 |
    ', (string) $form->field($model, 'firstname')); 90 | } 91 | 92 | public function testValidAndInvalidWthAttributeHints() 93 | { 94 | $model = new Stub2Model(); 95 | $model->addError('lastname', 'Error!'); 96 | 97 | ob_start(); 98 | $form = ActiveForm::begin([ 99 | 'action' => '/something', 100 | 'enableClientScript' => false, 101 | 'validationStateOn' => ActiveForm::VALIDATION_STATE_ON_INPUT, 102 | ]); 103 | ActiveForm::end(); 104 | ob_end_clean(); 105 | 106 | $this->assertContainsTrimmed(' 107 |
    108 | 109 | 110 |
    111 |
    ', (string) $form->field($model, 'firstname')); 112 | $this->assertContainsTrimmed(' 113 |
    114 | 115 | 116 |
    Error!
    117 |
    ', (string) $form->field($model, 'lastname')); 118 | $this->assertContainsTrimmed(' 119 |
    120 | 121 | 122 | some hint message 123 |
    124 |
    ', (string) $form->field($model, 'info')); 125 | } 126 | } 127 | 128 | /* the inline stub model to use for the active form */ 129 | 130 | class StubModel extends Model 131 | { 132 | public $firstname = null; 133 | 134 | public function rules() 135 | { 136 | return [ 137 | [['firstname'], 'string'], 138 | ]; 139 | } 140 | } 141 | 142 | 143 | class Stub2Model extends Model 144 | { 145 | public $firstname = null; 146 | public $lastname; 147 | public $info; 148 | 149 | public function rules() 150 | { 151 | return [ 152 | [['firstname', 'lastname', 'info'], 'string'], 153 | ]; 154 | } 155 | 156 | public function attributeHints() 157 | { 158 | return ['info' => 'some hint message']; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/blocks/CarouselBlock.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 1.0.0 16 | */ 17 | class CarouselBlock extends BaseBootstrap4Block 18 | { 19 | public $module = 'bootstrap4'; 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | public function name() 25 | { 26 | return Module::t('block_carousel.block_name'); 27 | } 28 | 29 | /** 30 | * @inheritdoc 31 | */ 32 | public function blockGroup() 33 | { 34 | return BootstrapGroup::class; 35 | } 36 | 37 | /** 38 | * @inheritdoc 39 | */ 40 | public function icon() 41 | { 42 | return 'view_carousel'; 43 | } 44 | 45 | /** 46 | * @inheritdoc 47 | */ 48 | public function config() 49 | { 50 | return [ 51 | 'vars' => [ 52 | ['var' => 'images', 'label' => Module::t('block_carousel.items'), 'type' => self::TYPE_MULTIPLE_INPUTS, 'options' => [ 53 | ['var' => 'title', 'type' => self::TYPE_TEXT, 'label' => Module::t('block_carousel.title')], 54 | ['var' => 'caption', 'type' => self::TYPE_TEXTAREA, 'label' => Module::t('block_carousel.caption')], 55 | ['var' => 'image', 'type' => self::TYPE_IMAGEUPLOAD, 'label' => Module::t('block_carousel.image')], 56 | ['var' => 'link', 'type' => self::TYPE_LINK, 'label' => Module::t('block_carousel.image_link')] 57 | ]], 58 | ], 59 | 'cfgs' => [ 60 | ['var' => 'blockCssClass', 'type' => self::TYPE_TEXT, 'label' => Module::t('block_carousel.config_block_css_class')], 61 | ['var' => 'captionCssClass', 'type' => self::TYPE_TEXT, 'label' => Module::t('block_carousel.config_caption_css_class')], 62 | ['var' => 'controls', 'type' => self::TYPE_CHECKBOX, 'label' => Module::t('block_carousel.config_controls'), 'initvalue' => 1], 63 | ['var' => 'indicators', 'type' => self::TYPE_CHECKBOX, 'label' => Module::t('block_carousel.config_indicators'), 'initvalue' => 1], 64 | ['var' => 'crossfade', 'type' => self::TYPE_CHECKBOX, 'label' => Module::t('block_carousel.config_crossfade'), 'initvalue' => 1], 65 | ['var' => 'interval', 'type' => self::TYPE_NUMBER, 'label' => Module::t('block_carousel.config_interval')], 66 | ['var' => 'keyboard', 'type' => self::TYPE_CHECKBOX, 'label' => Module::t('block_carousel.config_keyboard'), 'initvalue' => 1], 67 | ['var' => 'pause', 'type' => self::TYPE_TEXT, 'label' => Module::t('block_carousel.config_pause')], 68 | ['var' => 'ride', 'type' => self::TYPE_TEXT, 'label' => Module::t('block_carousel.config_ride')], 69 | ['var' => 'wrap', 'type' => self::TYPE_CHECKBOX, 'label' => Module::t('block_carousel.config_wrap'), 'initvalue' => 0], 70 | ['var' => 'row', 'type' => self::TYPE_CHECKBOX, 'label' => Module::t('block_carousel.config_row'), 'initvalue' => 0], 71 | ['var' => 'lazyload', 'label' => Module::t('block_carousel.lazyload'), 'type' => self::TYPE_CHECKBOX] 72 | ] 73 | ]; 74 | } 75 | 76 | public function getFieldHelp() 77 | { 78 | return [ 79 | 'blockCssClass' => 'Adds a class to the root contianer of the carousel.', 80 | 'captionCssClass' => 'Adds a class to the carousel item caption element.', 81 | 'controls' => 'Adds the previous and next controls arrows on the left and right side of the image.', 82 | 'indicators' => 'Indicators are additional controls which displays all slides with an indicator which is clickable. The indicator is placed in the middle of the image.', 83 | 'crossfade' => 'Add crossfase to your carousel to animate slides with a fade transition instead of a slide.', 84 | 'interval' => 'The amount of time to delay between automatically cycling an item. If false, carousel will not automatically cycle.', 85 | 'keyboard' => 'Whether the carousel should react to keyboard events.', 86 | 'pause' => 'If set to "hover", pauses the cycling of the carousel on mouseenter and resumes the cycling of the carousel on mouseleave. If set to false, hovering over the carousel won\'t pause it. On touch-enabled devices, when set to "hover", cycling will pause on touchend (once the user finished interacting with the carousel) for two intervals, before automatically resuming. Note that this is in addition to the above mouse behavior.', 87 | 'ride' => 'Autoplays the carousel after the user manually cycles the first item. If "carousel", autoplays the carousel on load.', 88 | 'wrap' => 'Whether the carousel should cycle continuously or have hard stops.', 89 | "row" => 'Adds the row class to the carousel container.', 90 | ]; 91 | } 92 | 93 | /** 94 | * Get all carousel images (slides) 95 | * 96 | * @return array images 97 | */ 98 | public function images() 99 | { 100 | $images = []; 101 | foreach ($this->getVarValue('images', []) as $item) { 102 | $image = BlockHelper::imageUpload($item['image'], false, true); 103 | if ($image) { 104 | $images[] = [ 105 | 'image' => $image, 106 | 'title' => isset($item['title']) ? $item['title'] : null, 107 | 'caption' => isset($item['caption']) ? $item['caption'] : null, 108 | 'link' => isset($item['link']) ? BlockHelper::linkObject($item['link']) : null, 109 | ]; 110 | } 111 | } 112 | return $images; 113 | } 114 | 115 | /** 116 | * Returns the carousel javascript configuration 117 | * 118 | * @return string Json encoded configuration 119 | */ 120 | public function getJsConfig() 121 | { 122 | return Json::encode([ 123 | 'interval' => $this->getCfgValue('interval', 5000), 124 | 'keyboard' => $this->getCfgValue('keyboard', 1) == 1 ? true : false, 125 | 'pause' => $this->getCfgValue('pause', 'hover'), 126 | 'ride' => $this->getCfgValue('ride', false), 127 | 'wrap' => $this->getCfgValue('wrap', 1) == 1 ? true : false, 128 | ]); 129 | } 130 | 131 | /** 132 | * {@inheritdoc} 133 | */ 134 | public function extraVars() 135 | { 136 | return [ 137 | 'images' => $this->images(), 138 | 'id' => 'carousel_'.md5($this->getEnvOption('id')), 139 | 'jsConfig' => $this->getJsConfig() 140 | ]; 141 | } 142 | 143 | /** 144 | * @inheritdoc 145 | */ 146 | // Todo: Needs adjustment to display correct 147 | public function admin() 148 | { 149 | return ' 150 | {% if extras.images %} 151 | {% set hasImage = false %} 152 | {% for image in extras.images %} 153 | {% if image.image.source %} 154 | {% set hasImage = true %} 155 | {% endif %} 156 | {% endfor %} 157 | {% if hasImage %} 158 |
    159 | {% for image in extras.images %} 160 | {% if image.image.source %} 161 |
    162 | 163 |
    164 | {% endif %} 165 | {% endfor %} 166 |
    167 | {% endif %} 168 | {% endif %}'; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /tests/src/widgets/LinkPagerTest.php: -------------------------------------------------------------------------------- 1 | $pag]); 16 | 17 | $this->assertContainsTrimmed('', ob_get_clean()); 18 | } 19 | 20 | public function testDefaultOutputWithTotalCount() 21 | { 22 | $pag = new \yii\data\Pagination([ 23 | 'totalCount' => 20 24 | ]); 25 | ob_start(); 26 | ob_implicit_flush(false); 27 | echo LinkPager::widget(['pagination' => $pag]); 28 | 29 | $this->assertContainsTrimmed('', ob_get_clean()); 30 | } 31 | 32 | public function testDefaultOutputWithPageSize() 33 | { 34 | $pag = new \yii\data\Pagination([ 35 | 'pageSize' => 5 36 | ]); 37 | ob_start(); 38 | ob_implicit_flush(false); 39 | echo LinkPager::widget(['pagination' => $pag]); 40 | 41 | $this->assertContainsTrimmed('', ob_get_clean()); 42 | } 43 | 44 | public function testDefaultOutputWithCurrentPage1() 45 | { 46 | $pag = new \yii\data\Pagination([ 47 | 'page' => 1 48 | ]); 49 | ob_start(); 50 | ob_implicit_flush(false); 51 | echo LinkPager::widget(['pagination' => $pag]); 52 | 53 | $this->assertContainsTrimmed('', ob_get_clean()); 54 | } 55 | 56 | public function testDefaultOutputWithCurrentPage4() 57 | { 58 | $pag = new \yii\data\Pagination([ 59 | 'page' => 4 60 | ]); 61 | ob_start(); 62 | ob_implicit_flush(false); 63 | echo LinkPager::widget(['pagination' => $pag]); 64 | 65 | $this->assertContainsTrimmed('', ob_get_clean()); 66 | } 67 | 68 | public function testDefaultOutputWithCurrentPage7() 69 | { 70 | $pag = new \yii\data\Pagination([ 71 | 'page' => 7 72 | ]); 73 | ob_start(); 74 | ob_implicit_flush(false); 75 | echo LinkPager::widget(['pagination' => $pag]); 76 | 77 | $this->assertContainsTrimmed('', ob_get_clean()); 78 | } 79 | 80 | public function testDefaultOutputCombinedPage0of0() 81 | { 82 | $pag = new \yii\data\Pagination([ 83 | 'totalCount' => 5, 84 | 'pageSize' => 5, 85 | 'page' => 0 86 | ]); 87 | ob_start(); 88 | ob_implicit_flush(false); 89 | echo LinkPager::widget(['pagination' => $pag]); 90 | 91 | $this->assertContainsTrimmed('', ob_get_clean()); 92 | } 93 | 94 | public function testDefaultOutputCombinedPage0of1() 95 | { 96 | $pag = new \yii\data\Pagination([ 97 | 'totalCount' => 10, 98 | 'pageSize' => 5, 99 | 'page' => 0, 100 | 'route' => 'foobar' 101 | ]); 102 | ob_start(); 103 | ob_implicit_flush(false); 104 | echo LinkPager::widget(['pagination' => $pag]); 105 | 106 | $this->assertContainsTrimmed('', ob_get_clean()); 120 | } 121 | 122 | public function testDefaultOutputCombinedPage0of7() 123 | { 124 | $pag = new \yii\data\Pagination([ 125 | 'totalCount' => 40, 126 | 'pageSize' => 5, 127 | 'page' => 0, 128 | 'route' => 'foobar' 129 | ]); 130 | ob_start(); 131 | ob_implicit_flush(false); 132 | echo LinkPager::widget(['pagination' => $pag]); 133 | 134 | $this->assertContainsTrimmed('', ob_get_clean()); 166 | } 167 | 168 | public function testDefaultOutputCombinedPage3of7() 169 | { 170 | $pag = new \yii\data\Pagination([ 171 | 'totalCount' => 40, 172 | 'pageSize' => 5, 173 | 'page' => 3, 174 | 'route' => 'foobar' 175 | ]); 176 | ob_start(); 177 | ob_implicit_flush(false); 178 | echo LinkPager::widget(['pagination' => $pag]); 179 | 180 | $this->assertContainsTrimmed('', ob_get_clean()); 212 | } 213 | 214 | public function testDefaultOutputCombinedPage7of7() 215 | { 216 | $pag = new \yii\data\Pagination([ 217 | 'totalCount' => 40, 218 | 'pageSize' => 5, 219 | 'page' => 7, 220 | 'route' => 'foobar' 221 | ]); 222 | ob_start(); 223 | ob_implicit_flush(false); 224 | echo LinkPager::widget(['pagination' => $pag]); 225 | 226 | $this->assertContainsTrimmed('', ob_get_clean()); 258 | } 259 | } -------------------------------------------------------------------------------- /tests/src/blocks/CarouselBlockTest.php: -------------------------------------------------------------------------------- 1 | assertSameTrimmed('', 16 | $this->renderFrontendNoSpace() 17 | ); 18 | 19 | $this->assertSameTrimmed('', $this->renderAdminNoSpace()); 20 | } 21 | 22 | public function testEmptyImageArray() 23 | { 24 | $this->block->addExtraVar('images', []); 25 | 26 | $this->assertSameTrimmed( 27 | '', 28 | $this->renderFrontendNoSpace() 29 | ); 30 | 31 | $this->assertSameTrimmed('', $this->renderAdminNoSpace()); 32 | } 33 | 34 | public function testImageArrayWithEmptyImageInArray() 35 | { 36 | $this->block->addExtraVar('images', [ 37 | [] 38 | ]); 39 | 40 | $this->assertSameTrimmed( 41 | '', 42 | $this->renderFrontendNoSpace() 43 | ); 44 | 45 | $this->assertSameTrimmed('', $this->renderAdminNoSpace()); 46 | } 47 | 48 | public function testImageArrayWithEmptyImagesInArray() 49 | { 50 | $this->block->addExtraVar('images', [ 51 | [], 52 | [], 53 | [] 54 | ]); 55 | 56 | $this->assertSameTrimmed( 57 | '', 58 | $this->renderFrontendNoSpace() 59 | ); 60 | 61 | $this->assertSameTrimmed('', $this->renderAdminNoSpace()); 62 | } 63 | 64 | public function testImageArrayWithSingleImageInArray() 65 | { 66 | Yii::$app->storage->addDummyFile(['id' => 1]); 67 | Yii::$app->storage->insertDummyFiles(); 68 | 69 | $this->block->addExtraVar('images', [ 70 | [ 71 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 72 | 'title' => 'title', 73 | 'link' => 'foobar', 74 | 'caption' => 'caption' 75 | ] 76 | ]); 77 | 78 | $this->assertSameTrimmed( 79 | '', 92 | $this->renderFrontendNoSpace() 93 | ); 94 | 95 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 96 | } 97 | 98 | public function testImageArrayWithEmptyFirstAndSingleImageInArray() 99 | { 100 | Yii::$app->storage->addDummyFile(['id' => 1]); 101 | Yii::$app->storage->insertDummyFiles(); 102 | 103 | $this->block->addExtraVar('images', [ 104 | [], 105 | [ 106 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 107 | 'title' => 'title', 108 | 'link' => 'foobar', 109 | 'caption' => 'caption' 110 | ], 111 | ]); 112 | 113 | $this->assertSameTrimmed( 114 | '', 127 | $this->renderFrontendNoSpace() 128 | ); 129 | 130 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 131 | } 132 | 133 | public function testImageArrayWithMultipleImagesInArray() 134 | { 135 | Yii::$app->storage->addDummyFile(['id' => 1]); 136 | Yii::$app->storage->addDummyFile(['id' => 2]); 137 | Yii::$app->storage->insertDummyFiles(); 138 | 139 | $this->block->addExtraVar('images', [ 140 | [ 141 | 'image' => Item::create(['caption' => 'caption', 'file_id' => 1, 'filter_id' => 0]), 142 | 'title' => 'title', 143 | 'caption' => 'caption', 144 | 'link' => 'foobar', 145 | 146 | ], 147 | [ 148 | 'image' => Item::create(['caption' => 'caption', 'file_id' => 2, 'filter_id' => 0]), 149 | 'title' => 'title', 150 | 'link' => 'foobar', 151 | 152 | ] 153 | ]); 154 | 155 | $this->assertSameTrimmed('', $this->renderFrontendNoSpace()); 176 | 177 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 178 | } 179 | 180 | public function testImageArrayWithMultipleImagesAndEmptyImageInArray() 181 | { 182 | Yii::$app->storage->addDummyFile(['id' => 1]); 183 | Yii::$app->storage->addDummyFile(['id' => 2]); 184 | Yii::$app->storage->insertDummyFiles(); 185 | 186 | $this->block->addExtraVar('images', [ 187 | [], 188 | [ 189 | 'image' => Item::create(['caption' => 'caption', 'file_id' => 1, 'filter_id' => 0]), 190 | 'title' => 'title', 191 | 'caption' => 'caption', 192 | 'link' => 'foobar', 193 | 194 | ], 195 | [], 196 | [ 197 | 'image' => Item::create(['caption' => 'caption', 'file_id' => 2, 'filter_id' => 0]), 198 | 'title' => 'title', 199 | 'link' => 'foobar', 200 | 201 | ] 202 | ]); 203 | 204 | $this->assertSameTrimmed('', $this->renderFrontendNoSpace()); 225 | 226 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 227 | } 228 | 229 | public function testImageWithoutTitle() 230 | { 231 | Yii::$app->storage->addDummyFile(['id' => 1]); 232 | Yii::$app->storage->insertDummyFiles(); 233 | 234 | $this->block->addExtraVar('images', [ 235 | [ 236 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 237 | 'link' => 'foobar', 238 | 'caption' => 'caption' 239 | ] 240 | ]); 241 | 242 | $this->assertSameTrimmed( 243 | '', 255 | $this->renderFrontendNoSpace() 256 | ); 257 | 258 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 259 | } 260 | 261 | public function testImageWithEmptyTitle() 262 | { 263 | Yii::$app->storage->addDummyFile(['id' => 1]); 264 | Yii::$app->storage->insertDummyFiles(); 265 | 266 | $this->block->addExtraVar('images', [ 267 | [ 268 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 269 | 'title' => '', 270 | 'link' => 'foobar', 271 | 'caption' => 'caption' 272 | ] 273 | ]); 274 | 275 | $this->assertSameTrimmed( 276 | '', 288 | $this->renderFrontendNoSpace() 289 | ); 290 | 291 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 292 | } 293 | 294 | public function testImageWithoutCaption() 295 | { 296 | Yii::$app->storage->addDummyFile(['id' => 1]); 297 | Yii::$app->storage->insertDummyFiles(); 298 | 299 | $this->block->addExtraVar('images', [ 300 | [ 301 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 302 | 'title' => 'title', 303 | 'link' => 'foobar' 304 | ] 305 | ]); 306 | 307 | $this->assertSameTrimmed( 308 | '', 320 | $this->renderFrontendNoSpace() 321 | ); 322 | 323 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 324 | } 325 | 326 | public function testImageWithEmptyCaption() 327 | { 328 | Yii::$app->storage->addDummyFile(['id' => 1]); 329 | Yii::$app->storage->insertDummyFiles(); 330 | 331 | $this->block->addExtraVar('images', [ 332 | [ 333 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 334 | 'title' => 'title', 335 | 'link' => 'foobar', 336 | 'caption' => '' 337 | ] 338 | ]); 339 | 340 | $this->assertSameTrimmed( 341 | '', 353 | $this->renderFrontendNoSpace() 354 | ); 355 | 356 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 357 | } 358 | 359 | public function testImageWithoutLink() 360 | { 361 | Yii::$app->storage->addDummyFile(['id' => 1]); 362 | Yii::$app->storage->insertDummyFiles(); 363 | 364 | $this->block->addExtraVar('images', [ 365 | [ 366 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 367 | 'title' => 'title', 368 | 'caption' => 'caption' 369 | ] 370 | ]); 371 | 372 | $this->assertSameTrimmed( 373 | '', 384 | $this->renderFrontendNoSpace() 385 | ); 386 | 387 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 388 | } 389 | 390 | public function testImageWithEmptyLink() 391 | { 392 | Yii::$app->storage->addDummyFile(['id' => 1]); 393 | Yii::$app->storage->insertDummyFiles(); 394 | 395 | $this->block->addExtraVar('images', [ 396 | [ 397 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0]), 398 | 'title' => 'title', 399 | 'link' => '', 400 | 'caption' => 'caption' 401 | ] 402 | ]); 403 | 404 | $this->assertSameTrimmed( 405 | '', 416 | $this->renderFrontendNoSpace() 417 | ); 418 | 419 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 420 | } 421 | 422 | 423 | public function testImageWithoutImage() 424 | { 425 | $this->block->addExtraVar('images', [ 426 | [ 427 | 'title' => 'title', 428 | 'link' => 'foobar', 429 | 'caption' => 'caption' 430 | ] 431 | ]); 432 | 433 | $this->assertSameTrimmed( 434 | '', 435 | $this->renderFrontendNoSpace() 436 | ); 437 | 438 | $this->assertSameTrimmed('', $this->renderAdminNoSpace()); 439 | } 440 | 441 | // /* 442 | // * @todo var value testing 443 | // */ 444 | // public function testVars() 445 | // { 446 | // $this->block->setVarValues(['title' => 'my title', 'caption' => 'caption']); 447 | // $this->block->addExtraVar('image', (object) ['source' => 'image.jpg']); 448 | // $this->assertContainsTrimmed(' 449 | // ', $this->renderFrontendNoSpace()); 468 | // $this->assertContainsTrimmed('
    ', $this->renderAdminNoSpace()); 469 | // } 470 | 471 | public function testIndicatorConfig() 472 | { 473 | Yii::$app->storage->addDummyFile(['id' => 1]); 474 | Yii::$app->storage->addDummyFile(['id' => 2]); 475 | Yii::$app->storage->insertDummyFiles(); 476 | 477 | $this->block->setCfgValues(['indicators' => true]); 478 | 479 | $this->block->addExtraVar('images', [ 480 | [ 481 | 'image' => Item::create(['caption' => 'caption', 'file_id' => 1, 'filter_id' => 0]), 482 | 'title' => 'title', 483 | 'caption' => 'caption', 484 | 'link' => 'foobar', 485 | 486 | ], 487 | [ 488 | 'image' => Item::create(['caption' => 'caption', 'file_id' => 2, 'filter_id' => 0]), 489 | 'title' => 'title', 490 | 'link' => 'foobar' 491 | ] 492 | ]); 493 | 494 | $this->assertSameTrimmed('', $this->renderFrontendNoSpace()); 519 | 520 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 521 | } 522 | 523 | public function testIndicatorConfigurationWithOneImage() 524 | { 525 | Yii::$app->storage->addDummyFile(['id' => 1]); 526 | Yii::$app->storage->insertDummyFiles(); 527 | 528 | $this->block->setCfgValues(['indicators' => true]); 529 | 530 | $this->block->addExtraVar('images', [ 531 | [ 532 | 'image' => Item::create(['caption' => 'caption', 'file_id' => 1, 'filter_id' => 0]), 533 | 'title' => 'title', 534 | 'caption' => 'caption', 535 | 'link' => 'foobar', 536 | ] 537 | ]); 538 | 539 | $this->assertSameTrimmed('', $this->renderFrontendNoSpace()); 552 | 553 | $this->assertSameTrimmed('
    ', $this->renderAdminNoSpace()); 554 | } 555 | 556 | /* 557 | * @todo test other configs 558 | */ 559 | 560 | public function testLazyLoadConfiguration() 561 | { 562 | Yii::$app->storage->addDummyFile(['id' => 1]); 563 | Yii::$app->storage->insertDummyFiles(); 564 | $this->block->setCfgValues(['lazyload' => 1]); 565 | 566 | $this->block->addExtraVar('images', [ 567 | [ 568 | 'image' => Item::create(['caption' => 'cap-title', 'file_id' => 1, 'filter_id' => 0, 'resolution_width' => 2, 'resolution_height' => 1]), 569 | 'title' => 'title', 570 | 'link' => 'foobar', 571 | 'caption' => 'caption' 572 | ] 573 | ]); 574 | 575 | $this->assertSameTrimmed( 576 | '', 598 | $this->renderFrontendNoSpace() 599 | ); 600 | } 601 | 602 | public function testBlockName() 603 | { 604 | $this->app->language = 'de'; 605 | $this->assertSame('Carousel', $this->block->name()); 606 | } 607 | } 608 | --------------------------------------------------------------------------------