├── .gitignore ├── LICENSE ├── README.md ├── Select2Action.php ├── Select2Asset.php ├── Select2BootstrapAsset.php ├── Select2MaximizeAsset.php ├── Select2Widget.php ├── assets ├── maximize-select2-height.js └── maximize-select2-height.min.js └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/ 2 | /.buildpath 3 | /.project 4 | /.idea/ 5 | /composer.lock 6 | /vendor/ 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Andrey Borodulin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Select2 widget for Yii2 framework 2 | ================= 3 | 4 | ## Description 5 | 6 | Select2 gives you a customizable select box with support for searching, tagging, remote data sets, infinite scrolling, and many other highly used options. 7 | For more information please visit [Select2](https://select2.github.io/) 8 | 9 | ## Installation 10 | 11 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 12 | 13 | To install, either run 14 | 15 | ``` 16 | $ php composer.phar require conquer/select2 "*" 17 | ``` 18 | or add 19 | 20 | ``` 21 | "conquer/select2": "*" 22 | ``` 23 | 24 | to the ```require``` section of your `composer.json` file. 25 | 26 | ## Usage 27 | 28 | Basic usage: 29 | 30 | ```php 31 | // Form edit view 32 | use conquer\select2\Select2Widget; 33 | use yii\helpers\ArrayHelper; 34 | 35 | $form->field($model, 'attribute')->widget( 36 | Select2Widget::className(), 37 | [ 38 | 'items'=>ArrayHelper::map(Catalog::find()->all(), 'id', 'name') 39 | ] 40 | ); 41 | ``` 42 | 43 | Ajax: 44 | 45 | ```php 46 | 47 | use conquer\select2\Select2Action; 48 | ... 49 | 50 | class SiteController extends Controller 51 | { 52 | public function actions() 53 | { 54 | return [ 55 | 'ajax' => [ 56 | 'class' => Select2Action::className(), 57 | 'dataCallback' => [$this, 'dataCallback'], 58 | ], 59 | ]; 60 | } 61 | /** 62 | * 63 | * @param string $q 64 | * @return array 65 | */ 66 | public function dataCallback($q) 67 | { 68 | $query = new ActiveQuery(Catalog::className()); 69 | return [ 70 | 'results' => $query->select([ 71 | 'catalog_id as id', 72 | 'catalog_name as text', 73 | ]) 74 | ->filterWhere(['like', 'catalog_name', $q]) 75 | ->asArray() 76 | ->limit(20) 77 | ->all(), 78 | ]; 79 | } 80 | } 81 | 82 | // Form edit view: 83 | 84 | $form->field($model, 'attribute')->widget( 85 | Select2Widget::className(), 86 | [ 87 | 'ajax' => ['site/ajax'] 88 | ] 89 | ); 90 | ``` 91 | 92 | Jquery Events: 93 | 94 | Array the Select2 JQuery events. You must define events in event-name => event-function format. All events will be stacked in the sequence. Refer the [plugin options documentation ](https://select2.github.io/options.html) for details. 95 | 96 | For example: 97 | 98 | ```php 99 | 100 | $form->field($model, 'attribute')->widget( 101 | Select2Widget::className(), 102 | [ 103 | 'events' => [ 104 | 'select2:open' => "function() { log('open'); }", 105 | ] 106 | ] 107 | ); 108 | 109 | ``` 110 | 111 | Initialization of multiple selection in case of using ajax and custom templates. 112 | 113 | ```php 114 | field($model, 'multipleItems')->widget(Select2Widget::className(), [ 115 | 'options' => [ 116 | 'placeholder' => 'Select items ...', 117 | ], 118 | 'ajax' => Url::to(['items/search']), 119 | 'multiple' => true, 120 | 'items' => ArrayHelper::map($model->multipleItems, 'id', 'text'), 121 | // Initial data the same, as returned results from Ajax request items/search 122 | 'data' => $model->multipleItems, 123 | 'settings' => [ 124 | 'ajax' => ['delay' => 250], 125 | 'minimumInputLength' => 1, 126 | 'minimumResultsForSearch' => -1, 127 | /** 128 | * Handlebars here is used as example of using template engine 129 | * If you will not provide initial data, 130 | * custom templates will not access additional info of items 131 | */ 132 | 'templateResult' => 'js:Handlebars.compile($("#template-result").html())', 133 | 'templateSelection' => 'js:Handlebars.compile($("#template-selection").html())', 134 | 'escapeMarkup' => 'js:function(markup){ return markup; }', 135 | ], 136 | ]) ?> 137 | ``` 138 | 139 | ## License 140 | 141 | **conquer/select2** is released under the MIT License. See the bundled `LICENSE` for details. 142 | -------------------------------------------------------------------------------- /Select2Action.php: -------------------------------------------------------------------------------- 1 | [['id'=>1,'text'=>'First Element'], ['id'=>2,'text'=>'Second Element']]]; } 30 | */ 31 | public $dataCallback; 32 | 33 | /** 34 | * @inheritdoc 35 | */ 36 | public function init() 37 | { 38 | if (!is_callable($this->dataCallback)) { 39 | throw new InvalidConfigException('"' . get_class($this) . '::dataCallback" should be a valid callback.'); 40 | } 41 | 42 | \Yii::$app->response->format = Response::FORMAT_JSON; 43 | $this->controller->enableCsrfValidation = false; 44 | } 45 | 46 | /** 47 | * @return array|mixed 48 | */ 49 | public function run() 50 | { 51 | $q = \Yii::$app->request->get($this->paramName); 52 | 53 | $data = call_user_func($this->dataCallback, $q); 54 | 55 | if (is_array($data) && (!isset($data['results']))) { 56 | $data = ['results' => $data]; 57 | } 58 | 59 | return $data; 60 | } 61 | } -------------------------------------------------------------------------------- /Select2Asset.php: -------------------------------------------------------------------------------- 1 | 1, 'text'=>'enhancement'], ['id'=>2, 'text'=>'bug']] 41 | * @var array 42 | */ 43 | public $data; 44 | 45 | /** 46 | * You can use Select2Action to provide AJAX data 47 | * @see \yii\helpers\BaseUrl::to() 48 | * @var array|string 49 | */ 50 | public $ajax; 51 | 52 | /** 53 | * @see \yii\helpers\BaseArrayHelper::map() 54 | * @var array 55 | */ 56 | public $items = []; 57 | 58 | /** 59 | * A placeholder value can be defined and will be displayed until a selection is made 60 | * @var string 61 | */ 62 | public $placeholder; 63 | 64 | /** 65 | * Multiple select boxes 66 | * @var boolean 67 | */ 68 | public $multiple; 69 | 70 | /** 71 | * Tagging support 72 | * @var boolean 73 | */ 74 | public $tags; 75 | 76 | /** 77 | * @link https://select2.github.io/options.html 78 | * @var array 79 | */ 80 | public $settings = []; 81 | 82 | /** 83 | * If value is integer, then it passed as "cushion" parameter 84 | * @link https://github.com/panorama-ed/maximize-select2-height 85 | * @var mixed 86 | */ 87 | public $maximize = false; 88 | 89 | /** 90 | * @var string[] the JavaScript event handlers. 91 | */ 92 | public $events = []; 93 | 94 | /** 95 | * @inheritdoc 96 | */ 97 | public function init() 98 | { 99 | parent::init(); 100 | 101 | if ($this->tags) { 102 | $this->options['data-tags'] = 'true'; 103 | $this->options['multiple'] = true; 104 | } 105 | if ($this->language) { 106 | $this->options['data-language'] = $this->language; 107 | } 108 | if (!is_null($this->ajax)) { 109 | $this->options['data-ajax--url'] = Url::to($this->ajax); 110 | $this->options['data-ajax--cache'] = 'true'; 111 | } 112 | if ($this->placeholder) { 113 | $this->options['data-placeholder'] = $this->placeholder; 114 | } 115 | if ($this->multiple) { 116 | $this->options['data-multiple'] = 'true'; 117 | $this->options['multiple'] = true; 118 | } 119 | if (!empty($this->data)) { 120 | $this->options['data-data'] = Json::encode($this->data); 121 | } 122 | if (!isset($this->options['class'])) { 123 | $this->options['class'] = 'form-control'; 124 | } 125 | if ($this->bootstrap) { 126 | $this->options['data-theme'] = 'bootstrap'; 127 | } 128 | if ($this->multiple || !empty($this->settings['multiple'])) { 129 | if ($this->hasModel()) { 130 | $name = isset($this->options['name']) ? $this->options['name'] : Html::getInputName($this->model, $this->attribute); 131 | } else { 132 | $name = $this->name; 133 | } 134 | if (substr($name, -2) != '[]') { 135 | $this->options['name'] = $this->name = $name . '[]'; 136 | } 137 | } 138 | } 139 | 140 | /** 141 | * @inheritdoc 142 | */ 143 | public function run() 144 | { 145 | if ($this->hasModel()) { 146 | echo Html::activeDropDownList($this->model, $this->attribute, $this->items, $this->options); 147 | } else { 148 | echo Html::dropDownList($this->name, $this->value, $this->items, $this->options); 149 | } 150 | $this->registerAssets(); 151 | } 152 | 153 | /** 154 | * Registers Assets 155 | */ 156 | public function registerAssets() 157 | { 158 | $view = $this->getView(); 159 | /** @var yii\web\AssetBundle $bandle */ 160 | $bandle = Select2Asset::register($view); 161 | if ($this->language !== false) { 162 | $langs[0] = $this->language ? $this->language : Yii::$app->language; 163 | if (($pos = strpos($langs[0], '-')) > 0) { 164 | // If "en-us" is not found, try to use "en". 165 | $langs[1] = substr($langs[0], 0, $pos); 166 | } 167 | foreach ($langs as $lang) { 168 | $langFile = "/js/i18n/{$lang}.js"; 169 | if (file_exists($bandle->sourcePath . $langFile)) { 170 | $view->registerJsFile($bandle->baseUrl . $langFile, ['depends' => Select2Asset::className()]); 171 | break; 172 | } 173 | } 174 | } 175 | if ($this->bootstrap) { 176 | Select2BootstrapAsset::register($view); 177 | } 178 | $settings = Json::encode($this->settings); 179 | $js = "jQuery('#{$this->options['id']}').select2($settings)"; 180 | if ($this->maximize) { 181 | Select2MaximizeAsset::register($view); 182 | if (is_integer($this->maximize)) { 183 | $this->maximize = "{cushion: $this->maximize}"; 184 | } elseif (is_array($this->maximize)) { 185 | $this->maximize = Json::encode($this->maximize); 186 | } else { 187 | $this->maximize = '{}'; 188 | } 189 | $js .= ".maximizeSelect2Height($this->maximize)"; 190 | } 191 | foreach ($this->events as $event => $handler) { 192 | $js .= '.on("' . $event . '", ' . new JsExpression($handler) . ')'; 193 | } 194 | $view->registerJs("$js;"); 195 | } 196 | } -------------------------------------------------------------------------------- /assets/maximize-select2-height.js: -------------------------------------------------------------------------------- 1 | // maximize-select2-height v1.0.2 2 | // (c) Panorama Education 2015 3 | // MIT License 4 | 5 | // This jQuery/Select2 plugin expands a Select2 dropdown to take up as much 6 | // height as possible given its position on the page and the current viewport 7 | // size. The plugin correctly handles: 8 | // - Dynamic window resizing. 9 | // - The effects of scroll bars on the viewport. 10 | // - Select2 rendering dropdowns both upwards and downwards. 11 | 12 | // NOTE: The original ) 14 | 15 | (function ($) { 16 | "use strict"; 17 | 18 | // We can find these elements now, since the properties we check on them are 19 | // all via methods that are recalculated each time. 20 | var $window = $(window); 21 | var $document = $(document); 22 | 23 | // @param {Object} options The options object passed in when this plugin is 24 | // initialized 25 | // @param {Boolean} dropdownDownwards True iff the dropdown is rendered 26 | // downwards (Select2 sometimes renders the options upwards to better fit on 27 | // a page) 28 | // @return {Object} The options passed in, combined with defaults. Keys are: 29 | // - cushion: The number of pixels between the edge of the dropdown and the 30 | // edge of the viewable window. [Default: 10, except when a 31 | // horizontal scroll bar would interfere, in which case it's 30.] 32 | // NOTE: If a value is passed in, no adjustments for possible 33 | // scroll bars are made. 34 | var settings = function (options, dropdownDownwards) { 35 | return $.extend({ 36 | cushion: ( 37 | dropdownDownwards && $document.width() > $window.width() 38 | ) ? 30 : 10 39 | }, options); 40 | }; 41 | 42 | // @param {String} id The DOM element ID for the original