Passed
Push — master ( 3f337a...acbc33 )
by Dmitrijs
02:00
created

Card::renderImageContent()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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