Completed
Push — master ( 26123a...ef3c8f )
by Klochok
11:26
created

IndexPage::setLayout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * HiPanel core package.
4
 *
5
 * @link      https://hipanel.com/
6
 * @package   hipanel-core
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2014-2017, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\widgets;
12
13
use hipanel\models\IndexPageUiOptions;
14
use hiqdev\higrid\representations\RepresentationCollectionInterface;
15
use Yii;
16
use yii\base\InvalidParamException;
17
use yii\base\Model;
18
use yii\base\Widget;
19
use yii\bootstrap\ButtonDropdown;
20
use yii\data\ArrayDataProvider;
21
use yii\data\DataProviderInterface;
22
use yii\helpers\Html;
23
use yii\helpers\Inflector;
24
use yii\helpers\Json;
25
use yii\helpers\Url;
26
use yii\web\View;
27
28
class IndexPage extends Widget
29
{
30
    /**
31
     * @var string
32
     */
33
    protected $_layout;
34
35
    /**
36
     * @var Model the search model
37
     */
38
    public $model;
39
40
    /**
41
     * @var IndexPageUiOptions
42
     */
43
    private $uiModel;
44
45
    /**
46
     * @var object original view context.
47
     * It is used to render sub-views with the same context, as IndexPage
48
     */
49
    public $originalContext;
50
51
    /**
52
     * @var DataProviderInterface
53
     */
54
    public $dataProvider;
55
56
    /**
57
     * @var array Hash of document blocks, that can be rendered later in the widget's views
58
     * Blocks can be set explicitly on widget initialisation, or by calling [[beginContent]] and
59
     * [[endContent]]
60
     *
61
     * @see beginContent
62
     * @see endContent
63
     */
64
    public $contents = [];
65
66
    /**
67
     * @var string the name of current content block, that is under the render
68
     * @see beginContent
69
     * @see endContent
70
     */
71
    protected $_current = null;
72
73
    /**
74
     * @var array
75
     */
76
    public $searchFormData = [];
77
78
    /**
79
     * @var array
80
     */
81
    public $searchFormOptions = [];
82
83
    /**
84
     * @var string the name of view file that contains search fields for the index page. Defaults to `_search`
85
     * @see renderSearchForm()
86
     */
87
    public $searchView = '_search';
88
89
    /** {@inheritdoc} */
90
    public function init()
91
    {
92
        parent::init();
93
        $searchFormId = Json::htmlEncode("#{$this->getBulkFormId()}");
94
        $this->originalContext = Yii::$app->view->context;
95
        $view = $this->getView();
96
        // Fix a very narrow select2 input in the search tables
97
        $view->registerCss('#content-pjax .select2-dropdown--below { min-width: 170px!important; }');
98
        $view->registerJs(<<<"JS"
99
        // Checkbox
100
        var bulkcontainer = $('.box-bulk-actions fieldset');
101
        $(document).on('ifChecked ifUnchecked', 'table input[type="checkbox"]', function(event) {
102
            if (event.type == 'ifChecked' && $('input.icheck').filter(':checked').length > 0) {
103
                bulkcontainer.prop('disabled', false);
104
            } else if ($('input.icheck').filter(':checked').length == 0) {
105
                bulkcontainer.prop('disabled', true);
106
            }
107
        });
108
        // On/Off Actions TODO: reduce scope
109
        $(document).on('click', '.box-bulk-actions a', function (event) {
110
            var link = $(this);
111
            var action = link.data('action');
112
            var form = $($searchFormId);
113
            if (action) {
114
                form.attr({'action': action, method: 'POST'}).submit();
115
            }
116
        });
117
118
        // Do not open select2 when it is clearing
119
        var comboSelector = 'div[role=grid] :input[data-combo-field], .advanced-search :input[data-combo-field]';
120
        $(document).on('select2:unselecting', comboSelector, function(e) {
121
            $(e.target).data('unselecting', true);
122
        }).on('select2:open', comboSelector, function(e) { // note the open event is important
123
            var el = $(e.target);
124
            if (el.data('unselecting')) {
125
                el.removeData('unselecting'); // you need to unset this before close
126
                el.select2('close');
127
            }
128
        });
129
JS
130
        );
131
    }
132
133
    public function getUiModel()
134
    {
135
        if ($this->uiModel === null) {
136
            $this->uiModel = $this->originalContext->indexPageUiOptionsModel;
137
        }
138
139
        return $this->uiModel;
140
    }
141
142
    /**
143
     * Begins output buffer capture to save data in [[contents]] with the $name key.
144
     * Must not be called nested. See [[endContent]] for capture terminating.
145
     * @param string $name
146
     */
147
    public function beginContent($name)
148
    {
149
        if ($this->_current) {
150
            throw new InvalidParamException('Output buffer capture is already running for ' . $this->_current);
151
        }
152
        $this->_current = $name;
153
        ob_start();
154
        ob_implicit_flush(false);
155
    }
156
157
    /**
158
     * Terminates output buffer capture started by [[beginContent()]].
159
     * @see beginContent
160
     */
161
    public function endContent()
162
    {
163
        if (!$this->_current) {
164
            throw new InvalidParamException('Outout buffer capture is not running. Call beginContent() first');
165
        }
166
        $this->contents[$this->_current] = ob_get_contents();
167
        ob_end_clean();
168
        $this->_current = null;
169
    }
170
171
    /**
172
     * Returns content saved in [[content]] by $name.
173
     * @param string $name
174
     * @return string
175
     */
176
    public function renderContent($name)
177
    {
178
        return $this->contents[$name];
179
    }
180
181
    public function run()
182
    {
183
        $layout = $this->getLayout();
184
        if ($layout === 'horizontal') {
185
            $this->horizontalClientScriptInit();
186
        }
187
188
        return $this->render($layout);
189
    }
190
191
    private function horizontalClientScriptInit()
192
    {
193
        $view = $this->getView();
194
        $view->registerCss('
195
            .affix {
196
                top: 5px;
197
            }
198
            .affix-bottom {
199
                position: fixed!important;
200
            }
201
            @media (min-width: 768px) {
202
                .affix {
203
                    position: fixed;
204
                }
205
            }
206
            @media (max-width: 768px) {
207
                .affix {
208
                    position: static;
209
                }
210
            }
211
            .advanced-search[min-width~="150px"] form > div {
212
                width: 100%;
213
            }
214
            #scrollspy * {
215
              /* Свойства изменение которых необходимо отслеживать */
216
              transition-property: all;
217
218
              /* Устанавливаем "незаметную для глаза" длительность перехода */
219
              transition-duration: 1ms;
220
            }
221
        ');
222
        $view->registerJs("
223
            function affixInit() {
224
                $('#scrollspy').affix({
225
                    offset: {
226
                        top: ($('header.main-header').outerHeight(true) + $('section.content-header').outerHeight(true)) + 15,
227
                        bottom: ($('footer').outerHeight(true)) + 15
228
                    }
229
                });
230
            }
231
            $(document).on('pjax:end', function() {
232
                $('.advanced-search form > div').css({'width': '100%'});
233
                
234
                // Fix left search block position
235
                $(window).trigger('scroll');
236
            });
237
            if ($(window).height() > $('#scrollspy').outerHeight(true) && $(window).width() > 991) {
238
                if ( $('#scrollspy').outerHeight(true) < $('.horizontal-view .col-md-9 > .box').outerHeight(true) ) {
239
                    var fixAffixWidth = function() {
240
                        $('#scrollspy').each(function() {
241
                            $(this).width( $(this).parent().width() );
242
                        });
243
                    }
244
                    fixAffixWidth();
245
                    $(window).resize(fixAffixWidth);
246
                    affixInit();
247
                    $('a.sidebar-toggle').click(function() {
248
                        setTimeout(function(){
249
                            fixAffixWidth();
250
                        }, 500);
251
                    });
252
                }
253
            }
254
        ", View::POS_LOAD);
255
    }
256
257
    public function detectLayout()
258
    {
259
        return $this->getUiModel()->orientation;
260
    }
261
262
    /**
263
     * @param array $data
264
     * @void
265
     */
266
    public function setSearchFormData($data = [])
267
    {
268
        $this->searchFormData = $data;
269
    }
270
271
    /**
272
     * @param array $options
273
     * @void
274
     */
275
    public function setSearchFormOptions($options = [])
276
    {
277
        $this->searchFormOptions = $options;
278
    }
279
280
    public function renderSearchForm($advancedSearchOptions = [])
281
    {
282
        $advancedSearchOptions = array_merge($advancedSearchOptions, $this->searchFormOptions);
283
        ob_start();
284
        ob_implicit_flush(false);
285
        try {
286
            $search = $this->beginSearchForm($advancedSearchOptions);
287
            echo Yii::$app->view->render($this->searchView, array_merge(compact('search'), $this->searchFormData), $this->originalContext);
288
            $search->end();
289
        } catch (\Exception $e) {
290
            ob_end_clean();
291
            throw $e;
292
        }
293
294
        return ob_get_clean();
295
    }
296
297
    public function beginSearchForm($options = [])
298
    {
299
        return AdvancedSearch::begin(array_merge(['model' => $this->model], $options));
300
    }
301
302
    public function renderSearchButton()
303
    {
304
        return AdvancedSearch::renderButton() . "\n";
305
    }
306
307
    public function renderLayoutSwitcher()
308
    {
309
        return IndexLayoutSwitcher::widget(['uiModel' => $this->getUiModel()]);
310
    }
311
312
    public function renderPerPage()
313
    {
314
        $items = [];
315
        foreach ([25, 50, 100, 200, 500] as $pageSize) {
316
            $items[] = ['label' => $pageSize, 'url' => Url::current(['per_page' => $pageSize])];
317
        }
318
319
        return ButtonDropdown::widget([
320
            'label' => Yii::t('hipanel', 'Per page') . ': ' . $this->getUiModel()->per_page,
321
            'options' => ['class' => 'btn-default btn-sm'],
322
            'dropdown' => [
323
                'items' => $items,
324
            ],
325
        ]);
326
    }
327
328
    /**
329
     * Renders button to choose representation.
330
     * Returns empty string when nothing to choose (less then 2 representations available).
331
     *
332
     * @param RepresentationCollectionInterface $collection
333
     * @return string rendered HTML
334
     */
335
    public function renderRepresentations($collection)
336
    {
337
        $current = $this->getUiModel()->representation;
338
339
        $representations = $collection->getAll();
340
        if (count($representations) < 2) {
341
            return '';
342
        }
343
344
        $items = [];
345
        foreach ($representations as $name => $representation) {
346
            $items[] = [
347
                'label' => $representation->getLabel(),
348
                'url' => Url::current(['representation' => $name]),
349
            ];
350
        }
351
352
        return ButtonDropdown::widget([
353
            'label' => Yii::t('hipanel:synt', 'View') . ': ' . $collection->getByName($current)->getLabel(),
354
            'options' => ['class' => 'btn-default btn-sm'],
355
            'dropdown' => [
356
                'items' => $items,
357
            ],
358
        ]);
359
    }
360
361
    public function renderSorter(array $options)
362
    {
363
        return LinkSorter::widget(array_merge([
364
            'show' => true,
365
            'uiModel' => $this->getUiModel(),
366
            'dataProvider' => $this->dataProvider,
367
            'sort' => $this->dataProvider->getSort(),
368
            'buttonClass' => 'btn btn-default dropdown-toggle btn-sm',
369
        ], $options));
370
    }
371
372
    public function renderExport($representationCollection)
373
    {
374
        return IndexExport::widget(compact('representationCollection'));
375
    }
376
377
    public function getViewPath()
378
    {
379
        return parent::getViewPath() . DIRECTORY_SEPARATOR . (new \ReflectionClass($this))->getShortName();
380
    }
381
382
    public function getBulkFormId()
383
    {
384
        return 'bulk-' . Inflector::camel2id($this->model->formName());
385
    }
386
387
    public function beginBulkForm($action = '')
388
    {
389
        echo Html::beginForm($action, 'POST', ['id' => $this->getBulkFormId()]);
390
    }
391
392
    public function endBulkForm()
393
    {
394
        echo Html::endForm();
395
    }
396
397
    public function renderBulkButton($text, $action, $color = 'default')
398
    {
399
        return Html::submitButton($text, [
400
            'class' => "btn btn-$color btn-sm",
401
            'form' => $this->getBulkFormId(),
402
            'formmethod' => 'POST',
403
            'formaction' => Url::toRoute($action),
404
        ]);
405
    }
406
407
    /**
408
     * @return string
409
     */
410
    public function getLayout()
411
    {
412
        if ($this->_layout === null) {
413
            $this->_layout = $this->detectLayout();
414
        }
415
416
        return $this->_layout;
417
    }
418
419
    /**
420
     * @param string $layout
421
     */
422
    public function setLayout($layout)
423
    {
424
        $this->_layout = $layout;
425
    }
426
}
427