forked from kartik-v/yii2-detail-view
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDetailView.php
executable file
·1377 lines (1289 loc) · 52 KB
/
DetailView.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* @package yii2-detail-view
* @author Kartik Visweswaran <[email protected]>
* @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2017
* @version 1.7.7
*/
namespace kartik\detail;
use Closure;
use kartik\base\Config;
use kartik\base\TranslationTrait;
use kartik\base\WidgetTrait;
use kartik\dialog\Dialog;
use kartik\helpers\Html;
use Yii;
use yii\base\Arrayable;
use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\bootstrap\Alert;
use yii\helpers\ArrayHelper;
use yii\helpers\Inflector;
use yii\web\View;
use yii\widgets\ActiveForm;
use yii\widgets\DetailView as YiiDetailView;
/**
* DetailView displays the detail of a single data [[model]]. This widget enhances the [[YiiDetailView]] widget with
* ability to edit detail view data, configure multi columnar layouts, merged section headers, and various other
* bootstrap styling enhancements.
*
* DetailView is best used for displaying a model in a regular format (e.g. each model attribute is displayed as a
* row in a table or one can define multiple columns by defining child attributes in each attribute configuration.)
* The model can be either an instance of [[Model]] or an associative array.
*
* DetailView uses the [[attributes]] property to determines which model attributes should be displayed and how they
* should be formatted.
*
* A typical usage of DetailView is as follows:
*
* ```php
* echo DetailView::widget([
* 'model' => $model,
* 'attributes' => [
* 'title', // title attribute (in plain text)
* 'description:html', // description attribute in HTML
* [ // the owner name of the model
* 'label' => 'Owner',
* 'value' => $model->owner->name,
* ],
* 'created_at:datetime', // creation date formatted as datetime
* ],
* ]);
* ```
*
* @author Kartik Visweswaran <[email protected]>
* @since 1.0
*/
class DetailView extends YiiDetailView
{
use WidgetTrait;
use TranslationTrait;
/**
* View mode for the detail view
*/
const MODE_VIEW = 'view';
/**
* Edit mode for the detail view
*/
const MODE_EDIT = 'edit';
/**
* The **default** bootstrap contextual color type (applicable only for panel contextual style)
*/
const TYPE_DEFAULT = 'default';
/**
* The **primary** bootstrap contextual color type
*/
const TYPE_PRIMARY = 'primary';
/**
* The **information** bootstrap contextual color type
*/
const TYPE_INFO = 'info';
/**
* The **danger** bootstrap contextual color type
*/
const TYPE_DANGER = 'danger';
/**
* The **warning** bootstrap contextual color type
*/
const TYPE_WARNING = 'warning';
/**
* The **success** bootstrap contextual color type
*/
const TYPE_SUCCESS = 'success';
/**
* The **active** bootstrap contextual color type (applicable only for table row contextual style)
*/
const TYPE_ACTIVE = 'active';
/**
* Horizontal **right** alignment for grid cells
*/
const ALIGN_RIGHT = 'right';
/**
* Horizontal **center** alignment for grid cells
*/
const ALIGN_CENTER = 'center';
/**
* Horizontal **left** alignment for grid cells
*/
const ALIGN_LEFT = 'left';
/**
* Vertical **top** alignment for grid cells
*/
const ALIGN_TOP = 'top';
/**
* Vertical **middle** alignment for grid cells
*/
const ALIGN_MIDDLE = 'middle';
/**
* Vertical **bottom** alignment for grid cells
*/
const ALIGN_BOTTOM = 'bottom';
/**
* Static input (styled using bootstrap style)
*/
const INPUT_STATIC = 'staticInput';
/**
* Hidden input.
*/
const INPUT_HIDDEN = 'hiddenInput';
/**
* Hidden static input
*/
const INPUT_HIDDEN_STATIC = 'hiddenStaticInput';
/**
* Text input
*/
const INPUT_TEXT = 'textInput';
/**
* Text area
*/
const INPUT_TEXTAREA = 'textarea';
/**
* Password input
*/
const INPUT_PASSWORD = 'passwordInput';
/**
* Dropdown list allowing single select
*/
const INPUT_DROPDOWN_LIST = 'dropDownList';
/**
* List box allowing multiple select
*/
const INPUT_LIST_BOX = 'listBox';
/**
* Checkbox input
*/
const INPUT_CHECKBOX = 'checkbox';
/**
* Radio input
*/
const INPUT_RADIO = 'radio';
/**
* Checkbox inputs as a list allowing multiple selection
*/
const INPUT_CHECKBOX_LIST = 'checkboxList';
/**
* Radio inputs as a list
*/
const INPUT_RADIO_LIST = 'radioList';
/**
* Bootstrap styled checkbox button group
*/
const INPUT_CHECKBOX_BUTTON_GROUP = 'checkboxButtonGroup';
/**
* Bootstrap styled radio button group
*/
const INPUT_RADIO_BUTTON_GROUP = 'radioButtonGroup';
/**
* Krajee styled multiselect input that allows formatted checkbox list and radio list
*/
const INPUT_MULTISELECT = 'multiselect';
/**
* File input
*/
const INPUT_FILE = 'fileInput';
/**
* Other HTML5 input (e.g. color, range, email etc.)
*/
const INPUT_HTML5 = 'input';
/**
* Input widget
*/
const INPUT_WIDGET = 'widget';
/**
* Krajee dependent dropdown input widget [[\kartik\depdrop\DepDrop]]
*/
const INPUT_DEPDROP = '\kartik\depdrop\DepDrop';
/**
* Krajee select2 input widget [[\kartik\select2\Select2]]
*/
const INPUT_SELECT2 = '\kartik\select2\Select2';
/**
* Krajee typeahead input widget [[\kartik\typeahead\Typeahead]]
*/
const INPUT_TYPEAHEAD = '\kartik\typeahead\Typeahead';
/**
* Krajee switch input widget [[\kartik\switchinput\SwitchInput]]
*/
const INPUT_SWITCH = '\kartik\switchinput\SwitchInput';
/**
* Krajee touch spin input widget [[\kartik\touchspin\TouchSpin]]
*/
const INPUT_SPIN = '\kartik\touchspin\TouchSpin';
/**
* Krajee star rating input widget [[\kartik\rating\StarRating]]
*/
const INPUT_RATING = '\kartik\rating\StarRating';
/**
* Krajee range input widget [[\kartik\range\RangeInput]]
*/
const INPUT_RANGE = '\kartik\range\RangeInput';
/**
* Krajee color input widget [[\kartik\color\ColorInput]]
*/
const INPUT_COLOR = '\kartik\color\ColorInput';
/**
* Krajee file input widget [[\kartik\file\FileInput]]
*/
const INPUT_FILEINPUT = '\kartik\file\FileInput';
/**
* Krajee date picker input widget [[\kartik\date\DatePicker]]
*/
const INPUT_DATE = '\kartik\date\DatePicker';
/**
* Krajee Time picker input widget [[\kartik\time\TimePicker]]
*/
const INPUT_TIME = '\kartik\time\TimePicker';
/**
* Krajee date time Picker input widget [[\kartik\datetime\DateTimePicker]]
*/
const INPUT_DATETIME = '\kartik\datetime\DateTimePicker';
/**
* Krajee date range picker input widget [[\kartik\daterange\DateRangePicker]]
*/
const INPUT_DATE_RANGE = '\kartik\daterange\DateRangePicker';
/**
* Krajee sortable input widget [[\kartik\sortinput\SortableInput]]
*/
const INPUT_SORTABLE = '\kartik\sortinput\SortableInput';
/**
* Krajee slider input widget [[\kartik\slider\Slider]]
*/
const INPUT_SLIDER = '\kartik\slider\Slider';
/**
* Krajee mask money input widget [[\kartik\money\MaskMoney]]
*/
const INPUT_MONEY = '\kartik\money\MaskMoney';
/**
* Krajee checkbox extended input widget [[\kartik\checkbox\CheckboxX]]
*/
const INPUT_CHECKBOX_X = '\kartik\checkbox\CheckboxX';
// inputs list
protected static $_inputsList = [
self::INPUT_HIDDEN => 'hiddenInput',
self::INPUT_TEXT => 'textInput',
self::INPUT_PASSWORD => 'passwordInput',
self::INPUT_TEXTAREA => 'textarea',
self::INPUT_CHECKBOX => 'checkbox',
self::INPUT_RADIO => 'radio',
self::INPUT_LIST_BOX => 'listBox',
self::INPUT_DROPDOWN_LIST => 'dropDownList',
self::INPUT_CHECKBOX_LIST => 'checkboxList',
self::INPUT_RADIO_LIST => 'radioList',
self::INPUT_HTML5 => 'input',
self::INPUT_FILE => 'fileInput',
self::INPUT_WIDGET => 'widget',
self::INPUT_CHECKBOX_BUTTON_GROUP => 'checkboxButtonGroup',
self::INPUT_RADIO_BUTTON_GROUP => 'radioButtonGroup',
];
// dropdown inputs
protected static $_dropDownInputs = [
self::INPUT_LIST_BOX => 'listBox',
self::INPUT_DROPDOWN_LIST => 'dropDownList',
self::INPUT_CHECKBOX_LIST => 'checkboxList',
self::INPUT_RADIO_LIST => 'radioList',
self::INPUT_CHECKBOX_BUTTON_GROUP => 'checkboxButtonGroup',
self::INPUT_RADIO_BUTTON_GROUP => 'radioButtonGroup',
];
/**
* @var string the mode for the Detail View when its initialized
*/
public $mode = self::MODE_VIEW;
/**
* @var integer the fade animation delay in microseconds when toggling between the view and edit modes.
*/
public $fadeDelay = 800;
/**
* @var string the horizontal alignment for the label column
*/
public $hAlign = self::ALIGN_RIGHT;
/**
* @var string the vertical alignment for the label column
*/
public $vAlign = self::ALIGN_MIDDLE;
/**
* @var array the HTML attributes for each attribute row
*/
public $rowOptions = [];
/**
* @var array the HTML attributes for the label column
*/
public $labelColOptions = ['style' => 'width: 20%'];
/**
* @var array the HTML attributes for the value column
*/
public $valueColOptions = [];
/**
* @var boolean whether to hide all alerts. Defaults to `false`.
*/
public $hideAlerts = false;
/**
* @var bool whether to show form error summery as an error alert. Defaults to `false`.
*/
public $showErrorSummary = false;
/**
* @var boolean whether to show values as not set if empty string
*/
public $notSetIfEmpty = false;
/**
* @var array the HTML attributes for the alert block container which will display any alert messages received on
* update or delete of record. This will not be displayed if there are no alert messages.
*/
public $alertContainerOptions = [];
/**
* @var array the widget settings for each bootstrap alert displayed in the alert container block. The CSS class in
* `options` within this property will be auto derived and appended.
* - For `update` error messages will be displayed if you have set messages using Yii::$app->session->setFlash. The
* CSS class for the error block will be auto-derived based on flash message type using `alertMessageSettings`.
* - For `delete` this will be displayed based on the ajax response. The ajax response should be an object that
* contain the following settings:
* - `success`: _boolean_, whether the ajax delete is successful.
* - `messages`: _array_|_object_,the list of messages to display as key value pairs. The key must be one of the
* message keys in the `alertMessageSettings`, and the value must be the message content to be displayed.
*/
public $alertWidgetOptions = [];
/**
* @var array the flash message settings which will be set as $key => $value, where
* - `$key`: flash message key e.g. `error`, `success`.
* - `$value`: CSS class for the flash message e.g. `alert alert-danger`, `alert alert-success`. This defaults to
* the following setting:
* ```php
* [
* 'kv-detail-error' => 'alert alert-danger',
* 'kv-detail-success' => 'alert alert-success',
* 'kv-detail-info' => 'alert alert-info',
* 'kv-detail-warning' => 'alert alert-warning'
* ]
* ```
*/
public $alertMessageSettings = [];
/**
* @var array the HTML attributes for the detail view table
*/
public $options = [];
/**
* @var boolean whether the grid view will have Bootstrap table styling.
*/
public $bootstrap = true;
/**
* @var boolean whether the grid table will have a `bordered` style. Applicable only if `bootstrap` is `true`.
*/
public $bordered = true;
/**
* @var boolean whether the grid table will have a `striped` style. Applicable only if `bootstrap` is `true`.
*/
public $striped = true;
/**
* @var boolean whether the grid table will have a `condensed` style. Applicable only if `bootstrap` is `true`.
*/
public $condensed = false;
/**
* @var boolean whether the grid table will have a `responsive` style. Applicable only if `bootstrap` is `true`.
*/
public $responsive = true;
/**
* @var boolean whether the grid table will highlight row on `hover`. Applicable only if `bootstrap` is `true`.
*/
public $hover = false;
/**
* @var boolean whether to enable edit mode for the detail view.
*/
public $enableEditMode = true;
/**
* @var boolean whether to hide rows in view mode if value is null or empty.
*/
public $hideIfEmpty = false;
/**
* @var boolean whether to display bootstrap style tooltips for titles on hover of buttons.
*/
public $tooltips = true;
/**
* @var array configuration settings for the Krajee dialog widget that will be used to render alerts and
* confirmation dialog prompts.
*
* @see http://demos.krajee.com/dialog
*/
public $krajeeDialogSettings = [];
/**
* @var array a list of attributes to be displayed in the detail view. Each array element represents the
* specification for displaying one particular attribute.
*
* An attribute can be specified as a string in the format of "attribute", "attribute:format" or
* "attribute:format:label", where "attribute" refers to the attribute name, and "format" represents the format
* of the attribute. The "format" is passed to the [[Formatter::format()]] method to format an attribute value
* into a displayable text. Please refer to [[Formatter]] for the supported types. Both "format" and "label"
* are optional. They will take default values if absent.
*
* An attribute can also be specified in terms of an array with the following elements.
*
* - attribute: string|Closure, the attribute name. This is required if either "label" or "value" is not specified.
* - label: string|Closure, the label associated with the attribute. If this is not specified, it will be generated
* from the attribute name.
* - value: mixed|Closure, the value to be displayed. If this is not specified, it will be retrieved from [[model]]
* using the attribute name by calling [[ArrayHelper::getValue()]]. Note that this value will be formatted into
* a displayable text according to the "format" option.
* - format: mixed|Closure, the type of the value that determines how the value would be formatted into a
* displayable text. Please refer to [[Formatter]] for supported types.
* - visible: boolean|Closure, whether the attribute is visible. If set to `false`, the attribute will NOT be
* displayed.
*
* Additional special settings are:
* - viewModel: Model|Closure, the model to be used for this attribute in VIEW mode. This will override the `model`
* setting at the widget level. If not set, the widget `model` setting will be used.
* - editModel: Model|Closure, the model to be used for this attribute in EDIT mode. This will override the `model`
* setting at the widget level. If not set, the widget `model` setting will be used.
* - rowOptions: array|Closure, HTML attributes for the row (if not set, this will be defaulted to the `rowOptions`
* set at the widget level)
* - labelColOptions: array|Closure, HTML attributes for the label column (if not set, this will be defaulted to
* the `labelColOptions` set at the widget level)
* - valueColOptions: array|Closure, HTML attributes for the value column (if not set, this will be defaulted to
* `valueColOptions` set at the widget level)
* - group: boolean|Closure, whether to group the selection by merging the label and value into a single column.
* - groupOptions: array|Closure, HTML attributes for the grouped/merged column when `group` is set to `true`.
* - type: string|Closure, the input type for rendering the attribute in edit mode. Must be one of the
* [[DetailView::::INPUT_]] constants.
* - displayOnly: boolean|Closure, if the input is to be set to as `display only` in edit mode.
* - widgetOptions: array|Closure, the widget options if you set `type` to [[DetailView::::INPUT_WIDGET]]. The
* following special options are recognized:
* - `class`: string the fully namespaced widget class.
* - items: array|Closure, the list of data items for dropDownList, listBox, checkboxList & radioList
* - inputType: string|Closure, the HTML 5 input type if `type` is set to [[DetailView::::INPUT_HTML 5]].
* - inputContainer: array|Closure, HTML attributes for the input container
* - inputWidth: string|Closure, the width of the container holding the input, should be appended along with the
* width unit (`px` or `%`) - this property is deprecated since v1.7.7
* - fieldConfig: array|Closure, optional, the Active field configuration.
* - options: array|Closure, optional, the HTML attributes for the input.
* - updateAttr: string|Closure, optional, the name of the attribute to be updated, when in edit mode. This will
* default to the `attribute` setting.
* - updateMarkup: string|Closure, the raw markup to render in edit mode. If not set, this normally will be
* automatically generated based on `attribute` or `updateAttr` setting. If this is set it will override the
* default markup.
*
* Note that all of the attribute properties above can also be setup as a Closure callback with the signature
* `function($form, $widget)`, where:
* - `$form`: ActiveForm, is the current active form object in the detail view.
* - `$widget`: DetailView, is the current detail view widget instance.
*/
public $attributes;
/**
* @var array the options for the ActiveForm that will be generated in edit mode.
*/
public $formOptions = [];
/**
* @var string the ActiveForm widget class
*/
public $formClass = 'kartik\form\ActiveForm';
/**
* @var array the panel settings. If this is set, the grid widget
* will be embedded in a bootstrap panel. Applicable only if `bootstrap`
* is `true`. The following array keys are supported:
* - `type`: _string_, the panel contextual type (one of the TYPE constants, if not set will default to `default` or
* `self::TYPE_DEFAULT`)
* - `heading`: string | boolean, the panel heading title value. If set to false, the entire heading will be not
* displayed. Note that the `{title}` tag in the `headingOptions['template']` will be replaced with this value.
* - `headingOptions`: _array_, the HTML attributes for the panel heading. Defaults to `['class'=>'panel-title']`.
* The following additional options are available:
* - `tag`: _string_, the tag to render the heading. Defaults to `h3`.
* - `template`: _string_, the template to render the heading. Defaults to `{buttons}{title}`, where:
* - `{title}` will be replaced with the `heading` value, and
* -`{buttons}` will be replaced by the rendered buttons.
* - `footer`: string | boolean, the panel footer title value. Defaults to `false`. If set to false, the entire
* footer will be not displayed. Note that the `{title}` tag in the `footerOptions['template']` will be
* replaced with this value.
* - `footerOptions`: _array_, the HTML attributes for the panel footer. Defaults to `['class'=>'panel-title']`. The
* following additional options are available:
* - `tag`: _string_, the tag to render the footer. Defaults to `h4`.
* - `template`: _string_, the template to render the footer. Defaults to `{title}`, where:
* - `{title}` will be replaced with the `footer`, and
* -`{buttons}` will be replaced by the rendered buttons.
*/
public $panel = [];
/**
* @var array the HTML attributes for the bootstrap panel container (applicable if [[panel]
* has been configured).
*/
public $panelOptions = [];
/**
* @var string the CSS class prefix to apply to the bootstrap panel container (applicable if
* [[panel] has been configured)
*/
public $panelCssPrefix = 'panel panel-';
/**
* @var string the main template to render the detail view. The following tags will be replaced:
* - `{detail}`: will be replaced by the rendered detail view
* - `{buttons}`: the buttons to be displayed as set in `buttons1` and
* `buttons2`.
*/
public $mainTemplate = "{detail}";
/**
* @var array the options for the button toolbar container
*/
public $buttonContainer = ['class' => 'pull-right'];
/**
* @var string the buttons to show when in view mode. The following tags will be replaced:
* - `{view}`: the view button
* - `{update}`: the update button
* - `{delete}`: the delete button
* - `{save}`: the save button
* Defaults to `{edit} {delete}`.
*/
public $buttons1 = '{update} {delete}';
/**
* @var string the buttons template to show when in edit mode. The following tags will be replaced:
* - `{view}`: the view button
* - `{update}`: the update button
* - `{reset}`: the reset button
* - `{delete}`: the delete button
* - `{save}`: the save button
* Defaults to `{view} {save}`.
*/
public $buttons2 = '{view} {reset} {save}';
/**
* @var array the HTML attributes for the container displaying the VIEW mode attributes.
*/
public $viewAttributeContainer = [];
/**
* @var array the HTML attributes for the container displaying the EDIT mode attributes.
*/
public $editAttributeContainer = [];
/**
* @var array the HTML attributes for the container displaying the VIEW mode buttons.
*/
public $viewButtonsContainer = [];
/**
* @var array the HTML attributes for the container displaying the EDIT mode buttons.
*/
public $editButtonsContainer = [];
/**
* @var array the HTML attributes for the view button. This will toggle the view from edit mode to view mode. The
* following special options are recognized:
* - `label`: the save button label. This will not be HTML encoded.
* Defaults to '<span class="glyphicon glyphicon-eye-open"></span>'.
*/
public $viewOptions = [];
/**
* @var array the HTML attributes for the update button. This button will toggle the edit mode on. The following
* special options are recognized:
* - `label`: the update button label. This will not be HTML encoded.
* Defaults to '<span class="glyphicon glyphicon-pencil"></span>'.
*/
public $updateOptions = [];
/**
* @var array the HTML attributes for the reset button. This button will reset the form in edit mode. The following
* special options are recognized:
* - `label`: the reset button label. This will not be HTML encoded.
* Defaults to '<span class="glyphicon glyphicon-ban-circle"></span>'.
*/
public $resetOptions = [];
/**
* @var array the HTML attributes for the edit button. The following special options are recognized:
* - `label`: the delete button label. This will not be HTML encoded. Defaults to
* `'<span class="glyphicon glyphicon-trash"></span>'`.
* - `url`: the delete button url. If not set will default to `#`.
* - `params`: _array_, the parameters to be passed via ajax which you must set as key value pairs. This will be
* automatically json encoded, so you can set JsExpression or callback
* - `ajaxSettings`: _array_, the ajax settings if you choose to override the delete ajax settings.
* @see http://api.jquery.com/jquery.ajax/
* - `confirm': _string_, the confirmation message before triggering delete. Defaults to:
* `Yii::t('kvdetail', 'Are you sure you want to delete this item?')`.
* - `showErrorStack`: _boolean_, whether to show the complete error stack.
*/
public $deleteOptions = [];
/**
* @var array the HTML attributes for the save button. This will default to a form submit button.
* The following special options are recognized:
* - `label`: the save button label. This will not be HTML encoded. Defaults to '<span class="glyphicon
* glyphicon-floppy-disk"></span>'.
*/
public $saveOptions = [];
/**
* @var array the HTML attributes for the widget container
*/
public $container = [];
/**
* @var array the the internalization configuration for this widget
*/
public $i18n = [];
/**
* @var string the Detail View plugin name
*/
public $pluginName = 'kvDetailView';
/**
* @var array the Detail View plugin options
*/
public $pluginOptions = [];
/**
* @var string the Detail View plugin destroy JS
*/
public $pluginDestroyJs;
/**
* @var integer the position where the client JS hash variables for the DetailView widget will be loaded.
* Defaults to `View::POS_HEAD`. This can be set to `View::POS_READY` for specific scenarios like when
* rendering the widget via `renderAjax`.
*/
public $hashVarLoadPosition = View::POS_HEAD;
/**
* @var string translation message file category name for i18n
*/
protected $_msgCat = 'kvdetail';
/**
* @var string the hashed global variable name storing the pluginOptions
*/
protected $_hashVar;
/**
* @var string the element's HTML5 data variable name storing the pluginOptions
*/
protected $_dataVar;
/**
* @var string the Json encoded options
*/
protected $_encOptions = '';
/**
* @var ActiveForm the form instance
*/
protected $_form;
/**
* @var array HTML attributes for child tables
*/
protected $_childTableOptions = [];
/**
* @var array HTML attributes for table row
*/
protected $_rowOptions = [];
/**
* @inheritdoc
*/
public function init()
{
$this->initWidget();
parent:: init();
}
/**
* @inheritdoc
*/
public function run()
{
$this->runWidget();
}
/**
* Initializes the detail view widget
*
* @throws InvalidConfigException
*/
protected function initWidget()
{
if ($this->enableEditMode) {
/**
* @var ActiveForm $formClass
*/
$formClass = $this->formClass;
$activeForm = ActiveForm::classname();
if (!is_subclass_of($formClass, $activeForm) && $formClass !== $activeForm) {
throw new InvalidConfigException("Form class '{$formClass}' must exist and extend from '{$activeForm}'.");
}
$this->validateDisplay();
if (!isset($this->formOptions['fieldConfig']['template'])) {
$this->formOptions['fieldConfig']['template'] = "{input}\n{hint}\n{error}";
}
$this->_form = $formClass::begin($this->formOptions);
}
if ($this->bootstrap) {
Html::addCssClass($this->options, 'table');
if ($this->hover) {
Html::addCssClass($this->options, 'table-hover');
}
if ($this->bordered) {
Html::addCssClass($this->options, 'table-bordered');
}
if ($this->condensed) {
Html::addCssClass($this->options, 'table-condensed');
}
$this->_childTableOptions = $this->options;
if ($this->striped) {
Html::addCssClass($this->options, 'table-striped');
}
}
Html::addCssClass($this->_childTableOptions, 'kv-child-table');
Html::addCssClass($this->options, 'detail-view');
Html::addCssStyle($this->labelColOptions, "text-align:{$this->hAlign};vertical-align:{$this->vAlign};");
}
/**
* Prepares and runs the detail view widget
*/
protected function runWidget()
{
if (empty($this->container['id'])) {
$this->container['id'] = $this->getId();
}
$this->initI18N(__DIR__);
Html::addCssClass($this->alertContainerOptions, 'panel-body kv-alert-container');
$this->alertMessageSettings += [
'kv-detail-error' => 'alert alert-danger',
'kv-detail-success' => 'alert alert-success',
'kv-detail-info' => 'alert alert-info',
'kv-detail-warning' => 'alert alert-warning'
];
$this->registerAssets();
$output = $this->renderDetailView();
if (is_array($this->panel) && !empty($this->panel) && $this->panel !== false) {
$output = $this->renderPanel($output);
}
$output = strtr(Html::tag('div', $this->mainTemplate, $this->container), ['{detail}' => $output]);
Html::addCssClass($this->viewButtonsContainer, 'kv-buttons-1');
$buttons = Html::tag('span', $this->renderButtons(1), $this->viewButtonsContainer);
if ($this->enableEditMode) {
Html::addCssClass($this->editButtonsContainer, 'kv-buttons-2');
$buttons .= Html::tag('span', $this->renderButtons(2), $this->editButtonsContainer);
}
echo str_replace('{buttons}', Html::tag('div', $buttons, $this->buttonContainer), $output);
if ($this->enableEditMode) {
/**
* @var ActiveForm $formClass
*/
$formClass = $this->formClass;
$formClass::end();
}
}
/**
* Initializes and renders alert container block
*/
protected function renderAlertBlock()
{
$session = Yii::$app->session;
$flashes = $session->getAllFlashes();
if ($this->showErrorSummary) {
// Show form error summary in error flash
if ($this->model->getErrors()) {
$flashes['kv-detail-error'] = $this->_form->errorSummary($this->model);
}
}
if (count($flashes) === 0) {
Html::addCssStyle($this->alertContainerOptions, 'display:none;');
}
$out = Html::beginTag('div', $this->alertContainerOptions);
foreach ($flashes as $type => $message) {
if (!isset($this->alertMessageSettings[$type])) {
continue;
}
$options = ArrayHelper::getValue($this->alertWidgetOptions, 'options', []);
Html::addCssClass($options, ['alert', 'alert-' . $this->alertMessageSettings[$type]]);
$this->alertWidgetOptions['body'] = $message;
$this->alertWidgetOptions['options'] = $options;
$out .= "\n" . Alert::widget($this->alertWidgetOptions);
$session->removeFlash($type);
}
$out .= "\n</div>";
return $out;
}
/**
* Check if model has editing errors
*
* @return boolean
*/
protected function hasEditErrors()
{
if ($this->model->hasErrors()) {
return true;
}
foreach ($this->attributes as $attribute) {
/**
* @var Model $attribute ['editModel']
*/
if (empty($attribute['editModel']) || !$attribute['editModel'] instanceof Model) {
continue;
}
if ($attribute['editModel']->hasErrors()) {
return true;
}
}
return false;
}
/**
* Validates the display of correct attributes and buttons
* at initialization based on mode
*
* @return void
*/
protected function validateDisplay()
{
$none = 'display:none';
if ($this->hasEditErrors()) {
$this->mode = self::MODE_EDIT;
}
if ($this->mode === self::MODE_EDIT) {
Html::addCssClass($this->container, 'kv-edit-mode');
Html::addCssStyle($this->viewAttributeContainer, $none);
Html::addCssStyle($this->viewButtonsContainer, $none);
} else {
Html::addCssClass($this->container, 'kv-view-mode');
Html::addCssStyle($this->editAttributeContainer, $none);
Html::addCssStyle($this->editButtonsContainer, $none);
}
}
/**
* Renders the main detail view widget
*
* @return string the detail view content
*/
protected function renderDetailView()
{
$rows = [];
foreach ($this->attributes as $attribute) {
$rows[] = $this->renderAttributeRow($attribute);
}
$tag = ArrayHelper::remove($this->options, 'tag', 'table');
$output = Html::tag($tag, implode("\n", $rows), $this->options);
return ($this->bootstrap && $this->responsive) ?
'<div class="table-responsive kv-detail-view">' . $output . '</div>' :
'<div class="kv-detail-view">' . $output . '</div>';
}
/**
* Renders a single attribute.
*
* @param array $attribute the specification of the attribute to be rendered.
*
* @return string the rendering result
*/
protected function renderAttributeRow($attribute)
{
$this->_rowOptions = ArrayHelper::getValue($attribute, 'rowOptions', $this->rowOptions);
if (isset($attribute['columns'])) {
Html::addCssClass($this->_rowOptions, 'kv-child-table-row');
$content = '<td class="kv-child-table-cell" colspan=2><table class="kv-child-table"><tr>';
foreach ($attribute['columns'] as $child) {
$content .= $this->renderAttributeItem($child);
}
$content .= '</tr></table></td>';
} else {
$content = $this->renderAttributeItem($attribute);
}
return Html::tag('tr', $content, $this->_rowOptions);
}
/**
* Renders a single attribute item combination.
*
* @param array $attribute the specification of the attribute to be rendered.
*
* @return string the rendering result
*/
protected function renderAttributeItem($attribute)
{
$labelColOpts = ArrayHelper::getValue($attribute, 'labelColOptions', $this->labelColOptions);
$valueColOpts = ArrayHelper::getValue($attribute, 'valueColOptions', $this->valueColOptions);
if (ArrayHelper::getValue($attribute, 'group', false)) {
$groupOptions = ArrayHelper::getValue($attribute, 'groupOptions', []);
$label = ArrayHelper::getValue($attribute, 'label', '');
if (empty($groupOptions['colspan'])) {
$groupOptions['colspan'] = 2;
}
return Html::tag('th', $label, $groupOptions);
}
if ($this->hideIfEmpty === true && empty($attribute['value'])) {
Html::addCssClass($this->_rowOptions, 'kv-view-hidden');
}
if (ArrayHelper::getValue($attribute, 'type', 'text') === self::INPUT_HIDDEN) {
Html::addCssClass($this->_rowOptions, 'kv-edit-hidden');
}
/** issue #158 **/
$value = is_array($attribute['value']) ? print_r($attribute['value'], true) : $attribute['value'];
if ($this->notSetIfEmpty && ($value === '' || $value === null)) {
$value = null;
}
$dispAttr = $this->formatter->format($value, $attribute['format']);
Html::addCssClass($this->viewAttributeContainer, 'kv-attribute');
Html::addCssClass($this->editAttributeContainer, 'kv-form-attribute');
$output = Html::tag('div', $dispAttr, $this->viewAttributeContainer) . "\n";
if ($this->enableEditMode) {
$editInput = ArrayHelper::getValue($attribute, 'displayOnly', false) ? $dispAttr :
$this->renderFormAttribute($attribute);
$output .= Html::tag('div', $editInput, $this->editAttributeContainer);
}
return Html::tag('th', $attribute['label'], $labelColOpts) . "\n" . Html::tag('td', $output, $valueColOpts);
}
/**
* Checks if a bootstrap grid column class has been added to the container
*
* @param array $container
*
* @return boolean
*/
protected static function hasGridCol($container = [])
{
$css = ArrayHelper::getValue($container, 'class', '');
$css = trim($css);
$css = preg_replace('/\s+/', ' ', $css);
if (empty($css)) {
return false;
}
$classes = explode(' ', $css);
if (!empty($classes)) {
foreach ($classes as $class) {
if (substr(trim($class), 0, 4) === 'col-') {
return true;