├── .gitignore ├── LICENSE ├── LICENSE.md ├── Metronic.php ├── README.md ├── builders └── TreeBuilder.php ├── bundles ├── BaseAssetBundle.php ├── BootboxAsset.php ├── CoreAsset.php ├── DatePickerAsset.php ├── DateRangePickerAsset.php ├── DraggablePortletsAssetBundle.php ├── DropZoneAsset.php ├── FontAsset.php ├── GridViewAsset.php ├── GridViewSortableAsset.php ├── IonRangeSliderAsset.php ├── ListViewAsset.php ├── ListViewSortableAsset.php ├── ModalAsset.php ├── MultiSelectAsset.php ├── NotificationAsset.php ├── Select2Asset.php ├── SpinnerAsset.php ├── StepsLineBundle.php ├── StyleBasedAsset.php ├── TagInputAsset.php ├── ThemeAsset.php └── TreeAsset.php ├── composer.json ├── composer.lock ├── composer └── Installer.php ├── helpers ├── Font.php ├── Html.php └── Layout.php ├── layouts └── main.php ├── traits └── HtmlTrait.php └── widgets ├── Accordion.php ├── ActionColumn.php ├── ActiveField.php ├── ActiveForm.php ├── Alert.php ├── Badge.php ├── Breadcrumbs.php ├── Button.php ├── ButtonDropdown.php ├── ButtonGroup.php ├── CheckboxList.php ├── DatePicker.php ├── DateRangePicker.php ├── Decorator.php ├── DetailView.php ├── DraggablePortlets.php ├── DropZone.php ├── Dropdown.php ├── DropdownContent.php ├── GridView.php ├── HorizontalMenu.php ├── InputWidget.php ├── IonRangeSlider.php ├── Link.php ├── ListView.php ├── Menu.php ├── Modal.php ├── MultiSelect.php ├── Nav.php ├── NavBar.php ├── Note.php ├── Notification.php ├── Panel.php ├── Portlet.php ├── Ribbon.php ├── Select2.php ├── Spinner.php ├── StepsLine.php ├── Tabs.php ├── TagInput.php ├── TextInputWidget.php ├── Tree.php └── Widget.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /nbproject/private/ 3 | /nbproject/ 4 | /vendor/ 5 | assets/* 6 | !assets/.gitignore 7 | protected/runtime/* 8 | !protected/runtime/.gitignore 9 | protected/data/*.db 10 | themes/classic/views/ 11 | assets 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, jirisvoboda 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 are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of yii2-metronic nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The Yii2Metronic is free software. It is released under the terms of 2 | the following BSD License. 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 Yii2Metronic 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. -------------------------------------------------------------------------------- /Metronic.php: -------------------------------------------------------------------------------- 1 | sidebarOption && self::SIDEBAR_MENU_HOVER === $this->sidebarMenu) { 241 | throw new InvalidConfigException('Hover Sidebar Menu is not compatible with Fixed Sidebar Mode. Select Default Sidebar Mode Instead.'); 242 | } 243 | 244 | if (!$this->resources) { 245 | throw new InvalidConfigException('You have to specify resources locations to be able to create symbolic links. Specify "admin" and "global" theme folder locations.'); 246 | } 247 | 248 | if (!is_link(self::ASSETS_LINK) && !is_dir(self::ASSETS_LINK)) { 249 | symlink($this->resources, self::ASSETS_LINK); 250 | } 251 | } 252 | 253 | public function parseAssetsParams(&$string) 254 | { 255 | if (preg_match('/\{[a-z]+\}/', $string)) { 256 | $string = str_replace(static::PARAM_VERSION, $this->version, $string); 257 | 258 | $string = str_replace(static::PARAM_THEME, $this->theme, $string); 259 | } 260 | } 261 | 262 | /** 263 | * @return Metronic Get Metronic component 264 | */ 265 | public static function getComponent() 266 | { 267 | try { 268 | return \Yii::$app->get(static::$componentName); 269 | } catch (InvalidConfigException $ex) { 270 | return null; 271 | } 272 | } 273 | 274 | /** 275 | * Get base url to metronic assets 276 | * @param $view View 277 | * @return string 278 | */ 279 | public static function getAssetsUrl($view) 280 | { 281 | if (static::$assetsBundle === null) { 282 | static::$assetsBundle = static::registerThemeAsset($view); 283 | } 284 | 285 | return (static::$assetsBundle instanceof AssetBundle) ? static::$assetsBundle->baseUrl : ''; 286 | } 287 | 288 | /** 289 | * Register Theme Asset 290 | * @param $view View 291 | * @return AssetBundle 292 | */ 293 | public static function registerThemeAsset($view) 294 | { 295 | return static::$assetsBundle = ThemeAsset::register($view); 296 | } 297 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yii2-metronic 2 | Yii2 [Metronic theme](http://www.keenthemes.com/) integration. Currently is supported the version 4.6 3 | 4 | Requirements 5 | ------------ 6 | To use this extension it is required to buy own license for Metronic theme from https://themeforest.net/item/metronic-responsive-admin-dashboard-template/4021469?ref=keenthemes 7 | 8 | Installation 9 | ------------ 10 | 11 | The extension is in development and the only way to use this fork is through through [composer](http://getcomposer.org/download/). 12 | 13 | 14 | So add it to your composer.json with this composer command: 15 | ``` 16 | php composer.phar require dlds/yii2-metronic dev-master 17 | ``` 18 | 19 | 20 | Then You've to unzip the contents of your metronic Zip theme inside the ```@webroot/metronic``` folder. Check [Aliases](http://www.yiiframework.com/doc-2.0/guide-concept-aliases.html). 21 | 22 | You should have a folder structure like this: 23 | 24 | * app/ 25 | * web/ 26 | * metronic/ 27 | * _documentation 28 | * _resources 29 | * _start 30 | * theme 31 | * theme_rtl 32 | 33 | 34 | 35 | Quick Start 36 | ----------- 37 | Edit your ```config/web.php``` configuration file and add the metronic component: 38 | 39 | ``` 40 | 'components' => [ 41 | 'metronic'=>[ 42 | 'class'=>'dlds\metronic\Metronic', 43 | 'resources'=>'[path to my web]/web/metronic/assets/theme/assets', 44 | 'style'=>\dlds\metronic\Metronic::STYLE_MATERIAL, 45 | 'theme'=>\dlds\metronic\Metronic::THEME_LIGHT, 46 | 'layoutOption'=>\dlds\metronic\Metronic::LAYOUT_FLUID, 47 | 'headerOption'=>\dlds\metronic\Metronic::HEADER_FIXED, 48 | 'sidebarPosition'=>\dlds\metronic\Metronic::SIDEBAR_POSITION_LEFT, 49 | 'sidebarOption'=>\dlds\metronic\Metronic::SIDEBAR_MENU_ACCORDION, 50 | 'footerOption'=>\dlds\metronic\Metronic::FOOTER_FIXED, 51 | 52 | ], 53 | ] 54 | ``` 55 | 56 | **WARNING** 57 | Check the "resources" key. This component field is used to locate the content of the zip theme. 58 | The component try to create a symlink to this directory inside it's folder. **Eventually this may not work!** 59 | In the case the link is invalid, you've to build it by yourself :) 60 | 61 | My vendor folder looks like this: 62 | 63 | * app/ 64 | * [...] 65 | * vendor/ 66 | * dlds/ 67 | * yii2-metronic/ 68 | * assets -> symlink to /var/www/project/web/metronic/assets/theme/assets 69 | * builders/ 70 | * bundles/ 71 | * helpers/ 72 | * layouts/ 73 | * widgets/ 74 | 75 | 76 | I suggest also to configure the assetManager. My actual configuration is this: 77 | ``` 78 | 'assetManager' => [ 79 | 'linkAssets' => true, 80 | 'bundles' => [ 81 | 'yii\web\JqueryAsset' => [ 82 | 'sourcePath' => null, // do not publish the bundle 83 | 'js' => [ 84 | '//code.jquery.com/jquery-1.11.2.min.js', // use custom jquery 85 | ] 86 | ], 87 | 88 | 'dlds\metronic\bundles\ThemeAsset' => [ 89 | 'addons'=>[ 90 | 'default/login'=>[ 91 | 'css'=>[ 92 | 'pages/css/login-4.min.css', 93 | ], 94 | 'js'=>[ 95 | 'global/plugins/backstretch/jquery.backstretch.min.js', 96 | 97 | ] 98 | ], 99 | ] 100 | ], 101 | ], 102 | ], 103 | ``` 104 | 105 | In the ThemeAsset class i've added the support for addons. You can specify additional css/js for specific controller/action. 106 | 107 | In the example is visible the way to add login-4.min.css and jquery.backstretch.min.js to the login page (in my case, the actionLogin is managed by a controller named DefaultController). 108 | 109 | Configuring the layout for your views is the last step. 110 | 111 | The metronic component contains a sample layout view. I've not checked it. I'm working on my layout :) 112 | 113 | Here is my sample ```views/layout/main.php```: 114 | 115 | ``` 116 | assetManager->getPublishedUrl($asset->sourcePath); 128 | ?> 129 | beginPage() ?> 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | <?= Html::encode($this->title) ?> 141 | head() ?> 142 | 143 | 'page-container-bg-solid'],true) ?>> 144 | beginBody() ?> 145 | 146 | render('parts/header.php', ['directoryAsset' => $directoryAsset]) ?> 147 | 148 | 149 |
150 | render('parts/sidebar.php', ['directoryAsset' => $directoryAsset]) ?> 151 | 152 | render('parts/content.php', ['content' => $content, 'directoryAsset' => $directoryAsset]) ?> 153 |
154 | render('parts/footer.php', ['directoryAsset' => $directoryAsset]) ?> 155 | 156 | endBody() ?> 157 | 158 | 159 | 160 | endPage() ?> 161 | ``` 162 | 163 | Metronic theme require that you replace yii\helpers\Html with it's helper. So, you have to add a ```config/bootstrap.php``` with the following content: 164 | 165 | ``` 166 | 169 | ``` 170 | 171 | The file bootstrap.php should be loaded before the web application is created. So you need to edit your ```web/index.php``` file 172 | and adjust it, and add a require directive. The file content should look like this: 173 | 174 | ``` 175 | run(); 187 | ``` 188 | 189 | Things to notice: 190 | 191 | * I've moved the rendering of the main parts to separate files (parts/*). You can build this files and add them to your project. 192 | * I pass everywhere the $directoryAsset variable: this contain the path to the assets. Useful to load images bundled with the metronic theme. 193 | * the BODY tag is managed with a Layout::getHtmlOptions(). This method is able to build all the Metronic required classes. 194 | * Always check to use $this->beginPage(), $this->beginBody() and relatives $this->endBody() and $this->endPage() in the proper places :) 195 | 196 | -------------------------------------------------------------------------------- /builders/TreeBuilder.php: -------------------------------------------------------------------------------- 1 | _items = $items; 65 | 66 | $this->setParams($params); 67 | } 68 | 69 | /** 70 | * Retrieves new instance of MTreeBuilder 71 | * @param array $items given items to traverse 72 | */ 73 | public static function instance($items, $params = array()) 74 | { 75 | return new self($items, $params); 76 | } 77 | 78 | /** 79 | * Build tree from given items 80 | */ 81 | public function build() 82 | { 83 | return $this->renderTree(); 84 | } 85 | 86 | /** 87 | * Sets class params 88 | * @param array $params given params 89 | * @throws Exception if param does not exists 90 | */ 91 | public function setParams($params) 92 | { 93 | foreach ($params as $param => $value) 94 | { 95 | if (!property_exists($this, $param)) 96 | { 97 | throw new Exception(Yii::t('app', 'Class {class} has no param called "{param}."', array( 98 | '{class}' => get_class($this), 99 | '{param}' => $param 100 | ))); 101 | } 102 | 103 | $this->{$param} = $value; 104 | } 105 | } 106 | 107 | /** 108 | * Renders tree 109 | * @return string html 110 | */ 111 | protected function renderTree() 112 | { 113 | $html = ''; 114 | 115 | $level = -1; 116 | 117 | foreach ($this->_items as $model) 118 | { 119 | if (is_array($model)){ 120 | $model = (object) $model; 121 | } 122 | 123 | if ($model->{$this->levelAttr} == $level) 124 | { 125 | $html .= $this->renderItemClose(); 126 | } 127 | else if ($model->{$this->levelAttr} > $level) 128 | { 129 | $html .= $this->renderTreeOpen(); 130 | } 131 | else 132 | { 133 | $html .= $this->renderItemClose(); 134 | 135 | for ($i = $level - $model->{$this->levelAttr}; $i; $i--) 136 | { 137 | $html .= $this->renderTreeClose(); 138 | 139 | $html .= $this->renderItemClose(); 140 | } 141 | } 142 | 143 | $html .= $this->renderItemOpen($model->primaryKey); 144 | 145 | $html .= Html::tag('i','', [ 146 | 'class' => 'jstree-icon jstree-ocl', 147 | 'role' => 'presentation' 148 | ] 149 | ); 150 | 151 | if (is_callable($this->contentCallback)) 152 | { 153 | $html .= $this->renderContent(call_user_func($this->contentCallback, $model, $level)); 154 | } 155 | else 156 | { 157 | $html .= $this->renderContent($model); 158 | } 159 | 160 | 161 | $level = $model->{$this->levelAttr}; 162 | } 163 | 164 | for ($i = $level; $i; $i--) 165 | { 166 | $html .= $this->renderItemClose(); 167 | $html .= $this->renderTreeClose(); 168 | } 169 | 170 | return $html; 171 | } 172 | 173 | /** 174 | * Renders tree open tag 175 | * @return string html 176 | */ 177 | protected function renderTreeOpen() 178 | { 179 | $options = $this->getHtmlOptions($this->treeHtmlOptions); 180 | 181 | return Html::beginTag($this->treeTag, $options); 182 | } 183 | 184 | /** 185 | * Renders item open tag 186 | * @return string html 187 | */ 188 | protected function renderItemOpen($id) 189 | { 190 | $options = $this->getHtmlOptions($this->itemHtmlOptions, $id); 191 | 192 | return Html::beginTag($this->itemTag, $options); 193 | } 194 | 195 | /** 196 | * Renders item content 197 | */ 198 | protected function renderContent($content) 199 | { 200 | if ($this->contentTag) 201 | { 202 | $options = $this->getHtmlOptions($this->contentHtmlOptions); 203 | 204 | return Html::tag($this->contentTag, $options, $content); 205 | } 206 | 207 | return $content; 208 | } 209 | 210 | /** 211 | * Renders item close tag 212 | * @return string html 213 | */ 214 | protected function renderItemClose() 215 | { 216 | return Html::endTag($this->itemTag); 217 | } 218 | 219 | /** 220 | * Renders tree close tag 221 | * @return string html 222 | */ 223 | protected function renderTreeClose() 224 | { 225 | return Html::endTag($this->treeTag); 226 | } 227 | 228 | /** 229 | * Retrieves html options for given property 230 | * @return array html options 231 | */ 232 | protected function getHtmlOptions($property, $attr = null) 233 | { 234 | if (is_callable($property)) 235 | { 236 | return (array) $property->__invoke($attr); 237 | } 238 | 239 | return (array) $property; 240 | } 241 | } -------------------------------------------------------------------------------- /bundles/BaseAssetBundle.php: -------------------------------------------------------------------------------- 1 | css as $k=>$v) { 21 | if (strpos($v,'.min.css')===false) { 22 | $fileName = str_replace('.css','.min.css',$v); 23 | $newFile = \Yii::getAlias($this->sourcePath) .'/'. $fileName; 24 | if (!file_exists($newFile)) { 25 | $fileName = $v; 26 | } 27 | $this->css[$k] = defined(YII_ENV_DEV) ? $v : $fileName; 28 | } 29 | } 30 | foreach($this->js as $k=>$v) { 31 | if (strpos($v,'.min.js')===false) { 32 | $fileName = str_replace('.css','.min.css',$v); 33 | $newFile = \Yii::getAlias($this->sourcePath) .'/'. $fileName; 34 | if (!file_exists($newFile)) { 35 | $fileName = $v; 36 | } 37 | $this->js[$k] = defined(YII_ENV_DEV) ? $v : $fileName; 38 | } 39 | } 40 | parent::init(); // TODO: Change the autogenerated stub 41 | } 42 | } -------------------------------------------------------------------------------- /bundles/BootboxAsset.php: -------------------------------------------------------------------------------- 1 | view->registerJs(' 23 | yii.confirm = function(message, ok, cancel) { 24 | bootbox.confirm({ 25 | title: "Confirm", 26 | message: message, 27 | callback: function(result) { if (result) { !ok || ok(); } else { !cancel || cancel(); } } 28 | }); 29 | } 30 | '); 31 | } 32 | } -------------------------------------------------------------------------------- /bundles/CoreAsset.php: -------------------------------------------------------------------------------- 1 | [ 36 | 'plugins/respond.min.js' => 'if lt IE 9', 37 | 'plugins/excanvas.min.js' => 'if lt IE 9', 38 | ], 39 | ]; 40 | 41 | /** 42 | * @var array js assets 43 | */ 44 | public $js = [ 45 | // 'global/plugins/jquery.min.js', 46 | 'global/plugins/jquery-migrate.min.js', 47 | 'global/plugins/jquery-ui/jquery-ui.min.js', 48 | // 'global/plugins/bootstrap/js/bootstrap.min.js', 49 | 'global/plugins/jquery-slimscroll/jquery.slimscroll.min.js', 50 | 'global/plugins/jquery.blockui.min.js', 51 | 'global/plugins/bootstrap-hover-dropdown/bootstrap-hover-dropdown.min.js', 52 | 'global/plugins/bootstrap-switch/js/bootstrap-switch.min.js', 53 | 54 | 55 | ]; 56 | } 57 | -------------------------------------------------------------------------------- /bundles/DatePickerAsset.php: -------------------------------------------------------------------------------- 1 | js = array_merge($this->js, static::$extraJs); 28 | parent::init(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /bundles/DateRangePickerAsset.php: -------------------------------------------------------------------------------- 1 | true 27 | ]; 28 | } -------------------------------------------------------------------------------- /bundles/FontAsset.php: -------------------------------------------------------------------------------- 1 | metronic; 40 | if (isset($component->ionSliderSkin)) { 41 | $skin = $component->ionSliderSkin; 42 | } 43 | 44 | $base = 'global/plugins/ion.rangeslider/css/ion.rangeSlider.%s.css'; 45 | $this->css[] = sprintf($base, $skin); 46 | 47 | parent::init(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /bundles/ListViewAsset.php: -------------------------------------------------------------------------------- 1 | [ 32 | 'global/css/components.css', 33 | 'global/css/plugins.css', 34 | ], 35 | Metronic::STYLE_ROUNDED => [ 36 | 'global/css/components-rounded.css', 37 | 'global/css/plugins.css', 38 | ], 39 | Metronic::STYLE_MATERIAL => [ 40 | 'global/css/components-md.css', 41 | 'global/css/plugins-md.css', 42 | ] 43 | ]; 44 | 45 | /** 46 | * Inits bundle 47 | */ 48 | public function init() 49 | { 50 | $this->_handleStyleBased(); 51 | 52 | return parent::init(); 53 | } 54 | 55 | /** 56 | * Handles style based files 57 | */ 58 | private function _handleStyleBased() 59 | { 60 | if (Metronic::getComponent()) 61 | { 62 | $css = $this->styleBasedCss[Metronic::getComponent()->style]; 63 | $this->css = ArrayHelper::merge($css, $this->css); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /bundles/TagInputAsset.php: -------------------------------------------------------------------------------- 1 | _handleSourcePath(); 53 | 54 | $this->_handleAddons(); 55 | 56 | $this->_handleDynamicCss(); 57 | 58 | $this->_handleDynamicJs(); 59 | 60 | return parent::init(); 61 | } 62 | 63 | /** 64 | * Parses source path 65 | */ 66 | private function _handleSourcePath() 67 | { 68 | if (Metronic::getComponent()) 69 | { 70 | Metronic::getComponent()->parseAssetsParams($this->sourcePath); 71 | } 72 | } 73 | 74 | /** 75 | * Parses dynamic css 76 | */ 77 | private function _handleDynamicCss() 78 | { 79 | $component = Metronic::getComponent(); 80 | 81 | if ($component) 82 | { 83 | array_walk($this->css, [$component, 'parseAssetsParams']); 84 | } 85 | } 86 | 87 | /** 88 | * Parses dynamic js 89 | */ 90 | private function _handleDynamicJs() 91 | { 92 | $component = Metronic::getComponent(); 93 | 94 | if ($component) 95 | { 96 | array_walk($this->js, [$component, 'parseAssetsParams']); 97 | } 98 | } 99 | 100 | private function _handleAddons() { 101 | $controller = Yii::$app->controller->id .'/'. Yii::$app->controller->action->id; 102 | if (array_key_exists($controller, $this->addons)) { 103 | $additional = $this->addons[$controller]; 104 | if (array_key_exists('js',$additional) && is_array($additional['js'])) { 105 | $this->js = array_merge($this->js, $additional['js']); 106 | } 107 | if (array_key_exists('css',$additional) && is_array($additional['css'])) { 108 | $this->css = array_merge($this->css, $additional['css']); 109 | } 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /bundles/TreeAsset.php: -------------------------------------------------------------------------------- 1 | style) 42 | { 43 | Html::addCssClass($options, 'page-md'); 44 | } 45 | 46 | if (Metronic::getComponent() && Metronic::LAYOUT_BOXED === Metronic::getComponent()->layoutOption) 47 | { 48 | Html::addCssClass($options, 'page-boxed'); 49 | } 50 | 51 | if (Metronic::getComponent() && Metronic::HEADER_FIXED === Metronic::getComponent()->headerOption) 52 | { 53 | Html::addCssClass($options, 'page-header-fixed'); 54 | } 55 | 56 | if (Metronic::getComponent() && Metronic::SIDEBAR_POSITION_RIGHT === Metronic::getComponent()->sidebarPosition) 57 | { 58 | Html::addCssClass($options, 'page-sidebar-reversed'); 59 | } 60 | 61 | if (Metronic::getComponent() && Metronic::SIDEBAR_FIXED === Metronic::getComponent()->sidebarOption) 62 | { 63 | Html::addCssClass($options, 'page-sidebar-fixed'); 64 | } 65 | 66 | if (Metronic::getComponent() && Metronic::FOOTER_FIXED === Metronic::getComponent()->footerOption) 67 | { 68 | Html::addCssClass($options, 'page-footer-fixed'); 69 | } 70 | 71 | return $options; 72 | } 73 | 74 | /** 75 | * Adds header tag options 76 | * @param array $options given options 77 | */ 78 | private static function _headerOptions($options) 79 | { 80 | Html::addCssClass($options, 'page-header navbar'); 81 | 82 | if (Metronic::getComponent() && Metronic::HEADER_FIXED === Metronic::getComponent()->headerOption) 83 | { 84 | Html::addCssClass($options, 'navbar-fixed-top'); 85 | } 86 | else 87 | { 88 | Html::addCssClass($options, 'navbar-static-top'); 89 | } 90 | 91 | return $options; 92 | } 93 | 94 | /** 95 | * Adds actions tag options 96 | * @param array $options given options 97 | */ 98 | private static function _actionsOptions($options) 99 | { 100 | Html::addCssClass($options, 'page-actions'); 101 | 102 | return $options; 103 | } 104 | 105 | /** 106 | * Adds top tag options 107 | * @param array $options given options 108 | */ 109 | private static function _topOptions($options) 110 | { 111 | Html::addCssClass($options, 'page-top'); 112 | 113 | return $options; 114 | } 115 | 116 | /** 117 | * Adds topmenu tag options 118 | * @param array $options given options 119 | */ 120 | private static function _topmenuOptions($options) 121 | { 122 | Html::addCssClass($options, 'top-menu'); 123 | 124 | return $options; 125 | } 126 | 127 | /** 128 | * Adds container tag options 129 | * @param array $options given options 130 | */ 131 | private static function _containerOptions($options) 132 | { 133 | Html::addCssClass($options, 'container'); 134 | 135 | return $options; 136 | } 137 | 138 | /** 139 | * Adds clearfix tag options 140 | * @param array $options given options 141 | */ 142 | private static function _clearfixOptions($options) 143 | { 144 | Html::addCssClass($options, 'clearfix'); 145 | 146 | return $options; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /traits/HtmlTrait.php: -------------------------------------------------------------------------------- 1 | $condition) { 43 | if (strpos($url, $file) !== false) { 44 | unset($options['conditions']); 45 | return static::conditionalComment(static::tag('link', '', $options), $condition); 46 | } 47 | } 48 | } 49 | unset($options['conditions']); 50 | 51 | return static::tag('link', '', $options); 52 | } 53 | 54 | /** 55 | * Generates a script tag that refers to an external JavaScript file. 56 | * @param string $url the URL of the external JavaScript file. This parameter will be processed by [[\yii\helpers\Url::to()]]. 57 | * @param array $options the tag options in terms of name-value pairs. These will be rendered as 58 | * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. 59 | * If a value is null, the corresponding attribute will not be rendered. 60 | * See [[renderTagAttributes()]] for details on how attributes are being rendered. 61 | * @return string the generated script tag 62 | * @see \yii\helpers\Url::to() 63 | */ 64 | public static function jsFile($url, $options = []) 65 | { 66 | $options['src'] = Url::to($url); 67 | if (!empty($options['conditions'])) { 68 | foreach ($options['conditions'] as $file => $condition) { 69 | if (strpos($url, $file) !== false) { 70 | unset($options['conditions']); 71 | return static::conditionalComment(static::tag('script', '', $options), $condition); 72 | } 73 | } 74 | } 75 | unset($options['conditions']); 76 | 77 | return static::tag('script', '', $options); 78 | } 79 | 80 | /** 81 | * Generates conditional comments such as ''. 82 | * @param $content string the commented content 83 | * @param $condition string condition. Can contain 'if...' or '' 84 | * @return string the generated result 85 | */ 86 | public static function conditionalComment($content, $condition) 87 | { 88 | $condition = strpos($condition, '') !== false ? ''; 93 | 94 | return implode("\n", $lines); 95 | } 96 | 97 | /** 98 | * @inheritdoc 99 | */ 100 | public static function dropDownList($name, $selection = null, $items = [], $options = [], $standardSelect = false) 101 | { 102 | if (!$standardSelect) { 103 | Select2Asset::register(\Yii::$app->view); 104 | 105 | self::addCssClass($options, static::$_clsSelect2); 106 | 107 | self::addData($options, 'placeholder', '-'); 108 | } 109 | 110 | return parent::dropDownList($name, $selection, $items, $options); 111 | } 112 | 113 | /** 114 | * @inheritdoc 115 | */ 116 | public static function activeDropDownList($model, $attribute, $items, $options = [], $standardSelect = false) 117 | { 118 | if (!$standardSelect) { 119 | Select2Asset::register(\Yii::$app->view); 120 | 121 | self::addCssClass($options, static::$_clsSelect2); 122 | 123 | self::addData($options, 'placeholder', '-'); 124 | } 125 | 126 | return parent::activeDropDownList($model, $attribute, $items, $options); 127 | } 128 | 129 | /** 130 | * Adds data attribute to element options 131 | * @param type $key 132 | * @param type $value 133 | * @param type $replace 134 | */ 135 | protected static function addData(&$options, $key, $value, $replace = false) 136 | { 137 | $placeholder = ArrayHelper::getValue($options, sprintf('data.%s', $key), null); 138 | 139 | if (null === $placeholder || $replace) { 140 | $options['data'][$key] = $value; 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /widgets/Accordion.php: -------------------------------------------------------------------------------- 1 | [ 21 | * [ 22 | * 'header' => 'Item 1', 23 | * 'content' => 'Content 1...', 24 | * // open its content by default 25 | * 'contentOptions' => ['class' => 'in'], 26 | * 'type' => Accordion::ITEM_TYPE_SUCCESS, 27 | * ], 28 | * [ 29 | * 'header' => 'Item 2', 30 | * 'content' => 'Content 2...', 31 | * ], 32 | * ], 33 | * 'itemConfig' => ['showIcon' => true], 34 | *]); 35 | * ``` 36 | * 37 | * @see http://getbootstrap.com/javascript/#collapse 38 | */ 39 | class Accordion extends Widget 40 | { 41 | // Item types 42 | const ITEM_TYPE_DEFAULT = 'default'; 43 | const ITEM_TYPE_SUCCESS = 'success'; 44 | const ITEM_TYPE_DANGER = 'danger'; 45 | const ITEM_TYPE_WARNING = 'warning'; 46 | const ITEM_TYPE_INFO = 'info'; 47 | 48 | /** 49 | * @var array list of groups in the collapse widget. Each array element represents a single 50 | * group with the following structure: 51 | * 52 | * ```php 53 | * [ 54 | * // required, the header (HTML) of the group 55 | * 'header' => 'Item 1', 56 | * // required, the content (HTML) of the group 57 | * 'content' => '', 58 | * // optional the HTML attributes of the content group 59 | * 'contentOptions' => [], 60 | * // optional, the HTML attributes of the group 61 | * 'options' => [], 62 | * // optional, the item type. Valid values are 'default', 'success', 'danger', 'warning', 'info' 63 | * // Determines color of the item. 64 | * 'type' => '', 65 | * ] 66 | * ``` 67 | */ 68 | public $items = []; 69 | /** 70 | * @var array the default configuration used by item. 71 | */ 72 | public $itemConfig = []; 73 | 74 | /** 75 | * Initializes the widget. 76 | */ 77 | public function init() 78 | { 79 | parent::init(); 80 | Html::addCssClass($this->options, 'panel-group accordion'); 81 | } 82 | 83 | /** 84 | * Renders the widget. 85 | */ 86 | public function run() 87 | { 88 | echo Html::beginTag('div', $this->options) . "\n"; 89 | echo $this->renderItems() . "\n"; 90 | echo Html::endTag('div') . "\n"; 91 | $this->registerPlugin('collapse'); 92 | } 93 | 94 | /** 95 | * Renders collapsible items as specified on [[items]]. 96 | * @return string the rendering result 97 | * @throws InvalidConfigException. 98 | */ 99 | public function renderItems() 100 | { 101 | $items = []; 102 | $index = 0; 103 | foreach ($this->items as $item) { 104 | if (!isset($item['header'])) { 105 | throw new InvalidConfigException("The 'header' option is required."); 106 | } 107 | if (!isset($item['content'])) { 108 | throw new InvalidConfigException("The 'content' option is required."); 109 | } 110 | 111 | $options = ArrayHelper::getValue($item, 'options', []); 112 | $type = ArrayHelper::getValue($item, 'type', self::ITEM_TYPE_DEFAULT); 113 | Html::addCssClass($options, 'panel panel-' . $type); 114 | $items[] = Html::tag('div', $this->renderItem(array_merge($this->itemConfig, $item), ++$index), $options); 115 | } 116 | 117 | return implode("\n", $items); 118 | } 119 | 120 | /** 121 | * Renders a single collapsible item group 122 | * @param array $item a single item from [[items]] 123 | * @param integer $index the item index as each item group content must have an id 124 | * @return string the rendering result 125 | * @throws InvalidConfigException 126 | */ 127 | protected function renderItem($item, $index) 128 | { 129 | $options = ArrayHelper::getValue($item, 'options', []); 130 | $type = ArrayHelper::getValue($item, 'type', self::ITEM_TYPE_DEFAULT); 131 | Html::addCssClass($options, 'panel panel-' . $type); 132 | $id = $this->options['id'] . '-collapse' . $index; 133 | $options = ArrayHelper::getValue($item, 'contentOptions', []); 134 | $options['id'] = $id; 135 | Html::addCssClass($options, 'panel-collapse collapse'); 136 | $styled = ''; 137 | if (ArrayHelper::getValue($item, 'showIcon', false)) { 138 | if (preg_match('/[^\w]*in[^\w]*/', $options['class'])) { 139 | $styled = 'accordion-toggle-styled'; 140 | } else { 141 | $styled = 'accordion-toggle-styled collapsed'; 142 | } 143 | } 144 | $headerToggle = Html::a( 145 | $item['header'], 146 | '#' . $id, 147 | [ 148 | 'class' => 'accordion-toggle ' . $styled, 149 | 'data-toggle' => 'collapse', 150 | 'data-parent' => '#' . $this->options['id'] 151 | ] 152 | ) . "\n"; 153 | 154 | $header = Html::tag('h4', $headerToggle, ['class' => 'panel-title']); 155 | $content = Html::tag('div', $item['content'], ['class' => 'panel-body']) . "\n"; 156 | 157 | $group = []; 158 | $group[] = Html::tag('div', $header, ['class' => 'panel-heading']); 159 | $group[] = Html::tag('div', $content, $options); 160 | 161 | return implode("\n", $group); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /widgets/ActionColumn.php: -------------------------------------------------------------------------------- 1 | 'text-center']; 18 | 19 | /** 20 | * @var array the HTML options for the data cell tags. 21 | */ 22 | public $contentOptions = ['class' => 'text-center']; 23 | 24 | /** 25 | * @var string the template that is used to render the content in each data cell. 26 | */ 27 | public $template = '{update}'; 28 | 29 | /** 30 | * @var string the icon for the view button. 31 | */ 32 | public $viewButtonIcon = 'icon-eye'; 33 | 34 | /** 35 | * @var string the icon for the update button. 36 | */ 37 | public $updateButtonIcon = 'icon-pencil'; 38 | 39 | /** 40 | * @var string the icon for the delete button. 41 | */ 42 | public $deleteButtonIcon = 'icon-trash'; 43 | 44 | /** 45 | * @var string the icon for the delete button. 46 | */ 47 | public $resetButtonIcon = 'icon-close'; 48 | 49 | /** 50 | * @var mixed array pager settings or false to disable pager 51 | */ 52 | public $pageSizeOptions = [20 => 20, 50 => 50]; 53 | 54 | /** 55 | * @var string btn view class 56 | */ 57 | public $btnViewClass = 'action-view'; 58 | 59 | /** 60 | * @var string btn update class 61 | */ 62 | public $btnUpdateClass = 'action-update'; 63 | 64 | /** 65 | * @var string btn delete class 66 | */ 67 | public $btnDeleteClass = 'action-delete'; 68 | 69 | /** 70 | * @var mixed filter reset route 71 | */ 72 | public $routeFilterReset = null; 73 | 74 | /** 75 | * Initializes the default button rendering callbacks. 76 | */ 77 | protected function initDefaultButtons() 78 | { 79 | if (!isset($this->buttons['view'])) 80 | { 81 | $this->buttons['view'] = function ($url, $model, $key) { 82 | return Html::a('', $url, [ 83 | 'title' => \Yii::t('yii', 'View'), 84 | 'data-pjax' => '0', 85 | 'class' => $this->btnViewClass, 86 | ]); 87 | }; 88 | } 89 | if (!isset($this->buttons['update'])) 90 | { 91 | $this->buttons['update'] = function ($url, $model, $key) { 92 | return Html::a('', $url, [ 93 | 'title' => \Yii::t('yii', 'Update'), 94 | 'data-pjax' => '0', 95 | 'class' => $this->btnUpdateClass, 96 | ]); 97 | }; 98 | } 99 | if (!isset($this->buttons['delete'])) 100 | { 101 | $this->buttons['delete'] = function ($url, $model, $key) { 102 | return Html::a('', $url, [ 103 | 'title' => \Yii::t('yii', 'Delete'), 104 | 'data-confirm' => \Yii::t('yii', 'Are you sure you want to delete this item?'), 105 | 'data-method' => 'post', 106 | 'data-pjax' => '0', 107 | 'class' => $this->btnDeleteClass, 108 | ]); 109 | }; 110 | } 111 | } 112 | 113 | /** 114 | * @inheritdoc 115 | */ 116 | protected function renderHeaderCellContent() 117 | { 118 | if (!$this->routeFilterReset) 119 | { 120 | $route = \Yii::$app->controller->getRoute(); 121 | 122 | if (!\yii\helpers\StringHelper::startsWith($route, '/')) 123 | { 124 | $route = '/'.$route; 125 | } 126 | 127 | $this->routeFilterReset = [$route]; 128 | } 129 | 130 | return Html::a('', $this->routeFilterReset, [ 131 | 'title' => \Yii::t('yii', 'Reset filter'), 132 | 'data-pjax' => '0', 133 | ]); 134 | } 135 | 136 | /** 137 | * Renders the filter cell content. 138 | * The default implementation simply renders a space. 139 | * This method may be overridden to customize the rendering of the filter cell (if any). 140 | * @return string the rendering result 141 | */ 142 | protected function renderFilterCellContent() 143 | { 144 | if (!$this->pageSizeOptions) 145 | { 146 | return parent::renderFilterCellContent(); 147 | } 148 | 149 | return Html::dropDownList($this->grid->dataProvider->pagination->pageSizeParam, $this->grid->dataProvider->pagination->pageSize, $this->pageSizeOptions); 150 | } 151 | } -------------------------------------------------------------------------------- /widgets/ActiveField.php: -------------------------------------------------------------------------------- 1 | options['tag']) ? $this->options['tag'] : 'div') . "\n"; 32 | } 33 | 34 | /** 35 | * Generates a icon for input. 36 | * @param array $options icon options. 37 | * The options have following structure: 38 | * ```php 39 | * [ 40 | * 'icon' => 'fa fa-bookmark-o', 41 | * 'position' => ActiveField::ICON_POSITION_LEFT, 42 | * ] 43 | * ``` 44 | * @return static the field object itself 45 | */ 46 | public function icon($options = []) 47 | { 48 | $icon = ArrayHelper::remove($options, 'icon', null); 49 | if ($icon) 50 | { 51 | $position = ArrayHelper::remove($options, 'position', self::ICON_POSITION_LEFT); 52 | if ($position != self::ICON_POSITION_RIGHT) 53 | { 54 | $position = ''; 55 | } 56 | $this->parts['{input}'] = Html::tag('i', '', ['class' => $icon]) . "\n" . $this->parts['{input}']; 57 | $this->parts['{input}'] = Html::tag('div', $this->parts['{input}'], ['class' => 'input-icon ' . $position]); 58 | } 59 | 60 | return $this; 61 | } 62 | 63 | /** 64 | * Generates a groupAddon for input. 65 | * GroupAddon similar to [[icon()]]. 66 | * @param array $options icon options. 67 | * The options have following structure: 68 | * ```php 69 | * [ 70 | * 'icon' => 'fa fa-bookmark-o', 71 | * 'position' => ActiveField::ICON_POSITION_LEFT, 72 | * ] 73 | * ``` 74 | * @return static the field object itself 75 | */ 76 | public function groupAddon($options = []) 77 | { 78 | $icon = ArrayHelper::remove($options, 'icon', null); 79 | if ($icon) 80 | { 81 | $addon = Html::tag('span', Html::tag('i', '', ['class' => $icon]), ['class' => 'input-group-addon']); 82 | $position = ArrayHelper::remove($options, 'position', self::ICON_POSITION_LEFT); 83 | if ($position == self::ICON_POSITION_RIGHT) 84 | { 85 | $this->parts['{input}'] .= "\n" . $addon; 86 | } 87 | else 88 | { 89 | $this->parts['{input}'] = $addon . "\n" . $this->parts['{input}']; 90 | } 91 | $this->parts['{input}'] = Html::tag('div', $this->parts['{input}'], ['class' => 'input-group']); 92 | } 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Generates a tag that contains error. 99 | * @param $error string the error to use. 100 | * @param array $options the tag options in terms of name-value pairs. It will be merged with [[errorOptions]]. 101 | * @return static the field object itself 102 | */ 103 | public function staticError($error, $options = []) 104 | { 105 | $options = array_merge($this->errorOptions, $options); 106 | $tag = isset($options['tag']) ? $options['tag'] : 'div'; 107 | unset($options['tag']); 108 | $this->parts['{error}'] = Html::tag($tag, $error, $options); 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * Generates spinner component. 115 | * @param array $options spinner options 116 | * @return $this 117 | */ 118 | public function spinner($options = []) 119 | { 120 | $this->parts['{input}'] = Spinner::widget(array_merge($options, ['model' => $this->model, 'attribute' => $this->attribute])); 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * Generates dateRangePicker component [[DateRangePicker]]. 127 | * @param array $options dateRangePicker options 128 | * @return $this 129 | */ 130 | public function dateRangePicker($options = []) 131 | { 132 | if ($this->form->type == ActiveForm::TYPE_VERTICAL) 133 | { 134 | //$options = array_merge($options, ['options' => ['style' => 'display:table-cell;']]); 135 | $options = array_merge($options, ['options' => ['class' => 'show']]); 136 | } 137 | $this->parts['{input}'] = DateRangePicker::widget(array_merge($options, ['model' => $this->model, 'attribute' => $this->attribute])); 138 | 139 | return $this; 140 | } 141 | 142 | /** 143 | * Generates dateRangePicker component [[DateRangePicker]]. 144 | * @param array $options dateRangePicker options 145 | * @return $this 146 | */ 147 | public function datePicker($options = []) 148 | { 149 | /* if ($this->form->type == ActiveForm::TYPE_VERTICAL) { 150 | //$options = array_merge($options, ['options' => ['style' => 'display:table-cell;']]); 151 | $options = array_merge($options, ['options' => ['class' => 'show']]); 152 | } */ 153 | $this->parts['{input}'] = DatePicker::widget(array_merge($options, ['model' => $this->model, 'attribute' => $this->attribute])); 154 | 155 | return $this; 156 | } 157 | 158 | /** 159 | * Generates select2 component [[Select2]]. 160 | * @param array $options select2 options 161 | * @return $this 162 | */ 163 | public function select2($options = []) 164 | { 165 | $this->parts['{input}'] = Select2::widget(array_merge($options, ['model' => $this->model, 'attribute' => $this->attribute])); 166 | 167 | return $this; 168 | } 169 | 170 | /** 171 | * Generates multiSelect component [[MultiSelect]]. 172 | * @param array $options multiSelect options 173 | * @return $this 174 | */ 175 | public function multiSelect($options = []) 176 | { 177 | $this->parts['{input}'] = MultiSelect::widget(array_merge($options, ['model' => $this->model, 'attribute' => $this->attribute])); 178 | 179 | return $this; 180 | } 181 | 182 | public function range($options = []) 183 | { 184 | $this->parts['{input}'] = IonRangeSlider::widget(array_merge($options, ['model' => $this->model, 'attribute' => $this->attribute])); 185 | 186 | return $this; 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /widgets/ActiveForm.php: -------------------------------------------------------------------------------- 1 | ActiveForm::BUTTONS_POSITION_LEFT, 58 | * //optional, vertical position 59 | * 'position' => ActiveForm::BUTTONS_POSITION_BOTTOM, 60 | * //optional, array of buttons 61 | * 'items' => [ 62 | * Button::widget('label' => 'Save', 'options' => ['type' => 'submit']), 63 | * Button::widget('label' => 'Back'), 64 | * ], 65 | * // optional, the HTML attributes (name-value pairs) for the form actions tag. 66 | * 'options' => ['class' => 'fluid'] 67 | * ] 68 | * ``` 69 | */ 70 | public $buttons = []; 71 | 72 | /** 73 | * @var array the default configuration used by [[field()]] when creating a new field object. 74 | */ 75 | public $fieldConfig = []; 76 | 77 | /** 78 | * @var bool indicates whether the tag 'form' is rendered. 79 | * In case 'true' widget renders 'div' instead 'form'. 80 | */ 81 | public $fake = false; 82 | 83 | /** 84 | * Initializes the widget. 85 | * This renders the form open tag. 86 | */ 87 | public function init() 88 | { 89 | if (!isset($this->options['id'])) 90 | { 91 | $this->options['id'] = $this->getId(); 92 | } 93 | 94 | switch ($this->type) 95 | { 96 | case self::TYPE_HORIZONTAL: 97 | if ($this->stripped) 98 | { 99 | Html::addCssClass($this->options, 'form-row-stripped'); 100 | } 101 | if ($this->separated) 102 | { 103 | Html::addCssClass($this->options, 'form-row-seperated'); 104 | } 105 | if ($this->bordered) 106 | { 107 | Html::addCssClass($this->options, 'form-bordered'); 108 | } 109 | Html::addCssClass($this->options, 'form-horizontal'); 110 | $this->fieldConfig = ArrayHelper::merge([ 111 | 'labelOptions' => ['class' => 'col-md-3 control-label'], 112 | 'template' => "{label}\n" . Html::tag('div', "{input}\n{error}\n{hint}", ['class' => 'col-md-9']), 113 | ], $this->fieldConfig); 114 | break; 115 | case self::TYPE_INLINE: 116 | Html::addCssClass($this->options, 'form-inline'); 117 | $this->fieldConfig = ArrayHelper::merge([ 118 | 'labelOptions' => ['class' => 'sr-only'], 119 | ], $this->fieldConfig); 120 | break; 121 | } 122 | if (!isset($this->fieldConfig['class'])) 123 | { 124 | $this->fieldConfig['class'] = ActiveField::className(); 125 | } 126 | if ($this->fake) 127 | { 128 | echo Html::beginTag('div', $this->options); 129 | } 130 | else 131 | { 132 | echo Html::beginForm($this->action, $this->method, $this->options); 133 | } 134 | echo $this->renderActions(self::BUTTONS_POSITION_TOP); 135 | echo Html::beginTag('div', ['class' => 'form-body']); 136 | } 137 | 138 | /** 139 | * Runs the widget. 140 | * This registers the necessary javascript code and renders the form close tag. 141 | */ 142 | public function run() 143 | { 144 | echo Html::endTag('div'); 145 | echo $this->renderActions(self::BUTTONS_POSITION_BOTTOM); 146 | if (!empty($this->attributes)) 147 | { 148 | $id = $this->options['id']; 149 | $options = Json::encode($this->getClientOptions()); 150 | $attributes = Json::encode($this->attributes); 151 | $view = $this->getView(); 152 | ActiveFormAsset::register($view); 153 | $view->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);"); 154 | } 155 | if ($this->fake) 156 | { 157 | echo Html::endTag('div'); 158 | } 159 | else 160 | { 161 | echo Html::endForm(); 162 | } 163 | } 164 | 165 | /** 166 | * Generates a form field. 167 | * A form field is associated with a model and an attribute. It contains a label, an input and an error message 168 | * and use them to interact with end users to collect their inputs for the attribute. 169 | * @param Model $model the data model 170 | * @param string $attribute the attribute name or expression. See [[Html::getAttributeName()]] for the format 171 | * about attribute expression. 172 | * @param array $options the additional configurations for the field object 173 | * @return ActiveField the created ActiveField object 174 | * @see fieldConfig 175 | */ 176 | public function field($model, $attribute, $options = []) 177 | { 178 | return parent::field($model, $attribute, $options); 179 | } 180 | 181 | protected function renderActions($currentPosition) 182 | { 183 | $position = ArrayHelper::getValue($this->buttons, 'position', self::BUTTONS_POSITION_BOTTOM); 184 | if (!empty($this->buttons['items']) && $position == $currentPosition) 185 | { 186 | $actionsOptions = ArrayHelper::getValue($this->buttons, 'options', []); 187 | Html::addCssClass($actionsOptions, 'form-actions'); 188 | if ($position == self::BUTTONS_POSITION_TOP) 189 | { 190 | Html::addCssClass($actionsOptions, 'top'); 191 | } 192 | if (isset($this->buttons['align']) && $this->buttons['align'] == self::BUTTONS_ALIGN_RIGHT) 193 | { 194 | Html::addCssClass($actionsOptions, 'right'); 195 | } 196 | $rowOptions = []; 197 | $buttons = implode("\n", $this->buttons['items']); 198 | switch ($this->type) 199 | { 200 | case self::TYPE_HORIZONTAL: 201 | Html::addCssClass($actionsOptions, 'fluid'); 202 | preg_match('#col-md-(\d+)#', $this->fieldConfig['labelOptions']['class'], $matches); 203 | if (isset($matches[1])) 204 | { 205 | $offset = $matches[1]; 206 | Html::addCssClass($rowOptions, 'col-md-offset-' . $offset); 207 | Html::addCssClass($rowOptions, 'col-md-' . 12 - $offset); 208 | $buttons = Html::tag('div', $buttons, $rowOptions); 209 | } 210 | break; 211 | } 212 | 213 | return Html::tag('div', $buttons, $actionsOptions); 214 | } 215 | 216 | return ''; 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /widgets/Alert.php: -------------------------------------------------------------------------------- 1 | 'Say hello...', 22 | * 'closeButton' => [ 23 | * 'label' => '×', 24 | * 'tag' => 'a', 25 | * 'type' => Alert::TYPE_DANGER, 26 | * ], 27 | * ]); 28 | * ``` 29 | * 30 | * The following example will show the content enclosed between the [[begin()]] 31 | * and [[end()]] calls within the alert box: 32 | * 33 | * ```php 34 | * Alert::begin([ 35 | * 'type' => Alert::TYPE_DANGER, 36 | * 'closeButton' => ['label' => '×'], 37 | * ]); 38 | * 39 | * echo 'Say hello...'; 40 | * 41 | * Alert::end(); 42 | * ``` 43 | */ 44 | class Alert extends \yii\bootstrap\Alert { 45 | 46 | // type 47 | const TYPE_SUCCESS = 'success'; 48 | const TYPE_INFO = 'info'; 49 | const TYPE_WARNING = 'warning'; 50 | const TYPE_DANGER = 'danger'; 51 | 52 | /** 53 | * @var string the note type. 54 | * Valid values are 'success', 'info', 'warning', 'danger'. 55 | */ 56 | public $type = self::TYPE_SUCCESS; 57 | 58 | /** 59 | * @var boolean when set, alert has a larger block size. 60 | */ 61 | public $block = true; 62 | 63 | /** 64 | * Initializes the widget. 65 | */ 66 | public function init() 67 | { 68 | Html::addCssClass($this->options, 'alert-' . $this->type); 69 | if ($this->block) 70 | { 71 | Html::addCssClass($this->options, 'alert-block'); 72 | } 73 | parent::init(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /widgets/Badge.php: -------------------------------------------------------------------------------- 1 | 'NEW', 18 | * 'type' => Badge::TYPE_SUCCESS, 19 | * 'round' 20 | * ]); 21 | * 22 | * @package dlds\metronic\widgets 23 | */ 24 | class Badge extends \yii\base\Widget 25 | { 26 | // type 27 | const TYPE_DEFAULT = 'default'; 28 | const TYPE_GRAY = 'default'; 29 | const TYPE_SUCCESS = 'success'; 30 | const TYPE_WARNING = 'warning'; 31 | const TYPE_DANGER = 'danger'; 32 | const TYPE_INFO = 'info'; 33 | /** 34 | * @var string the badge label 35 | */ 36 | public $label; 37 | /** 38 | * @var string the badge type 39 | * Valid values '', 'default', 'success', 'warning', 'danger', 'info' 40 | */ 41 | public $type = self::TYPE_DEFAULT; 42 | /** 43 | * @var bool Indicates whether badge is rounded or not. 44 | */ 45 | public $round = true; 46 | 47 | /** 48 | * Executes the widget. 49 | */ 50 | public function run() 51 | { 52 | $options = []; 53 | Html::addCssClass($options, 'badge'); 54 | if (!$this->round) { 55 | Html::addCssClass($options, 'badge-roundless'); 56 | } 57 | Html::addCssClass($options, 'badge-' . $this->type); 58 | 59 | echo Html::tag('span', $this->label, $options); 60 | } 61 | } -------------------------------------------------------------------------------- /widgets/Breadcrumbs.php: -------------------------------------------------------------------------------- 1 | [ 27 | * ['label' => 'Sample Post', 'url' => ['post/edit', 'id' => 1]], 28 | * 'Edit', 29 | * ], 30 | * ]); 31 | * ``` 32 | * 33 | * Because breadcrumbs usually appears in nearly every page of a website, you may consider placing it in a layout view. 34 | * You can use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different 35 | * views. In the layout view, you assign this view parameter to the [[links]] property like the following: 36 | * 37 | * ```php 38 | * // $this is the view object currently being used 39 | * echo Breadcrumbs::widget([ 40 | * 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], 41 | * ]); 42 | * ``` 43 | */ 44 | class Breadcrumbs extends \yii\widgets\Breadcrumbs 45 | { 46 | /** 47 | * @var string the template used to render each inactive item in the breadcrumbs. The token `{link}` 48 | * will be replaced with the actual HTML link for each inactive item. 49 | */ 50 | public $itemTemplate = "
  • {link}
  • \n"; 51 | /** 52 | * @var string the template used to render each active item in the breadcrumbs. The token `{link}` 53 | * will be replaced with the actual HTML link for each active item. 54 | */ 55 | public $activeItemTemplate = "
  • {link}
  • \n"; 56 | /** 57 | * @var array|string 58 | */ 59 | public $actions; 60 | 61 | public function init() 62 | { 63 | parent::init(); 64 | Html::addCssClass($this->options, 'page-breadcrumb'); 65 | } 66 | 67 | 68 | public function run() 69 | { 70 | if (empty($this->links)) { 71 | return; 72 | } 73 | $links = []; 74 | 75 | if ($this->actions !== null) { 76 | Html::addCssClass($this->actions['dropdown']['options'], 'pull-right'); 77 | if (is_string($this->actions)) { 78 | $links[] = $this->actions; 79 | } else if (is_array($this->actions)) { 80 | $links[] = ButtonDropdown::widget($this->actions); 81 | } else { 82 | throw new InvalidConfigException('Actions must be of type "string" or "array".'); 83 | } 84 | } 85 | 86 | if ($this->homeLink === null) { 87 | $links[] = $this->renderItem([ 88 | 'label' => Yii::t('yii', 'Home'), 89 | 'url' => Yii::$app->homeUrl, 90 | ], $this->itemTemplate); 91 | } elseif ($this->homeLink !== false) { 92 | $links[] = $this->renderItem($this->homeLink, $this->itemTemplate); 93 | } 94 | foreach ($this->links as $link) { 95 | if (!is_array($link)) { 96 | $link = ['label' => $link]; 97 | } 98 | $links[] = $this->renderItem($link, isset($link['url']) ? $this->itemTemplate : $this->activeItemTemplate); 99 | } 100 | echo Html::tag($this->tag, implode('', $links), $this->options); 101 | } 102 | 103 | /** 104 | * Renders a single breadcrumb item. 105 | * @param array $link the link to be rendered. It must contain the "label" element. The "url" element is optional. 106 | * @param string $template the template to be used to rendered the link. The token "{link}" will be replaced by the link. 107 | * @return string the rendering result 108 | * @throws InvalidConfigException if `$link` does not have "label" element. 109 | */ 110 | protected function renderItem($link, $template) 111 | { 112 | if (isset($link['label'])) { 113 | $label = $this->encodeLabels ? Html::encode($link['label']) : $link['label']; 114 | } else { 115 | throw new InvalidConfigException('The "label" element is required for each link.'); 116 | } 117 | 118 | $icon = ArrayHelper::getValue($link, 'icon', ''); 119 | if ($icon) { 120 | $icon = Html::tag('i', '', ['class' => 'fa ' . $icon]) . ' '; 121 | } 122 | if (isset($link['url'])) { 123 | return strtr($template, ['{link}' => $icon . Html::a($label, $link['url'])]); 124 | } else { 125 | return strtr($template, ['{link}' => $icon . $label]); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /widgets/Button.php: -------------------------------------------------------------------------------- 1 | 'Action', 22 | * 'icon' => 'fa fa-bookmark-o', 23 | * 'iconPosition' => Button::ICON_POSITION_LEFT, 24 | * 'size' => Button::SIZE_SMALL, 25 | * 'disabled' => false, 26 | * 'block' => false, 27 | * 'type' => Button::TYPE_M_BLUE, 28 | * ]); 29 | * ``` 30 | */ 31 | class Button extends \yii\bootstrap\Button { 32 | 33 | /** 34 | * Button bootstrap types 35 | */ 36 | const TYPE_DEFAULT = ''; 37 | const TYPE_PRIMARY = 'primary'; 38 | const TYPE_INFO = 'info'; 39 | const TYPE_SUCCESS = 'success'; 40 | const TYPE_WARNING = 'warning'; 41 | const TYPE_DANGER = 'danger'; 42 | const TYPE_INVERSE = 'inverse'; 43 | const TYPE_LINK = 'link'; 44 | const TYPE_CIRCLE = 'circle'; 45 | 46 | /** 47 | * Button sizes 48 | */ 49 | const SIZE_MINI = 'xs'; 50 | const SIZE_SMALL = 'sm'; 51 | const SIZE_LARGE = 'lg'; 52 | 53 | /** 54 | * Icon positions 55 | */ 56 | const ICON_POSITION_LEFT = 'left'; 57 | const ICON_POSITION_RIGHT = 'right'; 58 | 59 | /** 60 | * @var string The button size. 61 | * Valid values are 'xs', 'sm', 'lg'. 62 | */ 63 | public $size; 64 | 65 | /** 66 | * @var string The button type. 67 | * Valid values for metronic styles are 'default', 'red', 'blue', 'green', 'yellow', 'purple', 'dark'. 68 | * Valid values for bootstrap styles are 'primary', 'info', 'success', 'warning', 'danger', 'inverse', 'link'. 69 | */ 70 | public $type = self::TYPE_DEFAULT; 71 | 72 | /** 73 | * @var string color 74 | */ 75 | public $color = 'btn-default'; 76 | 77 | /** 78 | * @var string The button icon. 79 | */ 80 | public $icon; 81 | 82 | /** 83 | * @var string Icon position. 84 | * Valid values are 'left', 'right'. 85 | */ 86 | public $iconPosition = self::ICON_POSITION_LEFT; 87 | 88 | /** 89 | * @var bool Indicates whether button is disabled or not. 90 | */ 91 | public $disabled = false; 92 | 93 | /** 94 | * @var bool Indicates whether the button should span the full width of the a parent. 95 | */ 96 | public $block = false; 97 | 98 | /** 99 | * @var bool Indicates whether the dropdown shoud expand on hover. 100 | */ 101 | public $hover = false; 102 | 103 | /** 104 | * @var array sizes 105 | */ 106 | private $_sizes = [ 107 | self::SIZE_MINI, 108 | self::SIZE_SMALL, 109 | self::SIZE_LARGE, 110 | ]; 111 | 112 | /** 113 | * Initializes the widget. 114 | */ 115 | public function init() 116 | { 117 | parent::init(); 118 | 119 | if (static::TYPE_DEFAULT !== $this->type) 120 | { 121 | Html::addCssClass($this->options, sprintf('btn-%s', $this->type)); 122 | } 123 | 124 | Html::addCssClass($this->options, $this->color); 125 | 126 | if (in_array($this->size, $this->_sizes)) 127 | { 128 | Html::addCssClass($this->options, 'btn-' . $this->size); 129 | } 130 | 131 | if ($this->disabled === true) 132 | { 133 | Html::addCssClass($this->options, 'disabled'); 134 | } 135 | 136 | if ($this->block === true) 137 | { 138 | Html::addCssClass($this->options, 'btn-block'); 139 | } 140 | 141 | $this->options['type'] = 'button'; 142 | } 143 | 144 | /** 145 | * Renders the widget. 146 | */ 147 | public function run() 148 | { 149 | $label = $this->encodeLabel ? Html::encode($this->label) : $this->label; 150 | 151 | if ($this->icon !== null) 152 | { 153 | $icon = Html::tag('i', '', ['class' => $this->icon]); 154 | $label = strcasecmp($this->iconPosition, self::ICON_POSITION_LEFT) === 0 ? sprintf('%s %s', $icon, $label) : sprintf('%s %s', $label, $icon); 155 | } 156 | 157 | echo Html::tag($this->tagName, $label, $this->options); 158 | 159 | $this->registerPlugin('button'); 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /widgets/ButtonDropdown.php: -------------------------------------------------------------------------------- 1 | 'Action', 23 | * 'button' => [ 24 | * 'icon' => 'fa fa-bookmark-o', 25 | * 'iconPosition' => Button::ICON_POSITION_LEFT, 26 | * 'size' => Button::SIZE_SMALL, 27 | * 'disabled' => false, 28 | * 'block' => false, 29 | * 'type' => Button::TYPE_M_BLUE, 30 | * ], 31 | * 'dropdown' => [ 32 | * 'items' => [ 33 | * ['label' => 'DropdownA', 'url' => '/'], 34 | * ['label' => 'DropdownB', 'url' => '#'], 35 | * ], 36 | * ], 37 | * ]); 38 | * ``` 39 | * 40 | * */ 41 | class ButtonDropdown extends \yii\bootstrap\ButtonDropdown { 42 | 43 | /** 44 | * @var array The configuration array for [[Button]]. 45 | */ 46 | public $button = []; 47 | 48 | /** 49 | * @var bool Indicates whether the dropdown shoud expand on hover. 50 | */ 51 | public $hover = false; 52 | 53 | /** 54 | * Inits ButtonDropdown 55 | */ 56 | public function init() 57 | { 58 | parent::init(); 59 | 60 | $this->options['data-toggle'] = 'dropdown'; 61 | 62 | if ($this->hover === true) 63 | { 64 | $this->options['data-hover'] = 'dropdown'; 65 | } 66 | 67 | if ($this->encodeLabel) 68 | { 69 | $this->label = Html::encode($this->label); 70 | } 71 | 72 | $this->options['data-close-others'] = 'true'; 73 | 74 | Html::addCssClass($this->options, 'btn'); 75 | 76 | Html::addCssClass($this->options, 'dropdown-toggle'); 77 | } 78 | 79 | /** 80 | * Renders the widget. 81 | */ 82 | public function run() 83 | { 84 | echo Html::tag('div', sprintf('%s%s', $this->renderButton(), $this->renderDropdown()), ['class' => 'btn-group']); 85 | } 86 | 87 | /** 88 | * Renders the button. 89 | * @return string the rendering result 90 | */ 91 | protected function renderButton() 92 | { 93 | $label = Html::tag('span', $this->label, ['class' => 'hidden-sm hidden-xs']); 94 | 95 | if ($this->split) 96 | { 97 | $leftBtn = Button::widget($a = ArrayHelper::merge($this->button, [ 98 | 'label' => $label, 99 | 'encodeLabel' => false, 100 | 'tagName' => $this->tagName, 101 | ])); 102 | 103 | 104 | $rightBtn = Button::widget(ArrayHelper::merge($this->button, [ 105 | 'label' => '', 106 | 'encodeLabel' => false, 107 | 'options' => $this->options, 108 | 'tagName' => $this->tagName, 109 | ])); 110 | } 111 | else 112 | { 113 | $label .= ' '; 114 | 115 | if (!isset($this->options['href'])) 116 | { 117 | $this->options['href'] = '#'; 118 | } 119 | 120 | $leftBtn = Button::widget(ArrayHelper::merge($this->button, [ 121 | 'label' => $label, 122 | 'encodeLabel' => false, 123 | 'options' => $this->options, 124 | 'tagName' => $this->tagName, 125 | ])); 126 | 127 | $rightBtn = ''; 128 | } 129 | 130 | return sprintf('%s%s', $leftBtn, $rightBtn); 131 | } 132 | 133 | /** 134 | * Renders the dropdown 135 | * @return string the rendering result 136 | */ 137 | protected function renderDropdown() 138 | { 139 | $config = $this->dropdown; 140 | $config['clientOptions'] = false; 141 | return Dropdown::widget($config); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /widgets/ButtonGroup.php: -------------------------------------------------------------------------------- 1 | true, 21 | * 'buttons' => [ 22 | * ['label' => 'A'], 23 | * ['label' => 'B'], 24 | * ] 25 | * ]); 26 | * 27 | * // a button group with an item as a string 28 | * echo ButtonGroup::widget([ 29 | * 'buttons' => [ 30 | * Button::widget(['label' => 'A']), 31 | * ['label' => 'B'], 32 | * ] 33 | * ]); 34 | * ``` 35 | */ 36 | class ButtonGroup extends \yii\bootstrap\ButtonGroup 37 | { 38 | /** 39 | * @var bool Indicates whether the button group appears vertically stacked. 40 | */ 41 | public $stacked = false; 42 | 43 | /** 44 | * Initializes the widget. 45 | */ 46 | public function init() 47 | { 48 | if ($this->stacked === true) { 49 | Html::addCssClass($this->options, 'btn-group-vertical'); 50 | } else { 51 | Html::addCssClass($this->options, 'btn-group'); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /widgets/CheckboxList.php: -------------------------------------------------------------------------------- 1 | [ 22 | * 'full_name', 23 | * [ 24 | * 'name' => 'city', 25 | * 'label' => 'Location', 26 | * ] 27 | * ], 28 | * 'model' => $filterModel, 29 | * 'attribute' => 'columns', 30 | * ]); 31 | * ``` 32 | */ 33 | class CheckboxList extends InputWidget 34 | { 35 | /** 36 | * @var array list of checkbox items. 37 | * Each item must be either as string like the name checkbox 38 | * or as array with following special options: 39 | * - name, required, item name 40 | * - label, optional, item label 41 | * Item can not belong to the model. 42 | */ 43 | public $items = []; 44 | /** 45 | * @var string the model attribute that this widget is associated with. 46 | * This model attribute contains list of checkboxes name, separated $separator value. 47 | */ 48 | public $attribute; 49 | /** 50 | * @var string separator values 51 | */ 52 | public $separator = ','; 53 | /** 54 | * @var array the HTML attributes for items. 55 | */ 56 | public $itemOptions = []; 57 | /** 58 | * @var array items name, that will be checked. 59 | */ 60 | private $_checked = []; 61 | 62 | /** 63 | * Initializes the widget. 64 | */ 65 | public function init() 66 | { 67 | parent::init(); 68 | $items = []; 69 | if ($this->hasModel()) { 70 | $this->_checked = array_map('trim', explode(',', $this->model->{$this->attribute})); 71 | foreach ($this->items as $item) { 72 | $input = []; 73 | if (is_string($item)) { 74 | $input['name'] = $item; 75 | $input['label'] = $this->model->getAttributeLabel($item); 76 | } else { 77 | if (!isset($item['name'])) { 78 | throw new InvalidConfigException('Option "name" is required.'); 79 | } 80 | $input['name'] = $item['name']; 81 | $input['label'] = isset($item['label']) ? $item['label'] : $this->model->getAttributeLabel( 82 | $item['name'] 83 | ); 84 | } 85 | $items[] = $input; 86 | } 87 | } else { 88 | $this->_checked = array_map('trim', explode(',', $this->value)); 89 | foreach ($this->items as $item) { 90 | $input = []; 91 | if (is_string($item)) { 92 | $input['name'] = $item; 93 | $input['label'] = Inflector::camel2words($item); 94 | } else { 95 | if (!isset($item['name'])) { 96 | throw new InvalidConfigException('Option "name" is required.'); 97 | } 98 | $input['name'] = $item['name']; 99 | $input['label'] = isset($item['label']) ? $item['label'] : Inflector::camel2words($item['name']); 100 | } 101 | $items[] = $input; 102 | } 103 | } 104 | 105 | $this->items = $items; 106 | } 107 | 108 | /** 109 | * Executes the widget. 110 | */ 111 | public function run() 112 | { 113 | if ($this->hasModel()) { 114 | $hiddenInput = Html::activeHiddenInput($this->model, $this->attribute); 115 | $inputId = Html::getInputId($this->model, $this->attribute); 116 | } else { 117 | $hiddenInput = Html::textInput($this->name, $this->name); 118 | $inputId = $this->name; 119 | } 120 | 121 | $items = []; 122 | usort($this->items, function($a, $b){ 123 | $aKey = array_search($a['name'], $this->_checked); 124 | $bKey = array_search($b['name'], $this->_checked); 125 | if ($aKey == $bKey) { 126 | return 0; 127 | } 128 | 129 | return ($aKey > $bKey) ? 1 : -1; 130 | }); 131 | Html::addCssClass($this->itemOptions, 'btn btn-xs default'); 132 | foreach ($this->items as $item) { 133 | $checkbox = Html::checkbox($item['name'], in_array($item['name'], $this->_checked)); 134 | $items[] = Html::tag('span', $checkbox . ' ' . $item['label'], $this->itemOptions); 135 | } 136 | 137 | echo Html::beginTag('div', $this->options); 138 | echo Sortable::widget([ 139 | 'items' => $items, 140 | 'options' => ['tag' => 'div'], 141 | 'itemOptions' => ['tag' => 'span'], 142 | 'clientOptions' => ['cursor' => 'move', 143 | 'start' => new JsExpression('function(e, ui){ 144 | ui.placeholder.height(ui.item.height()); 145 | ui.placeholder.width(ui.item.width()); 146 | }'), 147 | 'update' => new JsExpression("function(e, ui){ 148 | var values = $.map($('#{$this->options['id']} input:checkbox:checked'), 149 | function(item){ return $(item).attr('name')}); 150 | $('#{$inputId}').val(values.join('{$this->separator}')); 151 | }"), 152 | ], 153 | ]); 154 | echo $hiddenInput; 155 | echo Html::endTag('div'); 156 | $this->registerJs($inputId); 157 | } 158 | 159 | protected function registerJs($inputId) 160 | { 161 | $this->view->registerJs(" 162 | ;(function($){ 163 | $('#{$this->options['id']}').on('change', 'input:checkbox', function(){ 164 | var values = $.map($('#{$this->options['id']} input:checkbox:checked'), 165 | function(item){ return $(item).attr('name')}); 166 | $('#{$inputId}').val(values.join('{$this->separator}')); 167 | }); 168 | })(jQuery); 169 | ", View::POS_READY); 170 | } 171 | } -------------------------------------------------------------------------------- /widgets/DatePicker.php: -------------------------------------------------------------------------------- 1 | 'ru', 24 | * 'model' => $model, 25 | * 'attribute' => 'country', 26 | * 'clientOptions' => [ 27 | * 'dateFormat' => 'yy-mm-dd', 28 | * ], 29 | * ]); 30 | * ``` 31 | * 32 | * The following example will use the name property instead: 33 | * 34 | * ```php 35 | * echo DatePicker::widget([ 36 | * 'language' => 'ru', 37 | * 'name' => 'country', 38 | * 'clientOptions' => [ 39 | * 'dateFormat' => 'yy-mm-dd', 40 | * ], 41 | * ]); 42 | * ``` 43 | * 44 | * @see http://api.jqueryui.com/datepicker/ 45 | * @author Alexander Kochetov 46 | * @since 2.0 47 | */ 48 | class DatePicker extends InputWidget { 49 | 50 | /** 51 | * @var string the locale ID (eg 'fr', 'de') for the language to be used by the date picker. 52 | * If this property set to false, I18N will not be involved. That is, the date picker will show in English. 53 | */ 54 | public $language = false; 55 | 56 | /** 57 | * @var boolean If true, shows the widget as an inline calendar and the input as a hidden field. 58 | */ 59 | public $inline = false; 60 | 61 | /** 62 | * @var array the HTML attributes for the container tag. This is only used when [[inline]] is true. 63 | */ 64 | public $containerOptions = []; 65 | 66 | /** 67 | * Initializes the widget. 68 | */ 69 | public function init() 70 | { 71 | parent::init(); 72 | if ($this->inline && !isset($this->containerOptions['id'])) 73 | { 74 | $this->containerOptions['id'] = $this->options['id'] . '-container'; 75 | } 76 | else 77 | { 78 | Html::addCssClass($this->options, 'form-control form-control-inline'); 79 | } 80 | } 81 | 82 | /** 83 | * Renders the widget. 84 | */ 85 | public function run() 86 | { 87 | $contents = []; 88 | if ($this->inline) 89 | { 90 | if ($this->hasModel()) 91 | { 92 | $contents[] = Html::activeHiddenInput($this->model, $this->attribute, $this->options); 93 | } 94 | else 95 | { 96 | $contents[] = Html::hiddenInput($this->name, $this->value, $this->options); 97 | } 98 | $contents[] = Html::tag('div', '', $this->containerOptions); 99 | } 100 | else 101 | { 102 | if ($this->hasModel()) 103 | { 104 | $contents[] = Html::activeTextInput($this->model, $this->attribute, $this->options); 105 | } 106 | else 107 | { 108 | $contents[] = Html::textInput($this->name, $this->value, $this->options); 109 | } 110 | } 111 | echo implode("\n", $contents); 112 | if ($this->language) 113 | { 114 | DatePickerAsset::$extraJs[] = 'plugins/bootstrap-datepicker-extended/js/locales/bootstrap-datepicker.' . $this->language . '.js'; 115 | $this->clientOptions['language'] = $this->language; 116 | } 117 | DatePickerAsset::register($this->view); 118 | $this->registerPlugin('datepicker'); 119 | if ($this->inline) 120 | { 121 | $this->view->registerJs(" 122 | !(function($){ 123 | var el = $('#{$this->options['id']}'), 124 | val = el.val(), 125 | container = $('#{$this->containerOptions['id']}'); 126 | container.on('changeDate', function(e){ 127 | el.val(e.format()); 128 | }); 129 | if(val) { 130 | container.datepicker('update', new Date(Date.parse(val))); 131 | } 132 | })(jQuery); 133 | ", View::POS_READY); 134 | } 135 | } 136 | 137 | /** 138 | * Registers a specific Bootstrap plugin and the related events 139 | * @param string $name the name of the Bootstrap plugin 140 | */ 141 | protected function registerPlugin($name) 142 | { 143 | $view = $this->getView(); 144 | $id = $this->inline ? $this->containerOptions['id'] : $this->options['id']; 145 | if ($this->clientOptions !== false) 146 | { 147 | $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); 148 | $js = "jQuery('#$id').$name($options);"; 149 | $view->registerJs($js); 150 | } 151 | if (!empty($this->clientEvents)) 152 | { 153 | $js = []; 154 | foreach ($this->clientEvents as $event => $handler) 155 | { 156 | $js[] = "jQuery('#$id').on('$event', $handler);"; 157 | } 158 | $view->registerJs(implode("\n", $js)); 159 | } 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /widgets/Decorator.php: -------------------------------------------------------------------------------- 1 | $model, 26 | * 'attributes' => [ 27 | * 'title', // title attribute (in plain text) 28 | * 'description:html', // description attribute in HTML 29 | * [ // the owner name of the model 30 | * 'label' => 'Owner', 31 | * 'value' => $model->owner->name, 32 | * ], 33 | * ], 34 | * ]); 35 | * ~~~ 36 | */ 37 | class DetailView extends \yii\widgets\DetailView 38 | { 39 | /** 40 | * @var string|callback the template used to render a single attribute. If a string, the token `{label}` 41 | * and `{value}` will be replaced with the label and the value of the corresponding attribute. 42 | * If a callback (e.g. an anonymous function), the signature must be as follows: 43 | * 44 | * ~~~ 45 | * function ($attribute, $index, $widget) 46 | * ~~~ 47 | * 48 | * where `$attribute` refer to the specification of the attribute being rendered, `$index` is the zero-based 49 | * index of the attribute in the [[attributes]] array, and `$widget` refers to this widget instance. 50 | */ 51 | public $template = '
    52 |
    {label}
    53 |
    {value}
    54 |
    '; 55 | } 56 | -------------------------------------------------------------------------------- /widgets/DraggablePortlets.php: -------------------------------------------------------------------------------- 1 | view); 46 | echo Html::beginTag('div', ['class' => "row {$this->cssRowClasses}", 'id' => 'sortable_portlets']); 47 | $this->renderColumns(); 48 | echo Html::endTag('div'); 49 | } 50 | 51 | private function renderColumns(){ 52 | foreach ($this->columns as $aColumn){ 53 | if (!array_key_exists('items', $aColumn)) { 54 | throw new InvalidConfigException( 55 | "The 'items' option is required." 56 | ); 57 | } 58 | 59 | echo Html::beginTag('div', ['class' => 'col-md-4 column sortable']); 60 | 61 | $options = []; 62 | if (array_key_exists('tools', $aColumn)){ 63 | $options['tools'] = $aColumn['tools']; 64 | } 65 | 66 | $this->renderItems($aColumn['items'], $options); 67 | if (!(array_key_exists('appendEmptyLastElement', $aColumn) && $aColumn['appendEmptyLastElement'] === false) ){ 68 | $this->renderEmptyPortlet(); 69 | } 70 | echo Html::endTag('div'); 71 | } 72 | } 73 | 74 | private function renderItems($items, $options){ 75 | foreach ($items as $key => $item) { 76 | if (!ArrayHelper::remove($item, 'visible', true)) { 77 | continue; 78 | } 79 | 80 | if (!is_string($key) && !array_key_exists('itemTitle', $item)) { 81 | throw new InvalidConfigException( 82 | "The 'itemTitle' option is required." 83 | ); 84 | } 85 | if (is_string($item)) { 86 | $item = ['content' => $item]; 87 | } 88 | 89 | Portlet::begin(array_merge([ 90 | 'title' => $item['itemTitle'], 91 | 'options' => [ 92 | 'class' => 'portlet-sortable', 93 | ], 94 | 'headerOptions' => [ 95 | 'class' => 'ui-sortable-handle', 96 | ], 97 | ], $options)); 98 | 99 | Portlet::end(); 100 | } 101 | } 102 | 103 | private function renderEmptyPortlet(){ 104 | echo Html::tag('div', '', ['class' => 'portlet portlet-sortable-empty']); 105 | } 106 | 107 | 108 | } -------------------------------------------------------------------------------- /widgets/DropZone.php: -------------------------------------------------------------------------------- 1 | options['url'])){ 36 | $this->options['url'] = $this->uploadUrl; // Set the url 37 | } 38 | 39 | // Define the element that should be used as click trigger to select files. 40 | if (!isset($this->options['previewsContainer'])){ 41 | $this->options['previewsContainer'] = '#' . $this->previewsContainer; 42 | } 43 | 44 | // Define the element that should be used as click trigger to select files. 45 | if (!isset($this->options['clickable'])){ 46 | $this->options['clickable'] = true; 47 | } 48 | 49 | if (!isset($this->options['cssClasses'])){ 50 | $this->options['cssClasses'] = 'dropzone'; 51 | } 52 | 53 | $this->autoDiscover = $this->autoDiscover===false ? 'false' : 'true'; 54 | 55 | if(\Yii::$app->getRequest()->enableCsrfValidation){ 56 | $this->options['headers'][\yii\web\Request::CSRF_HEADER] = \Yii::$app->getRequest()->getCsrfToken(); 57 | $this->options['params'][\Yii::$app->getRequest()->csrfParam] = \Yii::$app->getRequest()->getCsrfToken(); 58 | } 59 | $this->registerAssets(); 60 | } 61 | 62 | public function run() 63 | { 64 | return Html::tag('div', $this->renderDropzone(), ['id' => $this->dropzoneContainer, 'class' => $this->options['cssClasses']]); 65 | } 66 | 67 | private function renderDropzone() 68 | { 69 | $data = Html::tag('div', '', ['id' => $this->previewsContainer,'class' => 'dropzone-previews']); 70 | return $data; 71 | } 72 | 73 | /** 74 | * Registers the needed assets 75 | */ 76 | public function registerAssets() 77 | { 78 | $view = $this->getView(); 79 | $js = 'Dropzone.autoDiscover = ' . $this->autoDiscover . '; var ' . $this->id . ' = new Dropzone("div#' . $this->dropzoneContainer . '", ' . Json::encode($this->options) . ');'; 80 | if (!empty($this->clientEvents)) { 81 | foreach ($this->clientEvents as $event => $handler) { 82 | $js .= "$this->id.on('$event', $handler);"; 83 | } 84 | } 85 | $view->registerJs($js); 86 | DropZoneAsset::register($view); 87 | } 88 | } -------------------------------------------------------------------------------- /widgets/Dropdown.php: -------------------------------------------------------------------------------- 1 | 'Dropdown title', 22 | * 'more' => ['label' => 'xxx', 'url' => '/', 'icon' => 'm-icon-swapright'], 23 | * 'scroller' => ['height' => 200], 24 | * 'items' => [ 25 | * ['label' => 'Level 1 - Dropdown A', 'url' => '#'], 26 | * '
  • ', 27 | * '', 28 | * ['label' => 'Level 1 - Dropdown B', 'url' => '#'], 29 | * ], 30 | * ]); 31 | * 32 | */ 33 | class Dropdown extends \yii\bootstrap\Dropdown 34 | { 35 | 36 | public const LINK_TYPE_LINK = 'a'; 37 | 38 | public const LINK_TYPE_CHECKBOX = 'checkbox'; 39 | 40 | /** 41 | * @var string the dropdown title 42 | */ 43 | public $title; 44 | 45 | /** 46 | * @var array the dropdown last item options 47 | * with the following structure: 48 | * ```php 49 | * [ 50 | * // optional, item label 51 | * 'label' => 'Show all messages', 52 | * // optional, item icon 53 | * 'icon' => 'm-icon-swapright', 54 | * // optional, item url 55 | * 'url' => '/', 56 | * ] 57 | * ``` 58 | */ 59 | public $more = []; 60 | 61 | /** 62 | * @var array the dropdown item options 63 | * is an array of the following structure: 64 | * ```php 65 | * [ 66 | * // required, height of the body portlet as a px 67 | * 'height' => 150, 68 | * // optional, HTML attributes of the scroller 69 | * 'options' => [], 70 | * // optional, footer of the scroller. May contain string or array(the 71 | * options of Link component) 72 | * 'footer' => [ 73 | * 'label' => 'Show all', 74 | * ], 75 | * ] 76 | * ``` 77 | */ 78 | public $scroller = []; 79 | 80 | /** 81 | * @var bool if we should use pull-right menu 82 | */ 83 | public $pullRight = false; 84 | 85 | /** 86 | * @var bool if this is a drop-up 87 | */ 88 | public $dropUp = false; 89 | 90 | public function init() 91 | { 92 | 93 | Html::addCssClass($this->options, 'dropdown-menu-list'); 94 | if ($this->dropUp) { 95 | Html::addCssClass($this->options, 'bottom-up'); 96 | } 97 | if ($this->pullRight) { 98 | Html::addCssClass($this->options, 'pull-right'); 99 | } 100 | if (count($this->scroller) > 0) { 101 | Html::addCssClass($this->options, 'scroller'); 102 | } 103 | 104 | parent::init(); 105 | } 106 | 107 | /** 108 | * Executes the widget. 109 | */ 110 | public function run() 111 | { 112 | 113 | echo $this->renderItems($this->items); 114 | } 115 | 116 | /** 117 | * Renders menu items. 118 | * 119 | * @param array $items the menu items to be rendered 120 | * 121 | * @return string the rendering result. 122 | * @throws InvalidConfigException if the label option is not specified in 123 | * one of the items. 124 | */ 125 | protected function renderItems($items, $options = []) 126 | { 127 | $lines = []; 128 | if ($this->title) { 129 | $lines[] = Html::tag('li', Html::tag('p', $this->title)); 130 | } 131 | 132 | if (!empty($this->scroller)) { 133 | if (!isset($this->scroller['height'])) { 134 | throw new InvalidConfigException("The 'height' option of Scroller is required."); 135 | } 136 | $lines[] = Html::beginTag('li'); 137 | $lines[] = Html::beginTag('ul', [ 138 | 'style' => 'height: ' . $this->scroller['height'] . 'px;', 139 | 'class' => $this->options['class'], 140 | ] 141 | ); 142 | } 143 | 144 | foreach ($items as $i => $item) { 145 | if (isset($item['visible']) && !$item['visible']) { 146 | unset($items[$i]); 147 | continue; 148 | } 149 | if (is_string($item)) { 150 | $lines[] = $item; 151 | continue; 152 | } 153 | 154 | if (in_array('divider', $item)) { 155 | $lines[] = Html::tag('li', '', ['class' => 'divider']); 156 | continue; 157 | } 158 | 159 | if (!isset($item['label'])) { 160 | throw new InvalidConfigException("The 'label' option is required."); 161 | } 162 | $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; 163 | 164 | $icon = ArrayHelper::getValue($item, 'icon', null); 165 | if ($icon) { 166 | $label = Html::tag('i', '', 167 | ['alt' => $label, 'class' => $icon]) . ' ' . $label; 168 | } 169 | $label .= ArrayHelper::getValue($item, 'badge', ''); 170 | $options = ArrayHelper::getValue($item, 'options', []); 171 | $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); 172 | $linkOptions['tabindex'] = '-1'; 173 | 174 | if (ArrayHelper::getValue($item, 'linkType', 175 | self::LINK_TYPE_LINK) == self::LINK_TYPE_LINK) { 176 | $content = Html::a($label, 177 | ArrayHelper::getValue($item, 'url', '#'), $linkOptions); 178 | } else { 179 | $content = Html::checkbox($label, true, $linkOptions); 180 | } 181 | $lines[] = Html::tag('li', $content, $options); 182 | } 183 | 184 | if (!empty($this->scroller)) { 185 | $lines[] = Html::endTag('ul'); 186 | $lines[] = Html::endTag('li'); 187 | } 188 | 189 | if (!empty($this->more)) { 190 | $url = ArrayHelper::getValue($this->more, 'url', '#'); 191 | $text = ArrayHelper::getValue($this->more, 'label', ''); 192 | $icon = ArrayHelper::getValue($this->more, 'icon', ''); 193 | if ($icon) { 194 | $icon = Html::tag('i', '', ['class' => $icon]); 195 | } 196 | $lines[] = Html::tag('li', 197 | Html::tag('a', $text . $icon, ['href' => $url]), 198 | ['class' => 'external']); 199 | } 200 | 201 | return Html::tag('ul', implode("\n", $lines), $this->options); 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /widgets/DropdownContent.php: -------------------------------------------------------------------------------- 1 | 'Action', 21 | * 'dropdown' => 'Content', 22 | * ]); 23 | * ``` 24 | */ 25 | class DropdownContent extends ButtonDropdown 26 | { 27 | /** 28 | * @var string the button label 29 | */ 30 | public $label = 'Button'; 31 | /** 32 | * @var array the HTML attributes of the button. 33 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 34 | */ 35 | public $options = []; 36 | /** 37 | * @var string the dropdown content. 38 | */ 39 | public $dropdown = ''; 40 | 41 | /** 42 | * Executes the widget. 43 | */ 44 | public function run() 45 | { 46 | echo Html::beginTag('div', ['class' => 'btn-group']); 47 | echo $this->renderButton() . "\n" . $this->renderDropdown(); 48 | echo Html::endTag('div'); 49 | 50 | $this->registerPlugin('button'); 51 | 52 | } 53 | 54 | /** 55 | * Generates the button dropdown. 56 | * @return string the rendering result. 57 | */ 58 | protected function renderButton() 59 | { 60 | Html::addCssClass($this->options, 'btn'); 61 | $label = $this->label; 62 | if ($this->encodeLabel) { 63 | $label = Html::encode($label); 64 | } 65 | if ($this->split) { 66 | $options = $this->options; 67 | $this->options['data-toggle'] = 'dropdown'; 68 | Html::addCssClass($this->options, 'dropdown-toggle'); 69 | $splitButton = BButton::widget([ 70 | 'label' => '', 71 | 'encodeLabel' => false, 72 | 'options' => $this->options, 73 | 'view' => $this->getView(), 74 | ]); 75 | } else { 76 | $label .= ' '; 77 | $options = $this->options; 78 | if (!isset($options['href'])) { 79 | $options['href'] = '#'; 80 | } 81 | Html::addCssClass($options, 'dropdown-toggle'); 82 | $options['data-toggle'] = 'dropdown'; 83 | $splitButton = ''; 84 | } 85 | 86 | return BButton::widget([ 87 | 'tagName' => $this->tagName, 88 | 'label' => $label, 89 | 'options' => $options, 90 | 'encodeLabel' => false, 91 | 'view' => $this->getView(), 92 | ]) . "\n" . $splitButton; 93 | } 94 | 95 | /** 96 | * Gets dropdown content. 97 | * @return string the rendering result. 98 | */ 99 | protected function renderDropdown() 100 | { 101 | return Html::tag('div', $this->dropdown, ['class' => 'dropdown-menu']); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /widgets/GridView.php: -------------------------------------------------------------------------------- 1 |
    {summary}
    \n
    {pager}
    "; 21 | 22 | /** 23 | * @var boolean indicates if grid is sortable 24 | */ 25 | public $sortable = false; 26 | 27 | /** 28 | * Inits widget 29 | */ 30 | public function init() 31 | { 32 | parent::init(); 33 | 34 | $this->initPager(); 35 | 36 | $this->initVisible(); 37 | 38 | $this->initSortable(); 39 | 40 | //GridViewAsset::register($this->view); 41 | } 42 | 43 | /** 44 | * Renders the data models for the grid view. 45 | */ 46 | public function renderItems() 47 | { 48 | /* 49 | $content = array_filter([ 50 | $this->renderCaption(), 51 | $this->renderColumnGroup(), 52 | $this->showHeader ? $this->renderTableHeader() : false, 53 | $this->showFooter ? $this->renderTableFooter() : false, 54 | $this->renderTableBody(), 55 | ]); 56 | 57 | $table = Html::tag('table', implode("\n", $content), $this->tableOptions); 58 | if ($this->responsive) 59 | { 60 | $table = Html::tag('div', $table, ['class' => 'table-responsive']); 61 | } 62 | else 63 | { 64 | $table = Html::tag('div', $table, ['class' => 'table-scrollable']); 65 | } 66 | 67 | return $table; 68 | * 69 | */ 70 | return parent::renderItems(); 71 | } 72 | 73 | /** 74 | * Inits pager 75 | */ 76 | protected function initPager() 77 | { 78 | $this->pager['firstPageLabel'] = Html::tag('i', '', [ 79 | 'class' => 'fa fa-angle-double-left', 80 | ]); 81 | 82 | $this->pager['lastPageLabel'] = Html::tag('i', '', [ 83 | 'class' => 'fa fa-angle-double-right', 84 | ]); 85 | 86 | $this->pager['prevPageLabel'] = Html::tag('i', '', [ 87 | 'class' => 'fa fa-angle-left', 88 | ]); 89 | 90 | $this->pager['nextPageLabel'] = Html::tag('i', '', [ 91 | 'class' => 'fa fa-angle-right', 92 | ]); 93 | } 94 | 95 | protected function initVisible() 96 | { 97 | $columns = $this->getStorageColumns(); 98 | if (empty($columns)) 99 | { 100 | return; 101 | } 102 | foreach ($this->columns as $i => $column) 103 | { 104 | if (array_search($i, $columns) === false) 105 | { 106 | unset($this->columns[$i]); 107 | } 108 | } 109 | } 110 | 111 | /** 112 | * Inits sortable behavior on gridview 113 | */ 114 | protected function initSortable() 115 | { 116 | $route = ArrayHelper::getValue($this->sortable, 'url', false); 117 | 118 | if ($route) 119 | { 120 | $url = Url::toRoute($route); 121 | 122 | $options = json_encode(ArrayHelper::getValue($this->sortable, 'options', [])); 123 | 124 | $view = $this->getView(); 125 | $view->registerJs("jQuery('#{$this->id}').SortableGridView('{$url}', {$options});"); 126 | GridViewSortableAsset::register($view); 127 | } 128 | } 129 | 130 | protected function getStorageColumns() 131 | { 132 | return []; 133 | } 134 | } -------------------------------------------------------------------------------- /widgets/InputWidget.php: -------------------------------------------------------------------------------- 1 | hasModel() && $this->name === null) { 41 | throw new InvalidConfigException("Either 'name', or 'model' and 'attribute' properties must be specified."); 42 | } 43 | if (!isset($this->options['id'])) { 44 | $this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId(); 45 | } 46 | parent::init(); 47 | } 48 | 49 | /** 50 | * @return boolean whether this widget is associated with a data model. 51 | */ 52 | protected function hasModel() 53 | { 54 | return $this->model instanceof Model && $this->attribute !== null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /widgets/IonRangeSlider.php: -------------------------------------------------------------------------------- 1 | 'ionRangeSlider', 23 | * 'clientOptions' => [ 24 | * 'min' => 0, 25 | * 'max' => 5000, 26 | * 'from' => 1000, // default value 27 | * 'to' => 4000, // default value 28 | * 'type' => 'double', 29 | * 'step' => 1, 30 | * 'prefix' => "$", 31 | * 'prettify' => false, 32 | * 'hasGrid' => true 33 | * ], 34 | * ]); 35 | * ``` 36 | * @see https://github.com/IonDen/ion.rangeSlider 37 | */ 38 | class IonRangeSlider extends InputWidget { 39 | 40 | /** 41 | * Types 42 | */ 43 | const TYPE_SINGLE = 'single'; 44 | const TYPE_DOUBLE = 'double'; 45 | /** 46 | * @var string separator values 47 | */ 48 | public $separator = ';'; 49 | 50 | /** 51 | * Executes the widget. 52 | */ 53 | public function run() 54 | { 55 | if ($this->hasModel()) 56 | { 57 | $values = explode($this->separator, $this->model->{$this->attribute}); 58 | if (count($values) == 2) 59 | { 60 | $this->clientOptions['from'] = (int) $values[0]; 61 | $this->clientOptions['to'] = (int) $values[1]; 62 | } 63 | echo Html::activeTextInput($this->model, $this->attribute, $this->options); 64 | } 65 | else 66 | { 67 | $values = explode($this->separator, $this->value); 68 | if (count($values) == 2) 69 | { 70 | $this->clientOptions['from'] = (int) $values[0]; 71 | $this->clientOptions['to'] = (int) $values[1]; 72 | } 73 | echo Html::textInput($this->name, $this->value, $this->options); 74 | } 75 | IonRangeSliderAsset::register($this->view); 76 | $this->registerPlugin('ionRangeSlider'); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /widgets/Link.php: -------------------------------------------------------------------------------- 1 | 'Link', 21 | * 'url' => 'http://yii2metronic.icron.org/', 22 | * 'icon' => 'm-icon-swapright m-icon-gray', 23 | * 'iconPosition' => Link::ICON_POSITION_LEFT, 24 | * ]); 25 | * ``` 26 | */ 27 | class Link extends Widget { 28 | 29 | // Icon position 30 | const ICON_POSITION_LEFT = 'left'; 31 | const ICON_POSITION_RIGHT = 'right'; 32 | 33 | /** 34 | * @var string The button label 35 | */ 36 | public $label; 37 | 38 | /** 39 | * @var bool Whether the label should be HTML-encoded 40 | */ 41 | public $encodeLabel = true; 42 | 43 | /** 44 | * @var string The link url 45 | */ 46 | public $url = '#'; 47 | 48 | /** 49 | * @var string The button icon 50 | */ 51 | public $icon = 'm-icon-swapright m-icon-gray'; 52 | 53 | /** 54 | * @var string Icon position 55 | * Valid values are 'left', 'right' 56 | */ 57 | public $iconPosition = self::ICON_POSITION_RIGHT; 58 | 59 | /** 60 | * Label options 61 | */ 62 | public $labelOptions = []; 63 | 64 | /** 65 | * Initializes the widget. 66 | * @throws InvalidConfigException 67 | */ 68 | public function init() 69 | { 70 | if ($this->label === null) 71 | { 72 | throw new InvalidConfigException("The 'label' option is required."); 73 | } 74 | 75 | if ($this->url === null) 76 | { 77 | $this->url = '#'; 78 | } 79 | } 80 | 81 | /** 82 | * Renders the widget. 83 | */ 84 | public function run() 85 | { 86 | $icon = ($this->icon === null) ? '' : Html::tag('i', '', ['class' => $this->icon]); 87 | $label = Html::tag('span', Html::encode($this->label), $this->labelOptions); 88 | 89 | if (strcasecmp($this->iconPosition, self::ICON_POSITION_LEFT) === 0) 90 | { 91 | $content = sprintf('%s %s', $icon, $label); 92 | } 93 | else 94 | { 95 | $content = sprintf('%s %s', $label, $icon); 96 | } 97 | echo Html::a($content, $this->url, $this->options); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /widgets/ListView.php: -------------------------------------------------------------------------------- 1 | initSortable(); 36 | } 37 | 38 | /** 39 | * Inits sortable behavior 40 | */ 41 | protected function initSortable() 42 | { 43 | $route = ArrayHelper::getValue($this->sortable, 'url', false); 44 | 45 | if ($route) 46 | { 47 | $url = Url::toRoute($route); 48 | 49 | if (ArrayHelper::keyExists('class', $this->itemOptions)) 50 | { 51 | $this->itemOptions['class'] = sprintf('%s %s', $this->itemOptions['class'], self::SORTABLE_ITEM_CLASS); 52 | } 53 | else 54 | { 55 | $this->itemOptions['class'] = self::SORTABLE_ITEM_CLASS; 56 | } 57 | 58 | $options = json_encode(ArrayHelper::getValue($this->sortable, 'options', [])); 59 | 60 | $view = $this->getView(); 61 | $view->registerJs("jQuery('#{$this->id}').SortableListView('{$url}', {$options});"); 62 | 63 | $reload = ArrayHelper::getValue($this->sortable, 'reload', false); 64 | 65 | if ($reload) 66 | { 67 | $view->registerJs("jQuery('#{$this->id}').on('sortableSuccess', $reload)", \yii\web\View::POS_END); 68 | } 69 | 70 | ListViewSortableAsset::register($view); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /widgets/MultiSelect.php: -------------------------------------------------------------------------------- 1 | 'select1', 19 | * 'data' => ['1' => 'Item 1', '2' => 'Item 2'], 20 | * ]); 21 | * ``` 22 | * 23 | * @see http://loudev.com/ 24 | */ 25 | class MultiSelect extends InputWidget 26 | { 27 | /** 28 | * @var bool indicates whether the multiSelect is disabled or not. 29 | */ 30 | public $disabled; 31 | /** 32 | * @var array the option data items. The array keys are option values, and the array values 33 | * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). 34 | * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. 35 | * If you have a list of data models, you may convert them into the format described above using 36 | * [[\yii\helpers\ArrayHelper::map()]]. 37 | */ 38 | public $data = []; 39 | 40 | /** 41 | * Initializes the widget. 42 | */ 43 | public function init() 44 | { 45 | parent::init(); 46 | $this->options['multiple'] = true; 47 | if ($this->disabled) { 48 | $this->options['disabled'] = true; 49 | } 50 | Html::addCssClass($this->options, 'multi-select'); 51 | } 52 | /** 53 | * Executes the widget. 54 | */ 55 | public function run() 56 | { 57 | if ($this->hasModel()) { 58 | echo Html::activeDropDownList($this->model, $this->attribute, $this->data, $this->options, true); 59 | } else { 60 | echo Html::dropDownList($this->name, $this->value, $this->data, $this->options, true); 61 | } 62 | MultiSelectAsset::register($this->view); 63 | $this->registerPlugin('multiSelect'); 64 | } 65 | 66 | 67 | } -------------------------------------------------------------------------------- /widgets/Nav.php: -------------------------------------------------------------------------------- 1 | [ 24 | * [ 25 | * 'icon' => 'fa fa-warning', 26 | * 'badge' => Badge::widget(['label' => 'New', 'round' => false]), 27 | * 'label' => 'Home', 28 | * 'url' => ['site/index'], 29 | * 'linkOptions' => [...], 30 | * ], 31 | * [ 32 | * 'label' => 'Dropdown', 33 | * 'items' => [ 34 | * ['label' => 'Level 1 - Dropdown A', 'url' => '#'], 35 | * '
  • ', 36 | * '', 37 | * ['label' => 'Level 1 - Dropdown B', 'url' => '#'], 38 | * ], 39 | * ], 40 | * ], 41 | * ]); 42 | * ``` 43 | * 44 | * Note: Multilevel dropdowns beyond Level 1 are not supported in Bootstrap 3. 45 | */ 46 | class Nav extends \yii\bootstrap\Nav { 47 | 48 | /** 49 | * Positions 50 | */ 51 | const POS_DEFAULT = ''; 52 | const POS_LEFT = 'pull-left'; 53 | const POS_RIGHT = 'pull-right'; 54 | 55 | /** 56 | * Types 57 | */ 58 | const TYPE_DEFAULT = ''; 59 | const TYPE_NOTIFICATION = 'notification'; 60 | const TYPE_INBOX = 'inbox'; 61 | const TYPE_TASKS = 'tasks'; 62 | const TYPE_USER = 'user'; 63 | 64 | /** 65 | * Navbars 66 | */ 67 | const NAVBAR_DEFAULT = 'navbar-nav'; 68 | const NAVBAR_NONE = ''; 69 | 70 | /** 71 | * Items 72 | */ 73 | const ITEM_DIVIDER = 'divider'; 74 | 75 | /** 76 | * Tags 77 | */ 78 | const TAG_LINK = 'a'; 79 | 80 | /** 81 | * @var array list of items in the nav widget. Each array element represents a single 82 | * menu item which can be either a string or an array with the following structure: 83 | * 84 | * - label: string, required, the nav item label. 85 | * - icon: string, optional, the nav item icon. 86 | * - badge: array, optional 87 | * - url: optional, the item's URL. Defaults to "#". 88 | * - visible: boolean, optional, whether this menu item is visible. Defaults to true. 89 | * - linkOptions: array, optional, the HTML attributes of the item's link. 90 | * - options: array, optional, the HTML attributes of the item container (LI). 91 | * - active: boolean, optional, whether the item should be on active state or not. 92 | * - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget, 93 | * or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus. 94 | * 95 | * If a menu item is a string, it will be rendered directly without HTML encoding. 96 | */ 97 | public $items = []; 98 | 99 | /** 100 | * @var string the nav position 101 | */ 102 | public $position = self::POS_DEFAULT; 103 | 104 | /** 105 | * @var string dropdownType 106 | */ 107 | public $dropdownType = self::TYPE_DEFAULT; 108 | 109 | /** 110 | * @var string navbar holder 111 | */ 112 | public $navbar = self::NAVBAR_DEFAULT; 113 | 114 | /** 115 | * Initializes the widget. 116 | */ 117 | public function init() 118 | { 119 | Html::addCssClass($this->options, $this->navbar); 120 | Html::addCssClass($this->options, $this->position); 121 | parent::init(); 122 | } 123 | 124 | /** 125 | * Renders a widget's item. 126 | * @param string|array $item the item to render. 127 | * @return string the rendering result. 128 | * @throws InvalidConfigException 129 | */ 130 | public function renderItem($item) 131 | { 132 | if (is_string($item)) 133 | { 134 | return $item; 135 | } 136 | 137 | if (in_array(self::ITEM_DIVIDER, $item, true)) 138 | { 139 | return Html::tag('li', '', ['class' => self::ITEM_DIVIDER]); 140 | } 141 | 142 | $items = ArrayHelper::getValue($item, 'items'); 143 | 144 | if ($items === null) 145 | { 146 | return parent::renderItem($item); 147 | } 148 | 149 | if (!isset($item['label']) && !isset($item['icon'])) 150 | { 151 | throw new InvalidConfigException("The 'label' option is required."); 152 | } 153 | 154 | $dropdownType = ArrayHelper::getValue($item, 'dropdownType', self::TYPE_DEFAULT); 155 | $options = ArrayHelper::getValue($item, 'options', []); 156 | 157 | Html::addCssClass($options, 'dropdown'); 158 | 159 | if ($dropdownType !== self::TYPE_DEFAULT) 160 | { 161 | if ($dropdownType !== self::TYPE_USER) 162 | { 163 | Html::addCssClass($options, 'dropdown-extended'); 164 | } 165 | 166 | Html::addCssClass($options, 'dropdown-'.$dropdownType); 167 | 168 | if (Metronic::getComponent() && Metronic::HEADER_DROPDOWN_DARK === Metronic::getComponent()->headerDropdown) 169 | { 170 | Html::addCssClass($options, 'dropdown-dark'); 171 | } 172 | } 173 | 174 | if (isset($item['active'])) 175 | { 176 | $active = ArrayHelper::remove($item, 'active', false); 177 | } 178 | else 179 | { 180 | $active = $this->isItemActive($item); 181 | } 182 | 183 | if ($active) 184 | { 185 | Html::addCssClass($options, 'active'); 186 | } 187 | 188 | return Html::tag('li', sprintf('%s%s', $this->_getLinkTag($item), $this->_getDropdownTag($item)), $options); 189 | } 190 | 191 | /** 192 | * Retrieves link tag 193 | * @param array $item given item 194 | * @return string link 195 | */ 196 | private function _getLinkTag($item) 197 | { 198 | $dropdownType = ArrayHelper::getValue($item, 'dropdownType', self::TYPE_DEFAULT); 199 | 200 | if ($dropdownType !== self::TYPE_DEFAULT) 201 | { 202 | $label = $item['label']; 203 | } 204 | else 205 | { 206 | $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; 207 | } 208 | 209 | $icon = ArrayHelper::getValue($item, 'icon', null); 210 | 211 | if ($icon) 212 | { 213 | $label = Html::tag('i', '', ['alt' => $label, 'class' => $icon]); 214 | } 215 | 216 | $label .= ArrayHelper::getValue($item, 'badge', ''); 217 | 218 | $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); 219 | 220 | $linkOptions['data-toggle'] = 'dropdown'; 221 | $linkOptions['data-hover'] = 'dropdown'; 222 | $linkOptions['data-close-others'] = 'true'; 223 | 224 | Html::addCssClass($linkOptions, 'dropdown-toggle'); 225 | 226 | $tag = ArrayHelper::getValue($item, 'tag', 'a'); 227 | 228 | $url = ArrayHelper::getValue($item, 'url', false); 229 | 230 | if (!$url) 231 | { 232 | if (self::TAG_LINK == $tag) 233 | { 234 | $linkOptions['href'] = 'javascript:;'; 235 | } 236 | 237 | return Html::tag($tag, $label, $linkOptions); 238 | } 239 | 240 | if (self::TAG_LINK == $tag) 241 | { 242 | $linkOptions['href'] = Url::toRoute(ArrayHelper::getValue($item, 'url', '#')); 243 | } 244 | 245 | return Html::tag($tag, $label, $linkOptions); 246 | } 247 | 248 | /** 249 | * Retrieves items tag 250 | * @param array $item given parent item 251 | * @return Dropdown widget 252 | */ 253 | private function _getDropdownTag($item) 254 | { 255 | $dropdownType = ArrayHelper::getValue($item, 'dropdownType', self::TYPE_DEFAULT); 256 | 257 | $items = ArrayHelper::getValue($item, 'items', null); 258 | 259 | if ($items !== null && is_array($items)) 260 | { 261 | if ($dropdownType === self::TYPE_DEFAULT || $dropdownType === self::TYPE_USER) 262 | { 263 | $options = ['class' => 'dropdown-menu-default']; 264 | } 265 | else 266 | { 267 | $options = ['class' => sprintf('%s %s', 'dropdown-menu-default extended', $dropdownType)]; 268 | } 269 | 270 | if ($this->activateItems) 271 | { 272 | $items = $this->isChildActive($items, $active); 273 | } 274 | 275 | $items = Dropdown::widget([ 276 | 'title' => ArrayHelper::getValue($item, 'title', ''), 277 | 'more' => ArrayHelper::getValue($item, 'more', []), 278 | 'scroller' => ArrayHelper::getValue($item, 'scroller', []), 279 | 'items' => $items, 280 | 'encodeLabels' => $this->encodeLabels, 281 | 'clientOptions' => false, 282 | 'options' => $options, 283 | ]); 284 | } 285 | 286 | return $items; 287 | } 288 | 289 | /** 290 | * Renders user item. 291 | * @param $label string User label 292 | * @param $photo string User photo url 293 | * @return string the rendering result 294 | */ 295 | public static function userItem($label, $photo) 296 | { 297 | $lines = []; 298 | $lines[] = Html::tag('span', $label, ['class' => 'username username-hide-on-mobile']); 299 | $lines[] = Html::img($photo, ['alt' => $label, 'class' => 'img-circle']); 300 | return implode("\n", $lines); 301 | } 302 | } -------------------------------------------------------------------------------- /widgets/NavBar.php: -------------------------------------------------------------------------------- 1 | 'NavBar Test', 27 | * 'brandLogoUrl' => '/img/logo.png', 28 | * ]); 29 | * echo Nav::widget([ 30 | * 'items' => [ 31 | * ['label' => 'Home', 'url' => ['/site/index']], 32 | * ['label' => 'About', 'url' => ['/site/about']], 33 | * ], 34 | * ]); 35 | * NavBar::end(); 36 | * ``` 37 | * 38 | * @see http://twitter.github.io/bootstrap/components.html#navbar 39 | */ 40 | class NavBar extends \yii\bootstrap\NavBar { 41 | 42 | /** 43 | * @var string the url to logo of the brand. 44 | */ 45 | public $brandLogoUrl; 46 | 47 | /** 48 | * @var string the url to logo of the brand. 49 | */ 50 | public $brandWrapperOptions; 51 | 52 | /** 53 | * Initializes the widget. 54 | */ 55 | public function init() 56 | { 57 | if (!isset($this->options['id'])) 58 | { 59 | $this->options['id'] = $this->getId(); 60 | } 61 | 62 | echo Html::beginTag('div', $this->options); 63 | echo Html::beginTag('div', ['class' => 'page-header-inner']); 64 | 65 | Html::addCssClass($this->brandWrapperOptions, 'page-logo'); 66 | echo Html::beginTag('div', $this->brandWrapperOptions); 67 | echo $this->renderBrand(); 68 | echo $this->renderToggleButton(); 69 | echo Html::endTag('div'); 70 | } 71 | 72 | /** 73 | * Executes the widget. 74 | */ 75 | public function run() 76 | { 77 | echo Html::endTag('div'); 78 | echo Html::endTag('div'); 79 | } 80 | 81 | /** 82 | * Renders toggle button 83 | * @return string the rendering result 84 | */ 85 | protected function renderToggleButton() 86 | { 87 | return Html::tag('div', '', ['class' => 'menu-toggler sidebar-toggler']); 88 | } 89 | 90 | /** 91 | * Renders Brand 92 | * @return string the rendering result 93 | */ 94 | protected function renderBrand() 95 | { 96 | if ($this->brandLogoUrl) 97 | { 98 | $content = Html::img($this->brandLogoUrl, ['class' => 'logo-default', 'alt' => $this->brandLabel]); 99 | } 100 | else 101 | { 102 | $content = $this->brandLabel; 103 | } 104 | 105 | $this->brandOptions['href'] = $this->brandUrl; 106 | 107 | return Html::tag('a', $content, $this->brandOptions); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /widgets/Note.php: -------------------------------------------------------------------------------- 1 | 'Success! Some Header Goes Here', 18 | * 'body' => 'Duis mollis, est non commodo luctus', 19 | * 'type' => Note::TYPE_INFO, 20 | * ]); 21 | * ``` 22 | * 23 | * The following example will show the content enclosed between the [[begin()]] 24 | * and [[end()]] calls within the alert box: 25 | * ```php 26 | * Note::begin(['type' => Note::TYPE_DANGER]); 27 | * echo 'Some title and body'; 28 | * Note::end(); 29 | * ``` 30 | */ 31 | class Note extends Widget { 32 | 33 | const TYPE_DANGER = 'danger'; 34 | const TYPE_INFO = 'info'; 35 | const TYPE_SUCCESS = 'success'; 36 | const TYPE_WARNING = 'warning'; 37 | 38 | /** 39 | * @var string the note title 40 | */ 41 | public $title; 42 | 43 | /** 44 | * @var string the note body 45 | */ 46 | public $body; 47 | 48 | /** 49 | * @var string the note type. 50 | * Valid values are 'danger', 'info', 'success', 'warning'. 51 | */ 52 | public $type = self::TYPE_SUCCESS; 53 | 54 | /** 55 | * Initializes the widget. 56 | */ 57 | public function init() 58 | { 59 | parent::init(); 60 | Html::addCssClass($this->options, 'note note-'.$this->type); 61 | echo Html::beginTag('div', $this->options); 62 | echo $this->renderTitle(); 63 | } 64 | 65 | /** 66 | * Executes the widget. 67 | */ 68 | public function run() 69 | { 70 | echo $this->renderBody(); 71 | echo Html::endTag('div'); 72 | } 73 | 74 | /** 75 | * Renders title 76 | * @return string the rendering result 77 | */ 78 | public function renderTitle() 79 | { 80 | return !empty($this->title) ? Html::tag('h4', $this->title, ['class' => 'block']) : ''; 81 | } 82 | 83 | /** 84 | * Renders body 85 | * @return string the rendering result 86 | */ 87 | public function renderBody() 88 | { 89 | return !empty($this->body) ? Html::tag('p', $this->body) : ''; 90 | } 91 | } -------------------------------------------------------------------------------- /widgets/Notification.php: -------------------------------------------------------------------------------- 1 | 'Success! Some Header Goes Here', 22 | * 'body' => 'Duis mollis, est non commodo luctus', 23 | * 'type' => Notification::TYPE_INFO, 24 | * 'openButton' => [ 25 | * 'type' => Button::TYPE_M_GREEN, 26 | * 'label' => 'Notification', 27 | * 'icon' => 'fa fa-bell-o', 28 | * ] 29 | * ]); 30 | * ``` 31 | * 32 | * The following example will show the content enclosed between the [[begin()]] 33 | * and [[end()]] calls within the alert box: 34 | * ```php 35 | * Notification::begin(['type' => Notification::TYPE_DANGER]); 36 | * echo 'Some title and body'; 37 | * Notification::end(); 38 | * ``` 39 | * @see https://github.com/CodeSeven/toastr 40 | */ 41 | class Notification extends Widget 42 | { 43 | // type 44 | const TYPE_ERROR = 'error'; 45 | const TYPE_INFO = 'info'; 46 | const TYPE_SUCCESS = 'success'; 47 | const TYPE_WARNING = 'warning'; 48 | // position 49 | const POSITION_TOP_RIGHT = 'toast-top-right'; 50 | const POSITION_BOTTOM_RIGHT = 'toast-bottom-right'; 51 | const POSITION_BOTTOM_LEFT = 'toast-bottom-left'; 52 | const POSITION_TOP_LEFT = 'toast-top-left'; 53 | const POSITION_TOP_CENTER = 'toast-top-center'; 54 | const POSITION_BOTTOM_CENTER = 'toast-bottom-center'; 55 | const POSITION_FULL_WIDTH = 'toast-top-full-width'; 56 | // easing 57 | const EASING_LINEAR = 'linear'; 58 | const EASING_SWING = 'swing'; 59 | 60 | /** 61 | * @var string the notification title 62 | */ 63 | public $title = ''; 64 | /** 65 | * @var string the notification body 66 | */ 67 | public $body = ''; 68 | /** 69 | * @var string the notification type. 70 | * Valid values are 'danger', 'info', 'success', 'warning'. 71 | */ 72 | public $type = self::TYPE_SUCCESS; 73 | /** 74 | * @var array the configuration array for [[Button]]. 75 | */ 76 | public $openButton = []; 77 | 78 | /** 79 | * Executes the widget. 80 | */ 81 | public function init() 82 | { 83 | parent::init(); 84 | $this->initOptions(); 85 | ob_start(); 86 | ob_implicit_flush(false); 87 | } 88 | 89 | public function run() 90 | { 91 | $this->body .= ob_get_clean(); 92 | if (!empty($this->openButton)) { 93 | /** @var Button $widget */ 94 | $js = 'toastr.options = ' . Json::encode($this->clientOptions) . ';'; 95 | $this->view->registerJs($js, View::POS_READY); 96 | $this->initOpenButton(); 97 | } else { 98 | return null; 99 | } 100 | NotificationAsset::register($this->view); 101 | } 102 | 103 | /** 104 | * Initializes the widget options. 105 | * This method sets the default values for various options. 106 | */ 107 | public function initOptions() 108 | { 109 | $defaultOptions = [ 110 | 'closeButton'=> true, 111 | 'debug'=> false, 112 | 'positionClass'=> 'toast-top-right', 113 | 'onclick'=> null, 114 | 'showDuration'=> '1000', 115 | 'hideDuration'=> '1000', 116 | 'timeOut'=> '5000', 117 | 'extendedTimeOut'=> '1000', 118 | 'showEasing'=> 'swing', 119 | 'hideEasing'=> 'linear', 120 | 'showMethod'=> 'fadeIn', 121 | 'hideMethod'=> 'fadeOut' 122 | ]; 123 | 124 | $this->clientOptions = array_merge($defaultOptions, $this->clientOptions); 125 | } 126 | 127 | /** 128 | * Initializes the widget Button options. 129 | * This method sets the default values for various options. 130 | */ 131 | public function initOpenButton() 132 | { 133 | $widget = Button::begin($this->openButton); 134 | $msg = "'{$this->body}', '{$this->title}'"; 135 | $jsOpen = 'toastr.' . $this->type . '(' . $msg . ')'; 136 | if(!isset($widget->clientEvents['click'])) { 137 | $widget->clientEvents['click'] = "function(){{$jsOpen};}"; 138 | } 139 | $widget->run(); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /widgets/Panel.php: -------------------------------------------------------------------------------- 1 | 'fa fa-bell-o', 22 | * 'title' => 'Title Panel', 23 | * ]); 24 | * echo 'Body portlet'; 25 | * Panel::end(); 26 | * 27 | * 28 | * @see http://yii2metronic.icron.org/components.html#portlet 29 | * @author icron.org 30 | * @since 1.0 31 | */ 32 | class Panel extends Widget { 33 | 34 | /** 35 | * Types 36 | */ 37 | const TYPE_DEFAULT = 'panel-default'; 38 | 39 | /** 40 | * @var string The portlet title 41 | */ 42 | public $title; 43 | 44 | /** 45 | * @var string The portlet icon 46 | */ 47 | public $icon; 48 | 49 | /** 50 | * @var string The portlet type 51 | * Valid values are 'box', 'solid', '' 52 | */ 53 | public $type = self::TYPE_DEFAULT; 54 | 55 | /** 56 | * @var string The portlet color 57 | * Valid values are 'light-blue', 'blue', 'red', 'yellow', 'green', 'purple', 'light-grey', 'grey' 58 | */ 59 | public $color = ''; 60 | 61 | /** 62 | * @var array The HTML attributes for the widget container 63 | */ 64 | public $options = []; 65 | 66 | /** 67 | * @var array The HTML attributes for the widget body container 68 | */ 69 | public $bodyOptions = []; 70 | 71 | /** 72 | * @var array The HTML attributes for the widget body container 73 | */ 74 | public $headerOptions = []; 75 | 76 | /** 77 | * Initializes the widget. 78 | */ 79 | public function init() 80 | { 81 | parent::init(); 82 | 83 | Html::addCssClass($this->options, trim(sprintf('panel %s', $this->type))); 84 | echo Html::beginTag('div', $this->options); 85 | 86 | $this->_renderTitle(); 87 | 88 | Html::addCssClass($this->bodyOptions, 'panel-body'); 89 | echo Html::beginTag('div', $this->bodyOptions); 90 | } 91 | 92 | /** 93 | * Renders the widget. 94 | */ 95 | public function run() 96 | { 97 | echo Html::endTag('div'); // End panel body 98 | echo Html::endTag('div'); // End panel div 99 | } 100 | 101 | /** 102 | * Renders portlet title 103 | */ 104 | private function _renderTitle() 105 | { 106 | if (false !== $this->title) 107 | { 108 | Html::addCssClass($this->headerOptions, 'panel-heading'); 109 | 110 | echo Html::beginTag('div', $this->headerOptions); 111 | 112 | echo Html::beginTag('div', ['class' => $this->pushFontColor('panel-title')]); 113 | 114 | if ($this->icon) 115 | { 116 | echo Html::tag('i', '', ['class' => $this->icon]); 117 | } 118 | 119 | echo Html::tag('span', $this->title); 120 | 121 | echo Html::endTag('div'); 122 | 123 | echo Html::endTag('div'); 124 | } 125 | } 126 | 127 | /** 128 | * Retrieves font color 129 | */ 130 | protected function getFontColor() 131 | { 132 | if ($this->color) 133 | { 134 | return sprintf('font-%s', $this->color); 135 | } 136 | 137 | return ''; 138 | } 139 | 140 | /** 141 | * Pushes font color to given string 142 | */ 143 | protected function pushFontColor($string) 144 | { 145 | $color = $this->getFontColor(); 146 | 147 | if ($color) 148 | { 149 | return sprintf('%s %s', $string, $color); 150 | } 151 | 152 | return $string; 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /widgets/Portlet.php: -------------------------------------------------------------------------------- 1 | 'fa fa-bell-o', 25 | * 'title' => 'Title Portlet', 26 | * ]); 27 | * echo 'Body portlet'; 28 | * Portlet::end(); 29 | * 30 | * // Portlet with tools, actions, scroller, events and remote content 31 | * Portlet::begin([ 32 | * 'title' => 'Extended Portlet', 33 | * 'scroller' => [ 34 | * 'height' => 150, 35 | * 'footer' => ['label' => 'Show all', 'url' => '#'], 36 | * ], 37 | * 'clientOptions' => [ 38 | * 'loadSuccess' => new \yii\web\JsExpression('function(){ console.log("load success"); }'), 39 | * 'remote' => '/?r=site/about', 40 | * ], 41 | * 'clientEvents' => [ 42 | * 'close.mr.portlet' => 'function(e) { console.log("portlet closed"); e.preventDefault(); }' 43 | * ], 44 | * 'tools' => [ 45 | * Portlet::TOOL_RELOAD, 46 | * Portlet::TOOL_MINIMIZE, 47 | * Portlet::TOOL_CLOSE, 48 | * ], 49 | * ]); 50 | * ``` 51 | * 52 | * @see http://yii2metronic.icron.org/components.html#portlet 53 | * @author icron.org 54 | * @since 1.0 55 | */ 56 | class Portlet extends Widget 57 | { 58 | 59 | /** 60 | * Types 61 | */ 62 | const TYPE_LIGHT = 'light'; 63 | const TYPE_NONE = ''; 64 | 65 | /** 66 | * Tools 67 | */ 68 | const TOOL_MINIMIZE = 'collapse'; 69 | const TOOL_MODAL = 'modal'; 70 | const TOOL_RELOAD = 'reload'; 71 | const TOOL_CLOSE = 'remove'; 72 | 73 | /** 74 | * @var string The portlet title 75 | */ 76 | public $title; 77 | 78 | /** 79 | * @var string The portlet title helper 80 | */ 81 | public $helper; 82 | 83 | /** 84 | * @var string The portlet icon 85 | */ 86 | public $icon; 87 | 88 | /** 89 | * @var string The portlet type 90 | * Valid values are 'box', 'solid', '' 91 | */ 92 | public $type = self::TYPE_LIGHT; 93 | 94 | /** 95 | * @var string The portlet color 96 | * Valid values are 'light-blue', 'blue', 'red', 'yellow', 'green', 'purple', 'light-grey', 'grey' 97 | */ 98 | public $color = ''; 99 | 100 | /** 101 | * @var string The portlet background color 102 | */ 103 | public $background = ''; 104 | 105 | /** 106 | * @var array List of actions, where each element must be specified as a string. 107 | */ 108 | public $actions = []; 109 | 110 | /** 111 | * @var array The portlet tools 112 | * Valid values are 'collapse', 'modal', 'reload', 'remove' 113 | */ 114 | public $tools = []; 115 | 116 | /** 117 | * @var array Scroller options 118 | * is an array of the following structure: 119 | * ```php 120 | * [ 121 | * // required, height of the body portlet as a px 122 | * 'height' => 150, 123 | * // optional, HTML attributes of the scroller 124 | * 'options' => [], 125 | * // optional, footer of the scroller. May contain string or array(the options of Link component) 126 | * 'footer' => [ 127 | * 'label' => 'Show all', 128 | * ], 129 | * ] 130 | * ``` 131 | */ 132 | public $scroller = []; 133 | 134 | /** 135 | * @var Ribbon[] 136 | */ 137 | public $ribbons = []; 138 | 139 | /** 140 | * @var bool Whether the portlet should be bordered 141 | */ 142 | public $bordered = false; 143 | 144 | /** 145 | * @var array The HTML attributes for the widget container 146 | */ 147 | public $options = []; 148 | 149 | /** 150 | * @var array The HTML attributes for the widget body container 151 | */ 152 | public $bodyOptions = []; 153 | 154 | /** 155 | * @var array The HTML attributes for the widget body container 156 | */ 157 | public $headerOptions = []; 158 | 159 | /** 160 | * @var string tag title name 161 | */ 162 | public $tagTitle = 'h1'; 163 | 164 | /** 165 | * Initializes the widget. 166 | */ 167 | public function init() 168 | { 169 | parent::init(); 170 | 171 | Html::addCssClass($this->options, trim(sprintf('portlet %s %s', $this->type, $this->background))); 172 | if (count($this->ribbons)>0) { 173 | Html::addCssClass($this->options, 'mt-element-ribbon portlet-fit'); 174 | } 175 | echo Html::beginTag('div', $this->options); 176 | 177 | 178 | if (count($this->ribbons)>0) { 179 | $this->renderRibbon(); 180 | } 181 | 182 | $this->renderTitle(); 183 | 184 | Html::addCssClass($this->bodyOptions, 'portlet-body'); 185 | echo Html::beginTag('div', $this->bodyOptions); 186 | 187 | $this->renderScrollerBegin(); 188 | } 189 | 190 | /** 191 | * Renders the widget. 192 | */ 193 | public function run() 194 | { 195 | $this->renderScrollerEnd(); 196 | 197 | echo Html::endTag('div'); // End portlet body 198 | echo Html::endTag('div'); // End portlet div 199 | //$loader = Html::img(Metronic::getAssetsUrl($this->view) . '/img/loading-spinner-grey.gif'); 200 | //$this->clientOptions['loader'] = ArrayHelper::getValue($this->clientOptions, 'loader', $loader); 201 | //$this->registerPlugin('portlet'); 202 | } 203 | 204 | protected function renderRibbon() 205 | { 206 | /** @var Ribbon $r */ 207 | foreach($this->ribbons as $r) { 208 | print $r->run(); 209 | } 210 | } 211 | 212 | /** 213 | * Renders portlet title 214 | */ 215 | protected function renderTitle() 216 | { 217 | if (false !== $this->title) { 218 | 219 | Html::addCssClass($this->headerOptions, 'portlet-title'); 220 | 221 | echo Html::beginTag('div', $this->headerOptions); 222 | 223 | echo Html::beginTag('div', ['class' => 'caption']); 224 | 225 | if ($this->icon) { 226 | echo Html::tag('i', '', ['class' => $this->pushFontColor($this->icon)]); 227 | } 228 | 229 | echo Html::tag($this->tagTitle, $this->title, ['class' => $this->pushFontColor('caption-subject')]); 230 | 231 | if ($this->helper) { 232 | echo Html::tag('span', $this->helper, ['class' => 'caption-helper']); 233 | } 234 | 235 | echo Html::endTag('div'); 236 | 237 | echo Html::endTag('div'); 238 | } 239 | } 240 | 241 | /** 242 | * Renders portlet tools 243 | */ 244 | protected function renderTools() 245 | { 246 | if (!empty($this->tools)) { 247 | $tools = []; 248 | foreach ($this->tools as $tool) { 249 | $class = ''; 250 | switch ($tool) { 251 | case self::TOOL_CLOSE : 252 | $class = 'remove'; 253 | break; 254 | 255 | case self::TOOL_MINIMIZE : 256 | $class = 'collapse'; 257 | break; 258 | 259 | case self::TOOL_RELOAD : 260 | $class = 'reload'; 261 | break; 262 | } 263 | $tools[] = Html::tag('a', '', ['class' => $class, 'href' => '']); 264 | } 265 | 266 | echo Html::tag('div', implode("\n", $tools), ['class' => 'tools']); 267 | } 268 | } 269 | 270 | /** 271 | * Renders portlet actions 272 | */ 273 | protected function renderActions() 274 | { 275 | if (!empty($this->actions)) { 276 | echo Html::tag('div', implode("\n", $this->actions), ['class' => 'actions']); 277 | } 278 | } 279 | 280 | /** 281 | * Renders scroller begin 282 | * @throws InvalidConfigException 283 | */ 284 | protected function renderScrollerBegin() 285 | { 286 | if (!empty($this->scroller)) { 287 | if (!isset($this->scroller['height'])) { 288 | throw new InvalidConfigException("The 'height' option of the scroller is required."); 289 | } 290 | $options = ArrayHelper::getValue($this->scroller, 'options', []); 291 | echo Html::beginTag( 292 | 'div', ArrayHelper::merge( 293 | ['class' => 'scroller', 'data-always-visible' => '1', 'data-rail-visible' => '0'], $options, ['style' => 'height:' . $this->scroller['height'] . 'px;'] 294 | ) 295 | ); 296 | } 297 | } 298 | 299 | /** 300 | * Renders scroller end 301 | */ 302 | protected function renderScrollerEnd() 303 | { 304 | if (!empty($this->scroller)) { 305 | echo Html::endTag('div'); 306 | $footer = ArrayHelper::getValue($this->scroller, 'footer', ''); 307 | if (!empty($footer)) { 308 | echo Html::beginTag('div', ['class' => 'scroller-footer']); 309 | if (is_array($footer)) { 310 | echo Html::tag('div', Link::widget($footer), ['class' => 'pull-right']); 311 | } elseif (is_string($footer)) { 312 | echo $footer; 313 | } 314 | echo Html::endTag('div'); 315 | } 316 | } 317 | } 318 | 319 | /** 320 | * Retrieves font color 321 | */ 322 | protected function getFontColor() 323 | { 324 | if ($this->color) { 325 | return sprintf('font-%s', $this->color); 326 | } 327 | 328 | return ''; 329 | } 330 | 331 | /** 332 | * Pushes font color to given string 333 | */ 334 | protected function pushFontColor($string) 335 | { 336 | $color = $this->getFontColor(); 337 | 338 | if ($color) { 339 | return sprintf('%s %s', $string, $color); 340 | } 341 | 342 | return $string; 343 | } 344 | 345 | } 346 | -------------------------------------------------------------------------------- /widgets/Ribbon.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 1.1 17 | */ 18 | class Ribbon extends Widget { 19 | 20 | const TYPE_DEFAULT = 'ribbon-color-default'; 21 | const TYPE_PRIMARY = 'ribbon-color-primary'; 22 | const TYPE_INFO = 'ribbon-color-info'; 23 | const TYPE_SUCCESS = 'ribbon-color-success'; 24 | const TYPE_DANGER = 'ribbon-color-danger'; 25 | const TYPE_WARNING = 'ribbon-color-warning'; 26 | 27 | public $vertical = false; 28 | 29 | public $right = false; 30 | 31 | public $shadow = false; 32 | 33 | public $rounded = false; 34 | 35 | public $bordered = false; 36 | 37 | public $square_border = false; 38 | 39 | public $dashed = false; 40 | 41 | public $clipped = false; 42 | 43 | public $bookmark = false; 44 | 45 | public $color = self::TYPE_DEFAULT; 46 | 47 | public $title = ''; 48 | 49 | public $icon = ''; 50 | 51 | public $options = []; 52 | 53 | /** 54 | * Renders the widget. 55 | */ 56 | public function run() 57 | { 58 | Html::addCssClass($this->options, 'ribbon'); 59 | 60 | Html::addCssClass($this->options, $this->color); 61 | 62 | if ($this->vertical) { 63 | Html::addCssClass($this->options, ($this->right ? 'ribbon-vertical-right' : 'ribbon-vertical-left')); 64 | } else { 65 | if ($this->right) { 66 | Html::addCssClass($this->options, 'ribbon-right'); 67 | } 68 | } 69 | 70 | if ($this->shadow) { 71 | Html::addCssClass($this->options, 'ribbon-shadow'); 72 | } 73 | 74 | if ($this->rounded) { 75 | Html::addCssClass($this->options, 'ribbon-round'); 76 | } 77 | if ($this->square_border) { 78 | Html::addCssClass($this->options, 'ribbon-border'); 79 | } else { 80 | if ($this->bordered) { 81 | if ($this->vertical) { 82 | Html::addCssClass($this->options, $this->dashed ? 'ribbon-border-dash-ver' : 'ribbon-border-ver'); 83 | } else { 84 | Html::addCssClass($this->options, $this->dashed ? 'ribbon-border-dash-hor' : 'ribbon-border-hor'); 85 | } 86 | } 87 | } 88 | 89 | if ($this->clipped) { 90 | Html::addCssClass($this->options, 'ribbon-clip ribbon-sub'); 91 | } 92 | 93 | if ($this->bookmark) { 94 | Html::addCssClass($this->options, 'ribbon-bookmark'); 95 | } 96 | 97 | $content = $this->_renderSub() . $this->_renderTitle(); 98 | echo Html::tag('div', $content, $this->options); 99 | } 100 | 101 | private function _renderSub() { 102 | if ($this->clipped) { 103 | return Html::tag('div', '', ['class'=>'ribbon-sub ribbon-clip']); 104 | } 105 | if ($this->bookmark) { 106 | return Html::tag('div', '', ['class'=>'ribbon-sub ribbon-bookmark']); 107 | } 108 | } 109 | 110 | private function _renderTitle() { 111 | $html = ''; 112 | if ($this->icon) 113 | { 114 | $html .= Html::tag('i', '', ['class' => $this->icon]); 115 | $html .= ' '; 116 | } 117 | $html.= Html::tag('span', $this->title); 118 | return $html; 119 | } 120 | } -------------------------------------------------------------------------------- /widgets/Select2.php: -------------------------------------------------------------------------------- 1 | 'select', 21 | * 'data' => ['1' => 'Item 1', '2' => 'Item 2'], 22 | * 'multiple' => true, 23 | * ]); 24 | * ``` 25 | * 26 | * @see http://ivaynberg.github.io/select2/ 27 | */ 28 | class Select2 extends InputWidget 29 | { 30 | /** 31 | * @var bool indicates whether to display a dropdown select box or use it for tagging 32 | */ 33 | public $asDropdownList = true; 34 | /** 35 | * @var bool indicates whether the select2 is disabled or not. 36 | */ 37 | public $disabled = false; 38 | /** 39 | * @var array the option data items. The array keys are option values, and the array values 40 | * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). 41 | * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. 42 | * If you have a list of data models, you may convert them into the format described above using 43 | * [[\yii\helpers\ArrayHelper::map()]]. 44 | */ 45 | public $data = []; 46 | /** 47 | * @var bool indicates whether the select2 is multiple or not. 48 | */ 49 | public $multiple = false; 50 | 51 | /** 52 | * Initializes the widget. 53 | */ 54 | public function init() 55 | { 56 | parent::init(); 57 | Html::addCssClass($this->options, 'form-control'); 58 | if ($this->multiple) { 59 | $this->options['multiple'] = 'multiple'; 60 | } 61 | if ($this->disabled) { 62 | $this->options['disabled'] = true; 63 | } 64 | } 65 | 66 | /** 67 | * Executes the widget. 68 | */ 69 | public function run() 70 | { 71 | if ($this->hasModel()) { 72 | if ($this->asDropdownList) { 73 | echo Html::activeDropDownList($this->model, $this->attribute, $this->data, $this->options); 74 | } else { 75 | if (!isset($this->clientOptions['query']) && !isset($this->clientOptions['ajax']) && !isset($this->clientOptions['data'])) { 76 | throw new InvalidConfigException('Must be set at least one of the client options: query, data, ajax.'); 77 | } 78 | echo Html::activeHiddenInput($this->model, $this->attribute, $this->options); 79 | } 80 | } else { 81 | if ($this->asDropdownList) { 82 | echo Html::dropDownList($this->name, $this->value, $this->data, $this->options); 83 | } else { 84 | if (!isset($this->clientOptions['query']) && !isset($this->clientOptions['ajax']) && !isset($this->clientOptions['data'])) { 85 | throw new InvalidConfigException('Must be set at least one of the options Select2: query, data, ajax.'); 86 | } 87 | echo Html::hiddenInput($this->name, $this->value, $this->options); 88 | } 89 | } 90 | Select2Asset::register($this->view); 91 | $this->registerPlugin('select2'); 92 | } 93 | } -------------------------------------------------------------------------------- /widgets/Spinner.php: -------------------------------------------------------------------------------- 1 | $model, 19 | * 'attribute' => 'country', 20 | * 'size' => Spinner::SIZE_SMALL, 21 | * 'buttonsLocation' => Spinner::BUTTONS_LOCATION_VERTICAL, 22 | * 'clientOptions' => ['step' => 2], 23 | * 'clientEvents' => ['changed' => 'function(event, value){ console.log(value);}'], 24 | * ]); 25 | * ``` 26 | * 27 | * The following example will use the name property instead: 28 | * 29 | * ```php 30 | * echo Spinner::widget([ 31 | * 'name' => 'country', 32 | * 'clientOptions' => ['step' => 2], 33 | * ]); 34 | *``` 35 | * 36 | * @see http://exacttarget.github.io/fuelux/#spinner 37 | * @author 38 | */ 39 | class Spinner extends InputWidget 40 | { 41 | // position 42 | const BUTTONS_LOCATION_VERTICAL = 'vertical'; 43 | const BUTTONS_LOCATION_SIDES = 'sides'; 44 | // size 45 | const SIZE_XSMALL = 'xsmall'; 46 | const SIZE_SMALL = 'small'; 47 | const SIZE_MEDIUM = 'medium'; 48 | const SIZE_LARGE = 'large'; 49 | /** 50 | * @var string Spinner size 51 | */ 52 | public $size = self::SIZE_SMALL; 53 | /** 54 | * @var array the configuration array for [[Button]]. 55 | */ 56 | public $buttonsConfig = ['type' => Button::TYPE_M_BLUE]; 57 | /** 58 | * @var array the HTML attributes for the input element. 59 | */ 60 | public $inputOptions = []; 61 | /** 62 | * @var string The buttons location. 63 | * Valid values are 'vertical', 'sides' 64 | */ 65 | public $buttonsLocation = self::BUTTONS_LOCATION_VERTICAL; 66 | /** 67 | * Executes the widget. 68 | */ 69 | public function run() 70 | { 71 | Html::addCssClass($this->inputOptions, 'spinner-input form-control'); 72 | $this->buttonsConfig = array_merge(['label' => ''], $this->buttonsConfig); 73 | if ($this->hasModel()) { 74 | $input = Html::activeTextInput($this->model, $this->attribute, $this->inputOptions); 75 | } else { 76 | $input = Html::textInput($this->name, $this->value, $this->inputOptions); 77 | } 78 | if ($this->buttonsLocation == self::BUTTONS_LOCATION_VERTICAL) { 79 | $this->buttonsConfig = array_merge($this->buttonsConfig, ['size' => Button::SIZE_MINI]); 80 | } 81 | $btnUp = Button::widget( 82 | array_merge($this->buttonsConfig, [ 83 | 'icon' => 'fa fa-angle-up', 84 | 'options' => ['class' => 'spinner-up'] 85 | ]) 86 | ); 87 | $btnDown = Button::widget( 88 | array_merge($this->buttonsConfig, [ 89 | 'icon' => 'fa fa-angle-down', 90 | 'options' => ['class' => 'spinner-down'] 91 | ]) 92 | ); 93 | 94 | if ($this->buttonsLocation == self::BUTTONS_LOCATION_VERTICAL) { 95 | $spinner = $input . Html::tag('div', $btnUp . $btnDown, ['class' => 'spinner-buttons input-group-btn btn-group-vertical']); 96 | } else { 97 | $spinner = Html::tag('div', $btnUp . $input . $btnDown, ['class' => 'spinner-buttons input-group-btn']); 98 | } 99 | echo Html::tag('div' , Html::tag('div', $spinner, ['class' => 'input-group input-' . $this->size]), $this->options); 100 | SpinnerAsset::register($this->view); 101 | $this->registerPlugin('spinner'); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /widgets/StepsLine.php: -------------------------------------------------------------------------------- 1 | view); 49 | return implode("\n", [ 50 | Html::beginTag('div', ['class' => 'mt-element-step']), 51 | Html::beginTag('div', ['class' => "row {$this->cssRowClasses}"]), 52 | $this->renderItems(), 53 | Html::endTag('div'), 54 | Html::endTag('div') 55 | ]); 56 | } 57 | 58 | /** 59 | * Renders wizard items as specified on [[items]]. 60 | * @return string the rendering result. 61 | * @throws InvalidConfigException. 62 | */ 63 | public function renderItems() 64 | { 65 | $contents = []; 66 | $n = 1; 67 | $numberOfItems = count($this->items); 68 | 69 | switch ($numberOfItems){ 70 | case 3: 71 | $this->cssColClass = 'col-md-4'; 72 | break; 73 | case 4: 74 | $this->cssColClass = 'col-md-3'; 75 | break; 76 | default: 77 | throw new InvalidConfigException( 78 | "Only three and four steps are supported by this widget. Your actual item count is $numberOfItems" 79 | ); 80 | } 81 | 82 | foreach ($this->items as $key => $item) { 83 | $itemCssColClass = $this->cssColClass; 84 | 85 | if (!ArrayHelper::remove($item, 'visible', true)) { 86 | continue; 87 | } 88 | 89 | if (!is_string($key) && !array_key_exists('itemTitle', $item)) { 90 | throw new InvalidConfigException( 91 | "The 'itemTitle' option is required." 92 | ); 93 | } 94 | if (is_string($item)) { 95 | $item = ['content' => $item]; 96 | } 97 | 98 | if (!array_key_exists('itemIcon', $item)){ 99 | $item['itemIcon'] = $n; 100 | } 101 | 102 | if (!array_key_exists('itemContent', $item)){ 103 | $item['itemContent'] = ''; 104 | } 105 | 106 | if (array_key_exists('itemUrl', $item) && empty($item['itemUrl'])){ 107 | unset($item['itemUrl']); 108 | } 109 | 110 | switch ($n){ 111 | case 1: 112 | $itemCssColClass .= ' first'; 113 | break; 114 | case $numberOfItems: 115 | $itemCssColClass .= ' last'; 116 | break; 117 | default: 118 | $itemCssColClass .= ''; 119 | 120 | } 121 | 122 | if (array_key_exists('itemActive', $item)){ 123 | $itemCssColClass .= ' ' . $item['itemActive']; 124 | } 125 | 126 | if (array_key_exists('itemDone', $item)){ 127 | $itemCssColClass .= ' ' . $item['itemDone']; 128 | } 129 | 130 | $item['cssClassesCol'] = $itemCssColClass; 131 | 132 | $contents[] = $this->renderItem($item); 133 | 134 | $n++; 135 | } 136 | 137 | return implode("\n", $contents); 138 | } 139 | 140 | private function renderItem($item = []){ 141 | $lines = []; 142 | 143 | $lines[] = Html::beginTag('div', [ 144 | 'class' => "{$item['cssClassesCol']} mt-step-col" 145 | ]); 146 | 147 | $iconTag = Html::tag('div', $item['itemIcon'], ['class' => "mt-step-number {$this->cssItemIconClasses}"]); 148 | 149 | if (isset($item['itemUrl'])){ 150 | $iconTag = Html::a($iconTag, $item['itemUrl']); 151 | } 152 | 153 | $lines[] = $iconTag; 154 | $lines[] = Html::tag('div', $item['itemTitle'], ['class' => "mt-step-title {$this->cssItemTitleClasses}"]); 155 | $lines[] = Html::tag('div', $item['itemContent'], ['class' => "mt-step-content {$this->cssItemContentClasses}"]); 156 | $lines[] = Html::endTag('div'); 157 | 158 | return implode("\n", $lines); 159 | } 160 | } -------------------------------------------------------------------------------- /widgets/Tabs.php: -------------------------------------------------------------------------------- 1 | [ 22 | * [ 23 | * 'label' => 'One', 24 | * 'content' => 'Anim pariatur cliche...', 25 | * 'active' => true 26 | * ], 27 | * [ 28 | * 'label' => 'Two', 29 | * 'content' => 'Anim pariatur cliche...', 30 | * 'headerOptions' => [...], 31 | * 'options' => ['id' => 'myveryownID'], 32 | * ], 33 | * [ 34 | * 'label' => 'Dropdown', 35 | * 'items' => [ 36 | * [ 37 | * 'label' => 'DropdownA', 38 | * 'content' => 'DropdownA, Anim pariatur cliche...', 39 | * ], 40 | * [ 41 | * 'label' => 'DropdownB', 42 | * 'content' => 'DropdownB, Anim pariatur cliche...', 43 | * ], 44 | * ], 45 | * ], 46 | * ], 47 | * ]); 48 | * ``` 49 | * 50 | */ 51 | class Tabs extends \yii\bootstrap\Tabs { 52 | 53 | // Tab placements. 54 | const PLACEMENT_ABOVE = 'above'; 55 | const PLACEMENT_BELOW = 'below'; 56 | const PLACEMENT_LEFT = 'left'; 57 | const PLACEMENT_RIGHT = 'right'; 58 | // Tab type 59 | const NAV_TYPE_TABS = 'nav-tabs'; 60 | const NAV_TYPE_PILLS = 'nav-pills'; 61 | 62 | /** 63 | * @var string, specifies the Bootstrap tab styling. 64 | * Valid values 'nav-tabs', 'nav-pills' 65 | */ 66 | public $navType = self::NAV_TYPE_TABS; 67 | 68 | /** 69 | * @var string the placement of the tabs. 70 | * Valid values are 'above', 'below', 'left' and 'right'. 71 | */ 72 | public $placement = self::PLACEMENT_ABOVE; 73 | 74 | /** 75 | * @var bool Indicates whether tabs is styled for Metronic. 76 | */ 77 | public $styled = true; 78 | 79 | /** 80 | * @var bool Indicates whether tabs is justified. 81 | */ 82 | public $justified = false; 83 | 84 | /** 85 | * Initializes the widget. 86 | */ 87 | public function init() 88 | { 89 | if ($this->justified) 90 | { 91 | Html::addCssClass($this->options, 'nav-justified'); 92 | } 93 | 94 | Html::addCssClass($this->options, 'nav ' . $this->navType); 95 | parent::init(); 96 | } 97 | 98 | /** 99 | * Renders the widget. 100 | */ 101 | public function run() 102 | { 103 | $classWrap = ['tabs-' . $this->placement]; 104 | if ($this->styled) 105 | { 106 | $classWrap[] = 'tabbable-custom'; 107 | if ($this->justified) 108 | { 109 | $classWrap[] = 'nav-justified'; 110 | } 111 | } 112 | else 113 | { 114 | $classWrap[] = 'tabbable'; 115 | } 116 | echo Html::beginTag('div', ['class' => implode(' ', $classWrap)]); 117 | echo parent::run(); 118 | echo Html::endTag('div'); 119 | } 120 | 121 | /** 122 | * Renders tab items as specified on [[items]]. 123 | * @return string the rendering result. 124 | * @throws InvalidConfigException. 125 | */ 126 | protected function renderItems() 127 | { 128 | $headers = []; 129 | $panes = []; 130 | 131 | if (!$this->hasActiveTab() && !empty($this->items)) 132 | { 133 | $this->items[0]['active'] = true; 134 | } 135 | 136 | foreach ($this->items as $n => $item) 137 | { 138 | if (!isset($item['label'])) 139 | { 140 | throw new InvalidConfigException("The 'label' option is required."); 141 | } 142 | $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; 143 | $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); 144 | 145 | if (isset($item['items'])) 146 | { 147 | if ($this->styled) 148 | { 149 | throw new InvalidConfigException("The 'styled' not support dropdown items. Please, set 'styled' to false."); 150 | } 151 | $label .= ' '; 152 | Html::addCssClass($headerOptions, 'dropdown'); 153 | 154 | if ($this->renderDropdown(count($item['items']), $item['items'], $panes)) 155 | { 156 | Html::addCssClass($headerOptions, 'active'); 157 | } 158 | 159 | $header = Html::a($label, "#", ['class' => 'dropdown-toggle', 'data-toggle' => 'dropdown']) . "\n" 160 | . Dropdown::widget(['items' => $item['items'], 'clientOptions' => false]); 161 | } 162 | elseif (isset($item['content'])) 163 | { 164 | $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); 165 | $options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-tab' . $n); 166 | 167 | Html::addCssClass($options, 'tab-pane'); 168 | if (ArrayHelper::remove($item, 'active')) 169 | { 170 | Html::addCssClass($options, 'active'); 171 | Html::addCssClass($headerOptions, 'active'); 172 | } 173 | $header = Html::a($label, '#' . $options['id'], ['data-toggle' => 'tab']); 174 | $panes[] = Html::tag('div', $item['content'], $options); 175 | } 176 | else 177 | { 178 | throw new InvalidConfigException("Either the 'content' or 'items' option must be set."); 179 | } 180 | 181 | $headers[] = Html::tag('li', $header, $headerOptions); 182 | } 183 | 184 | $headers = Html::tag('ul', implode("\n", $headers), $this->options); 185 | $panes = Html::tag('div', implode("\n", $panes), ['class' => 'tab-content']); 186 | 187 | return ($this->placement == self::PLACEMENT_BELOW) ? ($panes . "\n" . $headers) : ($headers . "\n" . $panes); 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /widgets/TagInput.php: -------------------------------------------------------------------------------- 1 | 'auto', 35 | ]; 36 | 37 | /** 38 | * @inheritdoc 39 | */ 40 | public function init() 41 | { 42 | $this->pluginOptions = ArrayHelper::merge($this->pluginDefaults, $this->pluginOptions); 43 | 44 | parent::init(); 45 | } 46 | 47 | /** 48 | * Executes the widget. 49 | */ 50 | public function run() 51 | { 52 | $this->registerJs(); 53 | 54 | TagInputAsset::register($this->view); 55 | 56 | return parent::run(); 57 | } 58 | 59 | /** 60 | * Registeres JS 61 | */ 62 | protected function registerJs() 63 | { 64 | $this->view->registerJs(" 65 | !(function($){ 66 | var el = $('#{$this->options['id']}'); 67 | 68 | el.tagsInput(".Json::encode($this->pluginOptions)."); 69 | 70 | })(jQuery); 71 | ", \yii\web\View::POS_READY); 72 | } 73 | } -------------------------------------------------------------------------------- /widgets/TextInputWidget.php: -------------------------------------------------------------------------------- 1 | hasModel()) { 28 | echo Html::activeTextInput($this->model, $this->attribute, $this->options); 29 | } else { 30 | echo Html::textInput($this->name, $this->value, $this->options); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /widgets/Tree.php: -------------------------------------------------------------------------------- 1 | [ 85 | 'wholerow', 86 | ], 87 | 'core' => [ 88 | 'themes' => [ 89 | 'responsive' => false, 90 | 'icons' => false 91 | ], 92 | ], 93 | ]; 94 | 95 | /** 96 | * Inits widget 97 | */ 98 | public function init() 99 | { 100 | $this->jsTree(); 101 | } 102 | 103 | /** 104 | * Runs widget 105 | */ 106 | public function run() 107 | { 108 | $builder = \dlds\metronic\builders\TreeBuilder::instance($this->items, array( 109 | 'treeTag' => $this->listTag, 110 | 'itemTag' => $this->itemTag, 111 | 'levelAttr' => $this->levelAttr, 112 | 'contentCallback' => $this->contentCallback, 113 | 'treeHtmlOptions' => function() { 114 | return $this->getTreeOptions(); 115 | }, 116 | 'itemHtmlOptions' => function($id) { 117 | return $this->getItemOptions($id); 118 | }, 119 | 'contentHtmlOptions' => function() { 120 | return $this->getContentOptions(); 121 | }, 122 | )); 123 | 124 | echo $this->renderTree($builder->build()); 125 | } 126 | 127 | /** 128 | * Retrieves tree html options 129 | * @return array tree html options 130 | */ 131 | protected function getTreeOptions() 132 | { 133 | return array( 134 | 'class' => $this->listClass, 135 | ); 136 | } 137 | 138 | /** 139 | * Retrieves item html options 140 | * @param array $id passed item id 141 | */ 142 | protected function getItemOptions($id) 143 | { 144 | return array( 145 | 'class' => $this->itemClass, 146 | 'data-id' => $id, 147 | 'data-jstree' => json_encode([ 148 | 'selected' => $this->isItemAssigned($id), 149 | ]), 150 | ); 151 | } 152 | 153 | /** 154 | * Retrieves content html options 155 | * @return type 156 | */ 157 | protected function getContentOptions() 158 | { 159 | return array( 160 | 'class' => $this->contentClass, 161 | ); 162 | } 163 | 164 | /** 165 | * Indicates if item is currently assigned to model 166 | * @param int $id given item id 167 | */ 168 | protected function isItemAssigned($id) 169 | { 170 | if (null === $this->_assignedItems) 171 | { 172 | $this->_assignedItems = $this->pullAssignedItems(); 173 | } 174 | 175 | return in_array($id, $this->_assignedItems); 176 | } 177 | 178 | /** 179 | * Pulls assigned items from model 180 | */ 181 | protected function pullAssignedItems() 182 | { 183 | if (is_string($this->model{$this->attribute})) 184 | { 185 | return explode(',', $this->model{$this->attribute}); 186 | } 187 | 188 | return (array) $this->model{$this->attribute}; 189 | } 190 | 191 | /** 192 | * Renders output 193 | * @param string $tree 194 | */ 195 | protected function renderTree($tree) 196 | { 197 | $this->treeOptions = array_merge(['id' => $this->id], $this->treeOptions); 198 | $html = Html::beginTag('div', $this->treeOptions); 199 | 200 | $html .= $tree; 201 | 202 | $html .= Html::endTag('div'); 203 | 204 | if ($this->checkable) 205 | { 206 | $html .= $this->renderHiddenField(); 207 | } 208 | 209 | return $html; 210 | } 211 | 212 | /** 213 | * Renders hidden form field 214 | */ 215 | protected function renderHiddenField() 216 | { 217 | if ($this->hasModel()) 218 | { 219 | return Html::activeInput('hidden', $this->model, $this->attribute, ['id' => $this->getHiddenFieldId()]); 220 | } 221 | 222 | return Html::input('hidden', $this->name, $this->value, ['id' => $this->getHiddenFieldId()]); 223 | } 224 | 225 | /** 226 | * Registres JS files 227 | */ 228 | protected function jsTree() 229 | { 230 | if ($this->checkable) 231 | { 232 | $this->defaultTreeOptions = ArrayHelper::merge($this->defaultTreeOptions, [ 233 | 'plugins' => [ 234 | 'checkbox' 235 | ], 236 | 'checkbox' => [ 237 | 'keep_selected_style' => false, 238 | 'three_state' => false, 239 | 'cascade' => '' 240 | ] 241 | ]); 242 | } 243 | 244 | $treeOptions = json_encode(ArrayHelper::merge($this->defaultTreeOptions, $this->treeOptions)); 245 | 246 | $view = $this->getView(); 247 | $view->registerJs("jQuery('#{$this->id}').jstree({$treeOptions});"); 248 | $this->registerAdditionalJs(); 249 | TreeAsset::register($view); 250 | } 251 | 252 | protected function registerAdditionalJs() 253 | { 254 | $view = $this->getView(); 255 | 256 | if ($this->checkable) 257 | { 258 | $view->registerJs("jQuery('#{$this->id}').on('changed.jstree', function (e, data) { 259 | var i, j, r = []; 260 | 261 | for (i = 0, j = data.selected.length; i < j; i++) { 262 | r.push(data.instance.get_node(data.selected[i]).data.id); 263 | } 264 | 265 | jQuery('#{$this->getHiddenFieldId()}').val(r.join(',')); 266 | });"); 267 | } 268 | 269 | $view->registerJs("jQuery('#{$this->id}').on('select_node.jstree', function (e, data) { 270 | var \$this = $(this); 271 | \$this.jstree('open_node', data.node); 272 | var ParentNode = \$this.jstree('get_parent', data.node); 273 | \$this.jstree('select_node', ParentNode); 274 | });"); 275 | 276 | $view->registerJs("jQuery('#{$this->id}').on('deselect_node.jstree', function (e, data) { 277 | var \$this = $(this); 278 | \$this.jstree('open_node', data.node); 279 | var ChildrenNodes = jQuery.makeArray(\$this.jstree('get_children_dom', data.node)); 280 | \$this.jstree('deselect_node', ChildrenNodes); 281 | \$this.jstree('close_node', data.node); 282 | });"); 283 | } 284 | 285 | /** 286 | * Retrieves hidden field id 287 | */ 288 | private function getHiddenFieldId() 289 | { 290 | $formName = $this->model ? $this->model->formName() : 'jstree-form'; 291 | return strtolower(sprintf('%s-%s', $formName, $this->attribute)); 292 | } 293 | } 294 | ?> 295 | -------------------------------------------------------------------------------- /widgets/Widget.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 1.0 17 | */ 18 | class Widget extends \yii\bootstrap\Widget 19 | { 20 | /** 21 | * @var array the HTML attributes for the widget container tag. 22 | */ 23 | public $options = []; 24 | /** 25 | * @var array the options for the underlying Metronic JS plugin. 26 | * Please refer to the corresponding Metronic plugin Web page for possible options. 27 | * For example, [this page](http://yii2metronic.icron.org/javascript.html#portlet) shows 28 | * how to use the "Portlet" plugin and the supported options (e.g. "loadSuccess"). 29 | */ 30 | public $clientOptions = []; 31 | /** 32 | * @var array the event handlers for the underlying Metronic JS plugin. 33 | * Please refer to the corresponding Metronic plugin Web page for possible events. 34 | * For example, [this page](http://yii2metronic.icron.org/javascript.html#portlet) shows 35 | * how to use the "Portlet" plugin and the supported events (e.g. "close.mr.portlet"). 36 | */ 37 | public $clientEvents = []; 38 | 39 | /** 40 | * Registers a specific Bootstrap plugin and the related events 41 | * @param string $name the name of the Bootstrap plugin 42 | */ 43 | protected function registerPlugin($name) 44 | { 45 | $view = $this->getView(); 46 | $id = $this->options['id']; 47 | if ($this->clientOptions !== false) { 48 | $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); 49 | $js = "jQuery('#$id').$name($options);"; 50 | $view->registerJs($js); 51 | } 52 | if (!empty($this->clientEvents)) { 53 | $js = []; 54 | foreach ($this->clientEvents as $event => $handler) { 55 | $js[] = "jQuery('#$id').on('$event', $handler);"; 56 | } 57 | $view->registerJs(implode("\n", $js)); 58 | } 59 | } 60 | } 61 | --------------------------------------------------------------------------------