Completed
Push — master ( 030457...e6466d )
by Dmitrijs
10:39 queued 08:30
created

Card::run()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 23
rs 9.8333
c 0
b 0
f 0
cc 3
nc 2
nop 0
1
<?php
2
/**
3
 * @link https://github.com/DMGPage/yii2-materialize
4
 * @copyright Copyright (c) 2018 Dmitrijs Reinmanis
5
 * @license https://github.com/DMGPage/yii2-materialize/blob/master/LICENSE
6
 */
7
8
namespace dmgpage\yii2materialize\widgets;
9
10
use dmgpage\yii2materialize\helpers\Html;
11
use yii\helpers\ArrayHelper;
12
use yii\base\InvalidConfigException;
13
use dmgpage\yii2materialize\assets\MaterializeExtraAsset;
14
use dmgpage\yii2materialize\helpers\CardTitlePos;
15
16
/**
17
 * Cards are a convenient means of displaying content composed of different types of objects.
18
 * They’re also well-suited for presenting similar objects whose size or supported actions can vary considerably,
19
 * like photos with captions of variable length.
20
 *
21
 * You can use Cards like this:
22
 *
23
 * ```php
24
 * echo Card::widget([
25
 *     'colContainerOptions' => ['class' => 's12 m4'],
26
 *     'cardContainerOptions' => ['class' => 'blue-grey darken-1'],
27
 *     'contentContainerOptions' => ['class' => 'white-text'],
28
 *     'title' => 'Card Title',
29
 *     'titlePosition' => CardTitlePos::IMAGE,
30
 *     'actions' => [
31
 *         [
32
 *             'label' => 'This is a link #1',
33
 *             'icon' => 'add',
34
 *             'encode' => false,
35
 *         ],
36
 *         ['label' => 'This is a link #2']
37
 *     ],
38
 *     'imageUrl' => 'https://materializecss.com/images/sample-1.jpg',
39
 *     'actionBtn' => [
40
 *         'type' => ButtonType::FLOATING,
41
 *         'size' => Size::MEDIUM,
42
 *         'waves' => Waves::LIGHT,
43
 *         'icon' => ['name' => 'add'],
44
 *         'options' => ['class' => 'red']
45
 *     ]
46
 *     'content' => $this->render('card'),
47
 * ]);
48
 * ```
49
 */
