├── CHANGELOG.md ├── LICENSE.md ├── Makefile ├── README.md ├── composer.json └── src ├── Accordion.php ├── AutoComplete.php ├── DatePicker.php ├── DatePickerLanguageAsset.php ├── Dialog.php ├── Draggable.php ├── Droppable.php ├── InputWidget.php ├── JuiAsset.php ├── Menu.php ├── ProgressBar.php ├── Resizable.php ├── Selectable.php ├── Slider.php ├── SliderInput.php ├── Sortable.php ├── Spinner.php ├── Tabs.php └── Widget.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Yii Framework 2 jui extension Change Log 2 | ======================================== 3 | 4 | 2.0.8 under development 5 | ----------------------- 6 | 7 | - no changes in this release. 8 | 9 | 10 | 2.0.7 November 25, 2017 11 | ----------------------- 12 | 13 | - Bug #45: Fixed missing close icon in `yii\jui\Dialog` (mtangoo) 14 | - Bug #46: `yii\jui\Selectable` add support for `begin()`, `end()` widget methods (fdezmc) 15 | - Enh #56: Use `jQuery` instead of `$` in generated code to avoid conflicts (samdark) 16 | - Chg #55: `yii\jui\AutoComplete::run()` now returns output instead of echoing it (unlimix) 17 | - Chg #72: Updated jQueryUI dependency to use `1.12.1` as minimum version (samdark) 18 | 19 | 20 | 2.0.6 July 22, 2016 21 | ----------------------- 22 | 23 | - Bug #36: `yii\jui\Draggable` was using wrong event names (samdark) 24 | - Bug #41: `yii\jui\Droppable` and `yii\jui\Resizable` were using wrong event names (samdark) 25 | 26 | 27 | 2.0.5 March 17, 2016 28 | -------------------- 29 | 30 | - Bug #8607: `yii\jui\Spinner` was using wrong event names (samdark) 31 | 32 | 33 | 2.0.4 May 10, 2015 34 | ------------------ 35 | 36 | - Bug #6: When using `DatePicker` translations, asset was registered without timestamp when asset manager `$appendTimestamp` was enabled (samdark) 37 | - Bug (CVE-2015-3397): Using `Json::htmlEncode()` for safer JSON data encoding in HTML code (samdark, Tomasz Tokarski) 38 | 39 | 40 | 2.0.3 March 01, 2015 41 | -------------------- 42 | 43 | - Enh #7127: `name` or `model` and `attribute` are no longer required properties of `yii\jui\InputWidget` (nirvana-msu, cebe) 44 | 45 | 46 | 2.0.2 January 11, 2015 47 | ---------------------- 48 | 49 | - Enh #6570: Datepicker now uses fallback to find language files, e.g. application language is `de-DE` and the translation files does not exists, it will use `de` instead (cebe) 50 | - Enh #6471: Datepicker will now show an empty field when value is an empty string (cebe) 51 | 52 | 53 | 2.0.1 December 07, 2014 54 | ----------------------- 55 | 56 | - no changes in this release. 57 | 58 | 59 | 2.0.0 October 12, 2014 60 | ---------------------- 61 | 62 | - no changes in this release. 63 | 64 | 65 | 2.0.0-rc September 27, 2014 66 | --------------------------- 67 | 68 | - Chg #1551: Jui datepicker has a new property `$dateFormat` which is used to set the clientOption `dateFormat`. 69 | The new property does not use the datepicker formatting syntax anymore but uses the same as the `yii\i18n\Formatter` 70 | class which is the ICU syntax for date formatting, you have to adjust all your DatePicker widgets to use 71 | the new property instead of setting the dateFormat in the clientOptions (cebe) 72 | 73 | 74 | 2.0.0-beta April 13, 2014 75 | ------------------------- 76 | 77 | - Bug #1550: fixed the issue that JUI input widgets did not property input IDs. (qiangxue) 78 | - Bug #2514: Jui sortable clientEvents were not working because of wrong naming assumptions. (cebe) 79 | - Enh #2573: Jui datepicker now uses the current application language by default. (andy5) 80 | 81 | 2.0.0-alpha, December 1, 2013 82 | ----------------------------- 83 | 84 | - Initial release. 85 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Yii Software LLC nor the names of its 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # default versions to test against 3 | # these can be overridden by setting the environment variables in the shell 4 | PHP_VERSION=php-5.6.8 5 | YII_VERSION=dev-master 6 | 7 | # ensure all the configuration variables above are in environment of the shell commands below 8 | export 9 | 10 | help: 11 | @echo "make test - run phpunit tests using a docker environment" 12 | # @echo "make clean - stop docker and remove container" 13 | 14 | test: docker-php 15 | composer require "yiisoft/yii2:${YII_VERSION}" --prefer-dist 16 | composer install --prefer-dist 17 | docker run --rm=true -v $(shell pwd):/opt/test yiitest/php:${PHP_VERSION} phpunit --verbose --color 18 | 19 | docker-php: dockerfiles 20 | cd tests/docker/php && sh build.sh 21 | 22 | dockerfiles: 23 | test -d tests/docker || git clone https://github.com/cebe/jenkins-test-docker tests/docker 24 | cd tests/docker && git checkout -- . && git pull 25 | mkdir -p tests/dockerids 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

JUI Extension for Yii 2

6 |
7 |

8 | 9 | This is the JQuery UI extension for [Yii framework 2.0](https://www.yiiframework.com). It encapsulates [JQuery UI widgets](https://jqueryui.com/) as Yii widgets, 10 | and makes using JQuery UI widgets in Yii applications extremely easy. 11 | 12 | For license information check the [LICENSE](LICENSE.md)-file. 13 | 14 | Documentation is at [docs/guide/README.md](docs/guide/README.md). 15 | 16 | [![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2-jui/v/stable.png)](https://packagist.org/packages/yiisoft/yii2-jui) 17 | [![Total Downloads](https://poser.pugx.org/yiisoft/yii2-jui/downloads.png)](https://packagist.org/packages/yiisoft/yii2-jui) 18 | [![Build Status](https://github.com/yiisoft/yii2-jui/workflows/build/badge.svg)](https://github.com/yiisoft/yii2-jui/actions) 19 | 20 | Installation 21 | ------------ 22 | 23 | The preferred way to install this extension is through [composer](https://getcomposer.org/download/). 24 | 25 | Either run 26 | 27 | ``` 28 | php composer.phar require --prefer-dist yiisoft/yii2-jui 29 | ``` 30 | 31 | or add 32 | 33 | ``` 34 | "yiisoft/yii2-jui": "~2.0.0" 35 | ``` 36 | 37 | to the require section of your `composer.json` file. 38 | 39 | Usage 40 | ----- 41 | 42 | The following 43 | single line of code in a view file would render a [JQuery UI DatePicker](https://api.jqueryui.com/datepicker/) widget: 44 | 45 | ```php 46 | 'attributeName']) ?> 47 | ``` 48 | 49 | Configuring the Jquery UI options should be done using the clientOptions attribute: 50 | 51 | ```php 52 | 'attributeName', 'clientOptions' => ['defaultDate' => '2014-01-01']]) ?> 53 | ``` 54 | 55 | If you want to use the JUI widget in an ActiveForm, it can be done like this: 56 | 57 | ```php 58 | field($model,'attributeName')->widget(DatePicker::className(),['clientOptions' => ['defaultDate' => '2014-01-01']]) ?> 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yiisoft/yii2-jui", 3 | "description": "The Jquery UI extension for the Yii framework", 4 | "keywords": ["yii2", "Jquery UI"], 5 | "type": "yii2-extension", 6 | "license": "BSD-3-Clause", 7 | "support": { 8 | "issues": "https://github.com/yiisoft/yii2-jui/issues", 9 | "forum": "https://www.yiiframework.com/forum/", 10 | "wiki": "https://www.yiiframework.com/wiki/", 11 | "irc": "ircs://irc.libera.chat:6697/yii", 12 | "source": "https://github.com/yiisoft/yii2-jui" 13 | }, 14 | "authors": [ 15 | { 16 | "name": "Qiang Xue", 17 | "email": "qiang.xue@gmail.com" 18 | }, 19 | { 20 | "name": "Alexander Kochetov", 21 | "email": "creocoder@gmail.com" 22 | }, 23 | { 24 | "name": "Carsten Brandt", 25 | "email": "mail@cebe.cc" 26 | }, 27 | { 28 | "name": "Alexander Makarov", 29 | "email": "sam@rmcreative.ru" 30 | } 31 | ], 32 | "require": { 33 | "yiisoft/yii2": "~2.0.4", 34 | "bower-asset/jquery-ui": "~1.12.1" 35 | }, 36 | "require-dev": { 37 | "cweagans/composer-patches": "^1.7", 38 | "phpunit/phpunit": "4.8.34" 39 | }, 40 | "repositories": [ 41 | { 42 | "type": "composer", 43 | "url": "https://asset-packagist.org" 44 | } 45 | ], 46 | "autoload": { 47 | "psr-4": { 48 | "yii\\jui\\": "src" 49 | } 50 | }, 51 | "extra": { 52 | "branch-alias": { 53 | "dev-master": "2.0.x-dev" 54 | }, 55 | "composer-exit-on-patch-failure": true, 56 | "patches": { 57 | "phpunit/phpunit-mock-objects": { 58 | "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" 59 | }, 60 | "phpunit/phpunit": { 61 | "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", 62 | "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch" 63 | } 64 | } 65 | }, 66 | "config": { 67 | "allow-plugins": { 68 | "cweagans/composer-patches": true, 69 | "yiisoft/yii2-composer": true 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Accordion.php: -------------------------------------------------------------------------------- 1 | [ 22 | * [ 23 | * 'header' => 'Section 1', 24 | * 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...', 25 | * ], 26 | * [ 27 | * 'header' => 'Section 2', 28 | * 'headerOptions' => ['tag' => 'h3'], 29 | * 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...', 30 | * 'options' => ['tag' => 'div'], 31 | * ], 32 | * ], 33 | * 'options' => ['tag' => 'div'], 34 | * 'itemOptions' => ['tag' => 'div'], 35 | * 'headerOptions' => ['tag' => 'h3'], 36 | * 'clientOptions' => ['collapsible' => false], 37 | * ]); 38 | * ``` 39 | * 40 | * @see https://api.jqueryui.com/accordion/ 41 | * @author Alexander Kochetov 42 | * @since 2.0 43 | */ 44 | class Accordion extends Widget 45 | { 46 | /** 47 | * @var array the HTML attributes for the widget container tag. The following special options are recognized: 48 | * 49 | * - tag: string, defaults to "div", the tag name of the container tag of this widget 50 | * 51 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 52 | */ 53 | public $options = []; 54 | /** 55 | * @var array list of collapsible items. Each item can be an array of the following structure: 56 | * 57 | * ~~~ 58 | * [ 59 | * 'header' => 'Item header', 60 | * 'content' => 'Item content', 61 | * // the HTML attributes of the item header container tag. This will overwrite "headerOptions". 62 | * 'headerOptions' => [], 63 | * // the HTML attributes of the item container tag. This will overwrite "itemOptions". 64 | * 'options' => [], 65 | * ] 66 | * ~~~ 67 | */ 68 | public $items = []; 69 | /** 70 | * @var array list of HTML attributes for the item container tags. This will be overwritten 71 | * by the "options" set in individual [[items]]. The following special options are recognized: 72 | * 73 | * - tag: string, defaults to "div", the tag name of the item container tags. 74 | * 75 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 76 | */ 77 | public $itemOptions = []; 78 | /** 79 | * @var array list of HTML attributes for the item header container tags. This will be overwritten 80 | * by the "headerOptions" set in individual [[items]]. The following special options are recognized: 81 | * 82 | * - tag: string, defaults to "h3", the tag name of the item container tags. 83 | * 84 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 85 | */ 86 | public $headerOptions = []; 87 | 88 | 89 | /** 90 | * Renders the widget. 91 | */ 92 | public function run() 93 | { 94 | $options = $this->options; 95 | $tag = ArrayHelper::remove($options, 'tag', 'div'); 96 | echo Html::beginTag($tag, $options) . "\n"; 97 | echo $this->renderItems() . "\n"; 98 | echo Html::endTag($tag) . "\n"; 99 | $this->registerWidget('accordion'); 100 | } 101 | 102 | /** 103 | * Renders collapsible items as specified on [[items]]. 104 | * @return string the rendering result. 105 | * @throws InvalidConfigException. 106 | */ 107 | protected function renderItems() 108 | { 109 | $items = []; 110 | foreach ($this->items as $item) { 111 | if (!array_key_exists('header', $item)) { 112 | throw new InvalidConfigException("The 'header' option is required."); 113 | } 114 | if (!array_key_exists('content', $item)) { 115 | throw new InvalidConfigException("The 'content' option is required."); 116 | } 117 | $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); 118 | $headerTag = ArrayHelper::remove($headerOptions, 'tag', 'h3'); 119 | $items[] = Html::tag($headerTag, $item['header'], $headerOptions); 120 | $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); 121 | $tag = ArrayHelper::remove($options, 'tag', 'div'); 122 | $items[] = Html::tag($tag, $item['content'], $options); 123 | } 124 | 125 | return implode("\n", $items); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/AutoComplete.php: -------------------------------------------------------------------------------- 1 | $model, 20 | * 'attribute' => 'country', 21 | * 'clientOptions' => [ 22 | * 'source' => ['USA', 'RUS'], 23 | * ], 24 | * ]); 25 | * ``` 26 | * 27 | * The following example will use the name property instead: 28 | * 29 | * ```php 30 | * echo AutoComplete::widget([ 31 | * 'name' => 'country', 32 | * 'clientOptions' => [ 33 | * 'source' => ['USA', 'RUS'], 34 | * ], 35 | * ]); 36 | * ``` 37 | * 38 | * You can also use this widget in an [[yii\widgets\ActiveForm|ActiveForm]] using the [[yii\widgets\ActiveField::widget()|widget()]] 39 | * method, for example like this: 40 | * 41 | * ```php 42 | * field($model, 'from_date')->widget(\yii\jui\AutoComplete::classname(), [ 43 | * 'clientOptions' => [ 44 | * 'source' => ['USA', 'RUS'], 45 | * ], 46 | * ]) ?> 47 | * ``` 48 | * 49 | * @see https://api.jqueryui.com/autocomplete/ 50 | * @author Alexander Kochetov 51 | * @since 2.0 52 | */ 53 | class AutoComplete extends InputWidget 54 | { 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | public function run() 59 | { 60 | $this->registerWidget('autocomplete'); 61 | return $this->renderWidget(); 62 | } 63 | 64 | /** 65 | * Renders the AutoComplete widget. 66 | * @return string the rendering result. 67 | */ 68 | public function renderWidget() 69 | { 70 | if ($this->hasModel()) { 71 | return Html::activeTextInput($this->model, $this->attribute, $this->options); 72 | } 73 | return Html::textInput($this->name, $this->value, $this->options); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/DatePicker.php: -------------------------------------------------------------------------------- 1 | $model, 24 | * 'attribute' => 'from_date', 25 | * //'language' => 'ru', 26 | * //'dateFormat' => 'yyyy-MM-dd', 27 | * ]); 28 | * ``` 29 | * 30 | * The following example will use the name property instead: 31 | * 32 | * ```php 33 | * echo DatePicker::widget([ 34 | * 'name' => 'from_date', 35 | * 'value' => $value, 36 | * //'language' => 'ru', 37 | * //'dateFormat' => 'yyyy-MM-dd', 38 | * ]); 39 | * ``` 40 | * 41 | * You can also use this widget in an [[\yii\widgets\ActiveForm|ActiveForm]] using the [[\yii\widgets\ActiveField::widget()|widget()]] 42 | * method, for example like this: 43 | * 44 | * ```php 45 | * field($model, 'from_date')->widget(\yii\jui\DatePicker::className(), [ 46 | * //'language' => 'ru', 47 | * //'dateFormat' => 'yyyy-MM-dd', 48 | * ]) ?> 49 | * ``` 50 | * 51 | * Note that and empty string (`''`) and `null` will result in an empty text field while `0` will be 52 | * interpreted as a UNIX timestamp and result in a date displayed as `1970-01-01`. 53 | * It is recommended to add a 54 | * validation filter in your model that sets the value to `null` in case when no date has been entered: 55 | * 56 | * ```php 57 | * [['from_date'], 'default', 'value' => null], 58 | * ``` 59 | * 60 | * @see https://api.jqueryui.com/datepicker/ 61 | * @author Alexander Kochetov 62 | * @author Carsten Brandt 63 | * @since 2.0 64 | */ 65 | class DatePicker extends InputWidget 66 | { 67 | /** 68 | * @var string the locale ID (e.g. 'fr', 'de', 'en-GB') for the language to be used by the date picker. 69 | * If this property is empty, then the current application language will be used. 70 | * 71 | * Since version 2.0.2 a fallback is used if the application language includes a locale part (e.g. `de-DE`) and the language 72 | * file does not exist, it will fall back to using `de`. 73 | */ 74 | public $language; 75 | /** 76 | * @var boolean If true, shows the widget as an inline calendar and the input as a hidden field. 77 | */ 78 | public $inline = false; 79 | /** 80 | * @var array the HTML attributes for the container tag. This is only used when [[inline]] is true. 81 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 82 | */ 83 | public $containerOptions = []; 84 | /** 85 | * @var string the format string to be used for formatting the date value. This option will be used 86 | * to populate the [[clientOptions|clientOption]] `dateFormat`. 87 | * The value can be one of "short", "medium", "long", or "full", which represents a preset format of different lengths. 88 | * 89 | * It can also be a custom format as specified in the [ICU manual](https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax). 90 | * Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the 91 | * PHP [date()](https://php.net/manual/de/function.date.php)-function. 92 | * 93 | * For example: 94 | * 95 | * ```php 96 | * 'MM/dd/yyyy' // date in ICU format 97 | * 'php:m/d/Y' // the same date in PHP format 98 | * ``` 99 | * 100 | * If not set the default value will be taken from `Yii::$app->formatter->dateFormat`. 101 | */ 102 | public $dateFormat; 103 | /** 104 | * @var string the model attribute that this widget is associated with. 105 | * The value of the attribute will be converted using [[\yii\i18n\Formatter::asDate()|`Yii::$app->formatter->asDate()`]] 106 | * with the [[dateFormat]] if it is not null. 107 | */ 108 | public $attribute; 109 | /** 110 | * @var string the input value. 111 | * This value will be converted using [[\yii\i18n\Formatter::asDate()|`Yii::$app->formatter->asDate()`]] 112 | * with the [[dateFormat]] if it is not null. 113 | */ 114 | public $value; 115 | 116 | 117 | /** 118 | * {@inheritdoc} 119 | */ 120 | public function init() 121 | { 122 | parent::init(); 123 | if ($this->inline && !isset($this->containerOptions['id'])) { 124 | $this->containerOptions['id'] = $this->options['id'] . '-container'; 125 | } 126 | if ($this->dateFormat === null) { 127 | $this->dateFormat = Yii::$app->formatter->dateFormat; 128 | } 129 | } 130 | 131 | /** 132 | * Renders the widget. 133 | */ 134 | public function run() 135 | { 136 | echo $this->renderWidget() . "\n"; 137 | 138 | $containerID = $this->inline ? $this->containerOptions['id'] : $this->options['id']; 139 | $language = $this->language ? $this->language : Yii::$app->language; 140 | 141 | if (strncmp($this->dateFormat, 'php:', 4) === 0) { 142 | $this->clientOptions['dateFormat'] = FormatConverter::convertDatePhpToJui(substr($this->dateFormat, 4)); 143 | } else { 144 | $this->clientOptions['dateFormat'] = FormatConverter::convertDateIcuToJui($this->dateFormat, 'date', $language); 145 | } 146 | 147 | if ($language !== 'en-US') { 148 | $view = $this->getView(); 149 | $assetBundle = DatePickerLanguageAsset::register($view); 150 | $assetBundle->language = $language; 151 | $options = Json::htmlEncode($this->clientOptions); 152 | $language = Html::encode($language); 153 | $view->registerJs("jQuery('#{$containerID}').datepicker($.extend({}, $.datepicker.regional['{$language}'], $options));"); 154 | } else { 155 | $this->registerClientOptions('datepicker', $containerID); 156 | } 157 | 158 | $this->registerClientEvents('datepicker', $containerID); 159 | JuiAsset::register($this->getView()); 160 | } 161 | 162 | /** 163 | * Renders the DatePicker widget. 164 | * @return string the rendering result. 165 | */ 166 | protected function renderWidget() 167 | { 168 | $contents = []; 169 | 170 | // get formatted date value 171 | if ($this->hasModel()) { 172 | $value = Html::getAttributeValue($this->model, $this->attribute); 173 | } else { 174 | $value = $this->value; 175 | } 176 | if ($value !== null && $value !== '') { 177 | // format value according to dateFormat 178 | try { 179 | $value = Yii::$app->formatter->asDate($value, $this->dateFormat); 180 | } catch(InvalidParamException $e) { 181 | // ignore exception and keep original value if it is not a valid date 182 | } 183 | } 184 | $options = $this->options; 185 | $options['value'] = $value; 186 | 187 | if ($this->inline === false) { 188 | // render a text input 189 | if ($this->hasModel()) { 190 | $contents[] = Html::activeTextInput($this->model, $this->attribute, $options); 191 | } else { 192 | $contents[] = Html::textInput($this->name, $value, $options); 193 | } 194 | } else { 195 | // render an inline date picker with hidden input 196 | if ($this->hasModel()) { 197 | $contents[] = Html::activeHiddenInput($this->model, $this->attribute, $options); 198 | } else { 199 | $contents[] = Html::hiddenInput($this->name, $value, $options); 200 | } 201 | $this->clientOptions['defaultDate'] = $value; 202 | $this->clientOptions['altField'] = '#' . $this->options['id']; 203 | $contents[] = Html::tag('div', null, $this->containerOptions); 204 | } 205 | 206 | return implode("\n", $contents); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/DatePickerLanguageAsset.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 2.0 16 | */ 17 | class DatePickerLanguageAsset extends AssetBundle 18 | { 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public $sourcePath = '@bower/jquery-ui'; 23 | /** 24 | * @var boolean whether to automatically generate the needed language js files. 25 | * If this is true, the language js files will be determined based on the actual usage of [[DatePicker]] 26 | * and its language settings. If this is false, you should explicitly specify the language js files via [[js]]. 27 | */ 28 | public $autoGenerate = true; 29 | /** 30 | * @var string language to register translation file for 31 | */ 32 | public $language; 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | public $depends = [ 37 | 'yii\jui\JuiAsset', 38 | ]; 39 | 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function registerAssetFiles($view) 45 | { 46 | if ($this->autoGenerate) { 47 | $language = $this->language; 48 | $fallbackLanguage = substr($this->language, 0, 2); 49 | if ($fallbackLanguage !== $this->language && !file_exists(Yii::getAlias($this->sourcePath . "/ui/i18n/datepicker-{$language}.js"))) { 50 | $language = $fallbackLanguage; 51 | } 52 | $this->js[] = "ui/i18n/datepicker-$language.js"; 53 | } 54 | parent::registerAssetFiles($view); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Dialog.php: -------------------------------------------------------------------------------- 1 | [ 20 | * 'modal' => true, 21 | * ], 22 | * ]); 23 | * 24 | * echo 'Dialog contents here...'; 25 | * 26 | * Dialog::end(); 27 | * ``` 28 | * 29 | * @see https://api.jqueryui.com/dialog/ 30 | * @author Alexander Kochetov 31 | * @since 2.0 32 | */ 33 | class Dialog extends Widget 34 | { 35 | /** 36 | * Initializes the widget. 37 | */ 38 | public function init() 39 | { 40 | parent::init(); 41 | echo Html::beginTag('div', $this->options) . "\n"; 42 | 43 | //Fix for closing icon (x) not showing up in dialog 44 | $this->getView()->registerJs(" 45 | if ($.fn.button) { 46 | var bootstrapButton = $.fn.button.noConflict(); 47 | $.fn.bootstrapBtn = bootstrapButton; 48 | }", 49 | \yii\web\View::POS_READY 50 | ); 51 | } 52 | 53 | /** 54 | * Renders the widget. 55 | */ 56 | public function run() 57 | { 58 | echo Html::endTag('div') . "\n"; 59 | $this->registerWidget('dialog'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Draggable.php: -------------------------------------------------------------------------------- 1 | ['grid' => [50, 20]], 20 | * ]); 21 | * 22 | * echo 'Draggable contents here...'; 23 | * 24 | * Draggable::end(); 25 | * ``` 26 | * 27 | * @see https://api.jqueryui.com/draggable/ 28 | * @author Alexander Kochetov 29 | * @since 2.0 30 | */ 31 | class Draggable extends Widget 32 | { 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected $clientEventMap = [ 37 | 'create' => 'dragcreate', 38 | 'drag' => 'drag', 39 | 'stop' => 'dragstop', 40 | 'start' => 'dragstart', 41 | ]; 42 | 43 | 44 | /** 45 | * Initializes the widget. 46 | */ 47 | public function init() 48 | { 49 | parent::init(); 50 | echo Html::beginTag('div', $this->options) . "\n"; 51 | } 52 | 53 | /** 54 | * Renders the widget. 55 | */ 56 | public function run() 57 | { 58 | echo Html::endTag('div') . "\n"; 59 | $this->registerWidget('draggable'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Droppable.php: -------------------------------------------------------------------------------- 1 | ['accept' => '.special'], 20 | * ]); 21 | * 22 | * echo 'Droppable body here...'; 23 | * 24 | * Droppable::end(); 25 | * ``` 26 | * 27 | * @see https://api.jqueryui.com/droppable/ 28 | * @author Alexander Kochetov 29 | * @since 2.0 30 | */ 31 | class Droppable extends Widget 32 | { 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected $clientEventMap = [ 37 | 'activate' => 'dropactivate', 38 | 'create' => 'dropcreate', 39 | 'deactivate' => 'dropdeactivate', 40 | 'drop' => 'drop', 41 | 'out' => 'dropout', 42 | 'over' => 'dropover', 43 | ]; 44 | 45 | 46 | /** 47 | * Initializes the widget. 48 | */ 49 | public function init() 50 | { 51 | parent::init(); 52 | echo Html::beginTag('div', $this->options) . "\n"; 53 | } 54 | 55 | /** 56 | * Renders the widget. 57 | */ 58 | public function run() 59 | { 60 | echo Html::endTag('div') . "\n"; 61 | $this->registerWidget('droppable'); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/InputWidget.php: -------------------------------------------------------------------------------- 1 | field($model, 'from_date')->widget('WidgetClassName', [ 21 | * // configure additional widget properties here 22 | * ]) ?> 23 | * ``` 24 | * 25 | * @author Alexander Kochetov 26 | * @since 2.0 27 | */ 28 | class InputWidget extends Widget 29 | { 30 | /** 31 | * @var Model the data model that this widget is associated with. 32 | */ 33 | public $model; 34 | /** 35 | * @var string the model attribute that this widget is associated with. 36 | */ 37 | public $attribute; 38 | /** 39 | * @var string the input name. This must be set if [[model]] and [[attribute]] are not set. 40 | */ 41 | public $name; 42 | /** 43 | * @var string the input value. 44 | */ 45 | public $value; 46 | 47 | 48 | /** 49 | * Initializes the widget. 50 | * If you override this method, make sure you call the parent implementation first. 51 | */ 52 | public function init() 53 | { 54 | if ($this->hasModel() && !isset($this->options['id'])) { 55 | $this->options['id'] = Html::getInputId($this->model, $this->attribute); 56 | } 57 | parent::init(); 58 | } 59 | 60 | /** 61 | * @return bool whether this widget is associated with a data model. 62 | */ 63 | protected function hasModel() 64 | { 65 | return $this->model instanceof Model && $this->attribute !== null; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/JuiAsset.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 2.0 15 | */ 16 | class JuiAsset extends AssetBundle 17 | { 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public $sourcePath = '@bower/jquery-ui'; 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public $js = [ 26 | 'jquery-ui.js', 27 | ]; 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | public $css = [ 32 | 'themes/smoothness/jquery-ui.css', 33 | ]; 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public $depends = [ 38 | 'yii\web\JqueryAsset', 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /src/Menu.php: -------------------------------------------------------------------------------- 1 | 17 | * @since 2.0 18 | */ 19 | class Menu extends \yii\widgets\Menu 20 | { 21 | /** 22 | * @var array the options for the underlying jQuery UI widget. 23 | * Please refer to the corresponding jQuery UI widget Web page for possible options. 24 | * For example, [this page](https://api.jqueryui.com/accordion/) shows 25 | * how to use the "Accordion" widget and the supported options (e.g. "header"). 26 | */ 27 | public $clientOptions = []; 28 | /** 29 | * @var array the event handlers for the underlying jQuery UI widget. 30 | * Please refer to the corresponding jQuery UI widget Web page for possible events. 31 | * For example, [this page](https://api.jqueryui.com/accordion/) shows 32 | * how to use the "Accordion" widget and the supported events (e.g. "create"). 33 | */ 34 | public $clientEvents = []; 35 | 36 | 37 | /** 38 | * Initializes the widget. 39 | * If you override this method, make sure you call the parent implementation first. 40 | */ 41 | public function init() 42 | { 43 | parent::init(); 44 | if (!isset($this->options['id'])) { 45 | $this->options['id'] = $this->getId(); 46 | } 47 | } 48 | 49 | /** 50 | * Renders the widget. 51 | */ 52 | public function run() 53 | { 54 | parent::run(); 55 | 56 | $view = $this->getView(); 57 | JuiAsset::register($view); 58 | 59 | $id = $this->options['id']; 60 | if ($this->clientOptions !== false) { 61 | $options = empty($this->clientOptions) ? '' : Json::htmlEncode($this->clientOptions); 62 | $js = "jQuery('#$id').menu($options);"; 63 | $view->registerJs($js); 64 | } 65 | 66 | if (!empty($this->clientEvents)) { 67 | $js = []; 68 | foreach ($this->clientEvents as $event => $handler) { 69 | $js[] = "jQuery('#$id').on('menu$event', $handler);"; 70 | } 71 | $view->registerJs(implode("\n", $js)); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/ProgressBar.php: -------------------------------------------------------------------------------- 1 | [ 20 | * 'value' => 75, 21 | * ], 22 | * ]); 23 | * ``` 24 | * 25 | * The following example will show the content enclosed between the [[begin()]] 26 | * and [[end()]] calls within the widget container: 27 | * 28 | * ~~~php 29 | * ProgressBar::begin([ 30 | * 'clientOptions' => ['value' => 75], 31 | * ]); 32 | * 33 | * echo '
Loading...
'; 34 | * 35 | * ProgressBar::end(); 36 | * ~~~ 37 | * @see https://api.jqueryui.com/progressbar/ 38 | * @author Alexander Kochetov 39 | * @since 2.0 40 | */ 41 | class ProgressBar extends Widget 42 | { 43 | /** 44 | * Initializes the widget. 45 | */ 46 | public function init() 47 | { 48 | parent::init(); 49 | echo Html::beginTag('div', $this->options) . "\n"; 50 | } 51 | 52 | /** 53 | * Renders the widget. 54 | */ 55 | public function run() 56 | { 57 | echo Html::endTag('div') . "\n"; 58 | $this->registerWidget('progressbar'); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Resizable.php: -------------------------------------------------------------------------------- 1 | [ 20 | * 'grid' => [20, 10], 21 | * ], 22 | * ]); 23 | * 24 | * echo 'Resizable contents here...'; 25 | * 26 | * Resizable::end(); 27 | * ``` 28 | * 29 | * @see https://api.jqueryui.com/resizable/ 30 | * @author Alexander Kochetov 31 | * @since 2.0 32 | */ 33 | class Resizable extends Widget 34 | { 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | protected $clientEventMap = [ 39 | 'create' => 'resizecreate', 40 | 'resize' => 'resize', 41 | 'start' => 'resizestart', 42 | 'stop' => 'resizestop', 43 | ]; 44 | 45 | 46 | /** 47 | * Initializes the widget. 48 | */ 49 | public function init() 50 | { 51 | parent::init(); 52 | echo Html::beginTag('div', $this->options) . "\n"; 53 | } 54 | 55 | /** 56 | * Renders the widget. 57 | */ 58 | public function run() 59 | { 60 | echo Html::endTag('div') . "\n"; 61 | $this->registerWidget('resizable'); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Selectable.php: -------------------------------------------------------------------------------- 1 | [ 22 | * 'Item 1', 23 | * [ 24 | * 'content' => 'Item2', 25 | * ], 26 | * [ 27 | * 'content' => 'Item3', 28 | * 'options' => [ 29 | * 'tag' => 'li', 30 | * ], 31 | * ], 32 | * ], 33 | * 'options' => [ 34 | * 'tag' => 'ul', 35 | * ], 36 | * 'itemOptions' => [ 37 | * 'tag' => 'li', 38 | * ], 39 | * 'clientOptions' => [ 40 | * 'tolerance' => 'fit', 41 | * ], 42 | * ]); 43 | * ``` 44 | * 45 | * Selectable in begin mode. 46 | * 47 | * ```php 48 | * Selectable::begin([ 49 | * 'clientOptions' => [ 50 | * 'filter' => 'my-selectable-item', 51 | * 'tolerance' => 'touch', 52 | * ], 53 | * ]); 54 | * ``` 55 | *
    56 | *
  • Item 1
  • 57 | *
  • Item 2
  • 58 | *
  • Item 3
  • 59 | *
  • Item 4
  • 60 | *
61 | *
62 | *
63 | *
Another item
64 | *
65 | *
66 | * 67 | * ```php 68 | * Selectable::end(); 69 | * ``` 70 | * 71 | * @see https://api.jqueryui.com/selectable/ 72 | * @author Alexander Kochetov 73 | * @since 2.0 74 | */ 75 | class Selectable extends Widget 76 | { 77 | const MODE_DEFAULT = 'MODE_DEFAULT'; 78 | const MODE_BEGIN = 'MODE_BEGIN'; 79 | 80 | /** 81 | * @var string the mode used to render the widget. 82 | */ 83 | public $mode = self::MODE_DEFAULT; 84 | /** 85 | * @var array the HTML attributes for the widget container tag. The following special options are recognized: 86 | * 87 | * - tag: string, defaults to "ul", the tag name of the container tag of this widget. 88 | * 89 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 90 | */ 91 | public $options = []; 92 | /** 93 | * @var array list of selectable items. Each item can be a string representing the item content 94 | * or an array of the following structure: 95 | * 96 | * ```php 97 | * [ 98 | * 'content' => 'item content', 99 | * // the HTML attributes of the item container tag. This will overwrite "itemOptions". 100 | * 'options' => [], 101 | * ] 102 | * ``` 103 | */ 104 | public $items = []; 105 | /** 106 | * @var array list of HTML attributes for the item container tags. This will be overwritten 107 | * by the "options" set in individual [[items]]. The following special options are recognized: 108 | * 109 | * - tag: string, defaults to "li", the tag name of the item container tags. 110 | * 111 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 112 | */ 113 | public $itemOptions = []; 114 | 115 | 116 | /** 117 | * Begins a widget. 118 | * This method creates an instance of the calling class setting the MODE_BEGIN mode. Any item between 119 | * [[begin()]] and [[end()]] which match the filter attribute, will be selectable. 120 | * It will apply the configuration 121 | * to the created instance. A matching [[end()]] call should be called later. 122 | * As some widgets may use output buffering, the [[end()]] call should be made in the same view 123 | * to avoid breaking the nesting of output buffers. 124 | * @param array $config name-value pairs that will be used to initialize the object properties 125 | * @return static the newly created widget instance 126 | * @see end() 127 | */ 128 | public static function begin($config = []) { 129 | $config['mode'] = self::MODE_BEGIN; 130 | parent::begin($config); 131 | } 132 | 133 | /** 134 | * Initializes the widget. 135 | */ 136 | public function init() 137 | { 138 | parent::init(); 139 | if ($this->mode === self::MODE_BEGIN) { 140 | echo Html::beginTag('div', $this->options) . "\n"; 141 | } 142 | } 143 | 144 | /** 145 | * Renders the widget. 146 | */ 147 | public function run() 148 | { 149 | if ($this->mode === self::MODE_BEGIN) { 150 | echo Html::endTag('div') . "\n"; 151 | } else { 152 | $options = $this->options; 153 | $tag = ArrayHelper::remove($options, 'tag', 'ul'); 154 | echo Html::beginTag($tag, $options) . "\n"; 155 | echo $this->renderItems() . "\n"; 156 | echo Html::endTag($tag) . "\n"; 157 | } 158 | 159 | $this->registerWidget('selectable'); 160 | } 161 | 162 | /** 163 | * Renders selectable items as specified on [[items]]. 164 | * @return string the rendering result. 165 | * @throws InvalidConfigException. 166 | */ 167 | public function renderItems() 168 | { 169 | $items = []; 170 | foreach ($this->items as $item) { 171 | $options = $this->itemOptions; 172 | $tag = ArrayHelper::remove($options, 'tag', 'li'); 173 | if (is_array($item)) { 174 | if (!array_key_exists('content', $item)) { 175 | throw new InvalidConfigException("The 'content' option is required."); 176 | } 177 | $options = array_merge($options, ArrayHelper::getValue($item, 'options', [])); 178 | $tag = ArrayHelper::remove($options, 'tag', $tag); 179 | $items[] = Html::tag($tag, $item['content'], $options); 180 | } else { 181 | $items[] = Html::tag($tag, $item, $options); 182 | } 183 | } 184 | return implode("\n", $items); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/Slider.php: -------------------------------------------------------------------------------- 1 | [ 18 | * 'min' => 1, 19 | * 'max' => 10, 20 | * ], 21 | * ]); 22 | * ``` 23 | * 24 | * @see https://api.jqueryui.com/slider/ 25 | * @author Alexander Makarov 26 | * @since 2.0 27 | */ 28 | class Slider extends Widget 29 | { 30 | /** 31 | * @inheritDoc 32 | */ 33 | protected $clientEventMap = [ 34 | 'change' => 'slidechange', 35 | 'create' => 'slidecreate', 36 | 'slide' => 'slide', 37 | 'start' => 'slidestart', 38 | 'stop' => 'slidestop', 39 | ]; 40 | 41 | 42 | /** 43 | * Executes the widget. 44 | */ 45 | public function run() 46 | { 47 | echo Html::tag('div', '', $this->options); 48 | $this->registerWidget('slider'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/SliderInput.php: -------------------------------------------------------------------------------- 1 | $model, 20 | * 'attribute' => 'amount', 21 | * 'clientOptions' => [ 22 | * 'min' => 1, 23 | * 'max' => 10, 24 | * ], 25 | * ]); 26 | * ``` 27 | * 28 | * The following example will use the name property instead: 29 | * 30 | * ``` 31 | * echo SliderInput::widget([ 32 | * 'name' => 'amount', 33 | * 'clientOptions' => [ 34 | * 'min' => 1, 35 | * 'max' => 10, 36 | * ], 37 | * ]); 38 | * ``` 39 | * 40 | * You can also use this widget in an [[yii\widgets\ActiveForm|ActiveForm]] using the [[yii\widgets\ActiveField::widget()|widget()]] 41 | * method, for example like this: 42 | * 43 | * ```php 44 | * field($model, 'from_date')->widget(\yii\jui\SliderInput::classname(), [ 45 | * 'clientOptions' => [ 46 | * 'min' => 1, 47 | * 'max' => 10, 48 | * ], 49 | * ]) ?> 50 | * ``` 51 | * 52 | * @see https://api.jqueryui.com/slider/ 53 | * @author Alexander Makarov 54 | * @since 2.0 55 | */ 56 | class SliderInput extends InputWidget 57 | { 58 | /** 59 | * @var array the HTML attributes for the container tag. 60 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 61 | */ 62 | public $containerOptions = []; 63 | 64 | /** 65 | * @inheritDoc 66 | */ 67 | protected $clientEventMap = [ 68 | 'change' => 'slidechange', 69 | 'create' => 'slidecreate', 70 | 'slide' => 'slide', 71 | 'start' => 'slidestart', 72 | 'stop' => 'slidestop', 73 | ]; 74 | 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function init() 80 | { 81 | parent::init(); 82 | if (!isset($this->containerOptions['id'])) { 83 | $this->containerOptions['id'] = $this->options['id'] . '-container'; 84 | } 85 | } 86 | 87 | /** 88 | * Executes the widget. 89 | */ 90 | public function run() 91 | { 92 | echo Html::tag('div', '', $this->containerOptions); 93 | 94 | if ($this->hasModel()) { 95 | echo Html::activeHiddenInput($this->model, $this->attribute, $this->options); 96 | $this->clientOptions['value'] = Html::getAttributeValue($this->model, $this->attribute); 97 | } else { 98 | echo Html::hiddenInput($this->name, $this->value, $this->options); 99 | $this->clientOptions['value'] = $this->value; 100 | } 101 | 102 | if (!isset($this->clientEvents['slide'])) { 103 | $this->clientEvents['slide'] = 'function (event, ui) { 104 | jQuery("#' . $this->options['id'] . '").val(ui.value); 105 | }'; 106 | } 107 | 108 | $this->registerWidget('slider', $this->containerOptions['id']); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Sortable.php: -------------------------------------------------------------------------------- 1 | [ 22 | * 'Item 1', 23 | * ['content' => 'Item2'], 24 | * [ 25 | * 'content' => 'Item3', 26 | * 'options' => ['tag' => 'li'], 27 | * ], 28 | * ], 29 | * 'options' => ['tag' => 'ul'], 30 | * 'itemOptions' => ['tag' => 'li'], 31 | * 'clientOptions' => ['cursor' => 'move'], 32 | * ]); 33 | * ``` 34 | * 35 | * @see https://api.jqueryui.com/sortable/ 36 | * @author Alexander Kochetov 37 | * @since 2.0 38 | */ 39 | class Sortable extends Widget 40 | { 41 | /** 42 | * @var array the HTML attributes for the widget container tag. The following special options are recognized: 43 | * 44 | * - tag: string, defaults to "ul", the tag name of the container tag of this widget. 45 | * 46 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 47 | */ 48 | public $options = []; 49 | /** 50 | * @var array list of sortable items. Each item can be a string representing the item content 51 | * or an array of the following structure: 52 | * 53 | * ```php 54 | * [ 55 | * 'content' => 'item content', 56 | * // the HTML attributes of the item container tag. This will overwrite "itemOptions". 57 | * 'options' => [], 58 | * ] 59 | * ``` 60 | */ 61 | public $items = []; 62 | /** 63 | * @var array list of HTML attributes for the item container tags. This will be overwritten 64 | * by the "options" set in individual [[items]]. The following special options are recognized: 65 | * 66 | * - tag: string, defaults to "li", the tag name of the item container tags. 67 | * 68 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 69 | */ 70 | public $itemOptions = []; 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | protected $clientEventMap = [ 76 | 'activate' => 'sortactivate', 77 | 'beforeStop' => 'sortbeforestop', 78 | 'change' => 'sortchange', 79 | 'create' => 'sortcreate', 80 | 'deactivate' => 'sortdeactivate', 81 | 'out' => 'sortout', 82 | 'over' => 'sortover', 83 | 'receive' => 'sortreceive', 84 | 'remove' => 'sortremove', 85 | 'sort' => 'sort', 86 | 'start' => 'sortstart', 87 | 'stop' => 'sortstop', 88 | 'update' => 'sortupdate', 89 | ]; 90 | 91 | 92 | /** 93 | * Renders the widget. 94 | */ 95 | public function run() 96 | { 97 | $options = $this->options; 98 | $tag = ArrayHelper::remove($options, 'tag', 'ul'); 99 | echo Html::beginTag($tag, $options) . "\n"; 100 | echo $this->renderItems() . "\n"; 101 | echo Html::endTag($tag) . "\n"; 102 | $this->registerWidget('sortable'); 103 | } 104 | 105 | /** 106 | * Renders sortable items as specified on [[items]]. 107 | * @return string the rendering result. 108 | * @throws InvalidConfigException. 109 | */ 110 | public function renderItems() 111 | { 112 | $items = []; 113 | foreach ($this->items as $item) { 114 | $options = $this->itemOptions; 115 | $tag = ArrayHelper::remove($options, 'tag', 'li'); 116 | if (is_array($item)) { 117 | if (!isset($item['content'])) { 118 | throw new InvalidConfigException("The 'content' option is required."); 119 | } 120 | $options = array_merge($options, ArrayHelper::getValue($item, 'options', [])); 121 | $tag = ArrayHelper::remove($options, 'tag', $tag); 122 | $items[] = Html::tag($tag, $item['content'], $options); 123 | } else { 124 | $items[] = Html::tag($tag, $item, $options); 125 | } 126 | } 127 | 128 | return implode("\n", $items); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Spinner.php: -------------------------------------------------------------------------------- 1 | $model, 20 | * 'attribute' => 'country', 21 | * 'clientOptions' => ['step' => 2], 22 | * ]); 23 | * ``` 24 | * 25 | * The following example will use the name property instead: 26 | * 27 | * ```php 28 | * echo Spinner::widget([ 29 | * 'name' => 'country', 30 | * 'clientOptions' => ['step' => 2], 31 | * ]); 32 | * ``` 33 | * 34 | * You can also use this widget in an [[yii\widgets\ActiveForm|ActiveForm]] using the [[yii\widgets\ActiveField::widget()|widget()]] 35 | * method, for example like this: 36 | * 37 | * ```php 38 | * field($model, 'from_date')->widget(\yii\jui\Spinner::classname(), [ 39 | * 'clientOptions' => ['step' => 2], 40 | * ]) ?> 41 | * ``` 42 | * 43 | * @see https://api.jqueryui.com/spinner/ 44 | * @author Alexander Kochetov 45 | * @since 2.0 46 | */ 47 | class Spinner extends InputWidget 48 | { 49 | /** 50 | * @inheritDoc 51 | */ 52 | protected $clientEventMap = [ 53 | 'spin' => 'spin', 54 | 'change' => 'spinchange', 55 | 'create' => 'spincreate', 56 | 'start' => 'spinstart', 57 | 'stop' => 'spinstop' 58 | ]; 59 | 60 | 61 | /** 62 | * Renders the widget. 63 | */ 64 | public function run() 65 | { 66 | echo $this->renderWidget(); 67 | $this->registerWidget('spinner'); 68 | } 69 | 70 | /** 71 | * Renders the Spinner widget. 72 | * @return string the rendering result. 73 | */ 74 | public function renderWidget() 75 | { 76 | if ($this->hasModel()) { 77 | return Html::activeTextInput($this->model, $this->attribute, $this->options); 78 | } 79 | return Html::textInput($this->name, $this->value, $this->options); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Tabs.php: -------------------------------------------------------------------------------- 1 | [ 23 | * [ 24 | * 'label' => 'Tab one', 25 | * 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...', 26 | * ], 27 | * [ 28 | * 'label' => 'Tab two', 29 | * 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...', 30 | * 'options' => ['tag' => 'div'], 31 | * 'headerOptions' => ['class' => 'my-class'], 32 | * ], 33 | * [ 34 | * 'label' => 'Tab with custom id', 35 | * 'content' => 'Morbi tincidunt, dui sit amet facilisis feugiat...', 36 | * 'options' => ['id' => 'my-tab'], 37 | * ], 38 | * [ 39 | * 'label' => 'Ajax tab', 40 | * 'url' => ['ajax/content'], 41 | * ], 42 | * ], 43 | * 'options' => ['tag' => 'div'], 44 | * 'itemOptions' => ['tag' => 'div'], 45 | * 'headerOptions' => ['class' => 'my-class'], 46 | * 'clientOptions' => ['collapsible' => false], 47 | * ]); 48 | * ``` 49 | * 50 | * @see https://api.jqueryui.com/tabs/ 51 | * @author Alexander Kochetov 52 | * @since 2.0 53 | */ 54 | class Tabs extends Widget 55 | { 56 | /** 57 | * @var array the HTML attributes for the widget container tag. The following special options are recognized: 58 | * 59 | * - tag: string, defaults to "div", the tag name of the container tag of this widget. 60 | * 61 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 62 | */ 63 | public $options = []; 64 | /** 65 | * @var array list of tab items. Each item can be an array of the following structure: 66 | * 67 | * - label: string, required, specifies the header link label. When [[encodeLabels]] is true, the label 68 | * will be HTML-encoded. 69 | * - content: string, the content to show when corresponding tab is clicked. Can be omitted if url is specified. 70 | * - url: mixed, mixed, optional, the url to load tab contents via AJAX. It is required if no content is specified. 71 | * - template: string, optional, the header link template to render the header link. If none specified 72 | * [[linkTemplate]] will be used instead. 73 | * - options: array, optional, the HTML attributes of the header. 74 | * - headerOptions: array, optional, the HTML attributes for the header container tag. 75 | */ 76 | public $items = []; 77 | /** 78 | * @var array list of HTML attributes for the item container tags. This will be overwritten 79 | * by the "options" set in individual [[items]]. The following special options are recognized: 80 | * 81 | * - tag: string, defaults to "div", the tag name of the item container tags. 82 | * 83 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 84 | */ 85 | public $itemOptions = []; 86 | /** 87 | * @var array list of HTML attributes for the header container tags. This will be overwritten 88 | * by the "headerOptions" set in individual [[items]]. 89 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 90 | */ 91 | public $headerOptions = []; 92 | /** 93 | * @var string the default header template to render the link. 94 | */ 95 | public $linkTemplate = '{label}'; 96 | /** 97 | * @var boolean whether the labels for header items should be HTML-encoded. 98 | */ 99 | public $encodeLabels = true; 100 | 101 | 102 | /** 103 | * Renders the widget. 104 | */ 105 | public function run() 106 | { 107 | $options = $this->options; 108 | $tag = ArrayHelper::remove($options, 'tag', 'div'); 109 | $out = Html::beginTag($tag, $options) . "\n"; 110 | $out .= $this->renderItems() . "\n"; 111 | $out .= Html::endTag($tag) . "\n"; 112 | 113 | $this->registerWidget('tabs'); 114 | 115 | return $out; 116 | } 117 | 118 | /** 119 | * Renders tab items as specified on [[items]]. 120 | * @return string the rendering result. 121 | * @throws InvalidConfigException. 122 | */ 123 | protected function renderItems() 124 | { 125 | $headers = []; 126 | $items = []; 127 | foreach ($this->items as $n => $item) { 128 | if (!isset($item['label'])) { 129 | throw new InvalidConfigException("The 'label' option is required."); 130 | } 131 | if (isset($item['url'])) { 132 | $url = Url::to($item['url']); 133 | } else { 134 | if (!array_key_exists('content', $item)) { 135 | throw new InvalidConfigException("Either the 'content' or 'url' option is required."); 136 | } 137 | $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); 138 | $tag = ArrayHelper::remove($options, 'tag', 'div'); 139 | if (!isset($options['id'])) { 140 | $options['id'] = $this->options['id'] . '-tab' . $n; 141 | } 142 | $url = '#' . $options['id']; 143 | $items[] = Html::tag($tag, $item['content'], $options); 144 | } 145 | $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); 146 | $template = ArrayHelper::getValue($item, 'template', $this->linkTemplate); 147 | $headers[] = Html::tag('li', strtr($template, [ 148 | '{label}' => $this->encodeLabels ? Html::encode($item['label']) : $item['label'], 149 | '{url}' => $url, 150 | ]), $headerOptions); 151 | } 152 | 153 | return Html::tag('ul', implode("\n", $headers)) . "\n" . implode("\n", $items); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/Widget.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0 17 | */ 18 | class Widget extends \yii\base\Widget 19 | { 20 | /** 21 | * @var array the HTML attributes for the widget container tag. 22 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 23 | */ 24 | public $options = []; 25 | /** 26 | * @var array the options for the underlying jQuery UI widget. 27 | * Please refer to the corresponding jQuery UI widget Web page for possible options. 28 | * For example, [this page](https://api.jqueryui.com/accordion/) shows 29 | * how to use the "Accordion" widget and the supported options (e.g. "header"). 30 | */ 31 | public $clientOptions = []; 32 | /** 33 | * @var array the event handlers for the underlying jQuery UI widget. 34 | * Please refer to the corresponding jQuery UI widget Web page for possible events. 35 | * For example, [this page](https://api.jqueryui.com/accordion/) shows 36 | * how to use the "Accordion" widget and the supported events (e.g. "create"). 37 | * Keys are the event names and values are javascript code that is passed to the `.on()` function 38 | * as the event handler. 39 | * 40 | * For example you could write the following in your widget configuration: 41 | * 42 | * ```php 43 | * 'clientEvents' => [ 44 | * 'change' => 'function () { alert('event "change" occured.'); }' 45 | * ], 46 | * ``` 47 | */ 48 | public $clientEvents = []; 49 | 50 | /** 51 | * @var array event names mapped to what should be specified in `.on()`. 52 | * If empty, it is assumed that event passed to clientEvents is prefixed with widget name. 53 | */ 54 | protected $clientEventMap = []; 55 | 56 | 57 | /** 58 | * Initializes the widget. 59 | * If you override this method, make sure you call the parent implementation first. 60 | */ 61 | public function init() 62 | { 63 | parent::init(); 64 | if (!isset($this->options['id'])) { 65 | $this->options['id'] = $this->getId(); 66 | } 67 | } 68 | 69 | /** 70 | * Registers a specific jQuery UI widget options 71 | * @param string $name the name of the jQuery UI widget 72 | * @param string $id the ID of the widget 73 | */ 74 | protected function registerClientOptions($name, $id) 75 | { 76 | if ($this->clientOptions !== false) { 77 | $options = empty($this->clientOptions) ? '' : Json::htmlEncode($this->clientOptions); 78 | $js = "jQuery('#$id').$name($options);"; 79 | $this->getView()->registerJs($js); 80 | } 81 | } 82 | 83 | /** 84 | * Registers a specific jQuery UI widget events 85 | * @param string $name the name of the jQuery UI widget 86 | * @param string $id the ID of the widget 87 | */ 88 | protected function registerClientEvents($name, $id) 89 | { 90 | if (!empty($this->clientEvents)) { 91 | $js = []; 92 | foreach ($this->clientEvents as $event => $handler) { 93 | if (isset($this->clientEventMap[$event])) { 94 | $eventName = $this->clientEventMap[$event]; 95 | } else { 96 | $eventName = strtolower($name . $event); 97 | } 98 | $js[] = "jQuery('#$id').on('$eventName', $handler);"; 99 | } 100 | $this->getView()->registerJs(implode("\n", $js)); 101 | } 102 | } 103 | 104 | /** 105 | * Registers a specific jQuery UI widget asset bundle, initializes it with client options and registers related events 106 | * @param string $name the name of the jQuery UI widget 107 | * @param string $id the ID of the widget. If null, it will use the `id` value of [[options]]. 108 | */ 109 | protected function registerWidget($name, $id = null) 110 | { 111 | if ($id === null) { 112 | $id = $this->options['id']; 113 | } 114 | JuiAsset::register($this->getView()); 115 | $this->registerClientEvents($name, $id); 116 | $this->registerClientOptions($name, $id); 117 | } 118 | } 119 | --------------------------------------------------------------------------------