50
class Card extends Widget
51
{
52
    /**
53
     * @var array the HTML attributes for the row container tag of the card view.
54
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
55
     */
56
    public $options = [];
57
58
    /**
59
     * @var array the HTML attributes for the column container tag of the card view.
60
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
61
     */
62
    public $colContainerOptions = ['class' => 's12 m6'];
63
64
    /**
65
     * @var array the HTML attributes for the content wrapper tag of the card view.
66
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
67
     */
68
    public $cardContainerOptions = [];
69
70
    /**
71
     * @var array the HTML attributes for the content wrapper tag of the card view.
72
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
73
     */
74
    public $contentContainerOptions = [];
75
76
    /**
77
     * @var string title of the card
78
     */
79
    public $title;
80
81
    /**
82
     * @var array the HTML attributes for the title tag of the card view. Uses only if "cardTitle" attribute is specified.
83
     * - encode: boolean, optional, whether this item`s label should be HTML-encoded.
84
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
85
     */
86
    public $titleOptions = [];
87
88
    /**
89
     * @var string position of the card title. Possible values are: image, content. Default value is content
90
     */
91
    public $titlePosition = CardTitlePos::CONTENT;
92
93
    /**
94
     * @var array list of card action items. Each action item should be an array of the following structure:
95
     * - label: string, specifies the action item label. When [[encodeLabels]] is true, the label
96
     *   will be HTML-encoded.
97
     * - encode: boolean, optional, whether this item`s label should be HTML-encoded. This param will override
98
     *   global [[encodeLabels]] param.
99
     * - url: string or array, optional, specifies the URL of the action item. It will be processed by [[Url::to]].
100
     * - icon: string or array, optional, icon name or array with 'name' and 'options'.
101
     * - options: array, optional, the HTML attributes for the action container tag.
102
     */
103
    public $actions = [];
104
105
    /**
106
     * @var array the HTML attributes for the action wrapper tag of the card view. Uses only if "actions" attribute is specified.
107
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
108
     */
109
    public $actionContainerOptions = [];
110
111
    /**
112
     * @var bool whether to HTML-encode the link labels and card title
113
     */
114
    public $encodeLabels = true;
115
116
    /**
117
     * @var string Card body. It will NOT be HTML-encoded. Therefore you can pass in HTML code.
118
     * If this is coming from end users, you should consider encode() it to prevent XSS attacks.
119
     */
120
    public $content;
121
122
    /**
123
     * @var string the image URL. This parameter will be processed by [[Url::to()]]
124
     */
125
    public $imageUrl;
126
127
    /**
128
     * @var array the HTML attributes for the image wrapper tag of the card view. Uses only if "imageUrl" attribute is specified.
129
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
130
     */
131
    public $imageContainerOptions = [];
132
133
    /**
134
     * @var array the HTML attributes for the image tag of the card view. Uses only if "imageUrl" attribute is specified.
135
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
136
     */
137
    public $imageOptions = [];
138
139
    /**
140
     * @var array value will be passed to Button widget. You can set extra param 'url' to render it as link.
141
     * @see \dmgpage\yii2materialize\widgets\Button for details on how attributes are being rendered.
142
     */
143
    public $actionBtn = [];
144
145
    /**
146
     * Initializes the widget.
147
     * @return void
148
     */
149
    public function init()
150
    {
151
        parent::init();
152
153
        Html::addCssClass($this->cardContainerOptions, ['class' => 'card']);
154
        Html::addCssClass($this->contentContainerOptions, ['class' => 'card-content']);
155
156
        $html = Html::beginGridRow($this->options);
157
        $html .= Html::beginGridCol($this->colContainerOptions);
158
        $html .= Html::beginTag('div', $this->cardContainerOptions);
159
        $html .= $this->renderImageContent();
160
        $html .= Html::beginTag('div', $this->contentContainerOptions);
161
162
        if (CardTitlePos::CONTENT()->is($this->titlePosition)) {
163
            $html .= $this->renderTitleContent();
164
        }
165
166
        echo $html;
167
    }
168
169
    /**
170
     * Renders the widget.
171
     * @return void
172
     */
173
    public function run()
174
    {
175
        $this->registerPlugin('card');
176
177
        $html = $this->content;
178
        $html .= Html::endTag('div'); // ends container tag
179
180
        if (!empty($this->actions)) {
181
            Html::addCssClass($this->actionContainerOptions, ['class' => 'card-action']);
182
            $html .= Html::beginTag('div', $this->actionContainerOptions);
183
184
            foreach ($this->actions as $action) {
185
                $html .= $this->renderActionItem($action);
186
            }
187
188
            $html .= Html::endTag('div');
189
        }
190
191
        $html .= Html::endTag('div');
192
        $html .= Html::endGridCol();
193
        $html .= Html::endGridRow();
194
195
        echo $html;
196
    }
197
198
    /**
199
     * Renders card title tag content.
200
     * @return string the rendering result
201
     */
202
    protected function renderTitleContent()
203
    {
204
        $html = '';
205
206
        if (!empty($this->title)) {
207
            $encode = isset($this->titleOptions['encode']) ? $this->titleOptions['encode'] : $this->encodeLabels;
208
            unset($this->titleOptions['encode']);
209
            Html::addCssClass($this->titleOptions, ['class' => 'card-title']);
210
            $title = $encode ? Html::encode($this->title) : $this->title;
211
            $html .= Html::tag('span', $title, $this->titleOptions);
212
        }
213
214
        return $html;
215
    }
216
217
    /**
218
     * Renders card-image tag content, if "imageUrl" attribute is specified.
219
     * @return string the rendering result
220
     */
221
    protected function renderImageContent()
222
    {
223
        $html = '';
224
225
        if (!empty($this->imageUrl)) {
226
            Html::addCssClass($this->imageContainerOptions, ['class' => 'card-image']);
227
            $html .= Html::beginTag('div', $this->imageContainerOptions);
228
            $html .= Html::img($this->imageUrl, $this->imageOptions);
229
230
            if (CardTitlePos::IMAGE()->is($this->titlePosition)) {
231
                $html .= $this->renderTitleContent();
232
            }
233
234
            $html .= $this->renderActionButton();
235
            $html .= Html::endTag('div');
236
        }
237
238
        return $html;
239
    }
240
241
    /**
242
     * Renders action button tag, if "actionBtn" attribute is specified.
243
     * @return string the rendering result
244
     */
245
    protected function renderActionButton()
246
    {
247
        $html = '';
248
249
        if (!empty($this->actionBtn)) {
250
            if (!isset($this->actionBtn['options'])) {
251
                $this->actionBtn['options'] = ['class' => 'halfway-fab'];
252
            } else {
253
                Html::addCssClass($this->actionBtn['options'], 'halfway-fab');
254
            }
255
256
            $html .= Button::widget($this->actionBtn);
257
        }
258
259
        return $html;
260
    }
261
262
    /**
263
     * Renders a single card action item.
264
     *
265
     * @param array $link the link to be rendered. It must contain the "label" element. The "url" and "icon" element is optional.
266
     * @return string the rendering result
267
     * @throws InvalidConfigException if `$link` does not have "label" element.
268
     */
269
    protected function renderActionItem($link)
270
    {
271
        $encodeLabel = ArrayHelper::remove($link, 'encode', $this->encodeLabels);
272
273
        if (array_key_exists('label', $link)) {
274
            $label = $encodeLabel ? Html::encode($link['label']) : $link['label'];
275
        } else {
276
            throw new InvalidConfigException('The "label" element is required for each link.');
277
        }
278
279
        // Add icon to label text
280
        if (isset($link['icon'])) {
281
            $view = $this->getView();
282
            MaterializeExtraAsset::register($view);
283
284
            // Has issues on positioning: https://github.com/google/material-design-icons/issues/206
285
            $label = $this->renderIcon($link['icon']) . $label;
286
        }
287
288
        $options = $link['options'];
289
290
        if (isset($link['url'])) {
291
            return Html::a($label, $link['url'], $options);
292
        } else {
293
            return Html::a($label, '#', $options);
294
        }
295
    }
296
}
297