Completed
Push — master ( 7aacb2...2b39b6 )
by
unknown
06:55
created

Card::processAdditionToPanel()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 8.7057
c 0
b 0
f 0
cc 6
nc 7
nop 1
1
<?php
2
/**
3
 * Contains the component class for rendering a panel.
4
 *
5
 * @copyright (C) 2018, Tobias Oetterer, Paderborn University
6
 * @license       https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License, version 3 (or later)
7
 *
8
 * This file is part of the MediaWiki extension BootstrapComponents.
9
 * The BootstrapComponents extension is free software: you can redistribute it
10
 * and/or modify it under the terms of the GNU General Public License as published
11
 * by the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * The BootstrapComponents extension is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
 *
22
 * @file
23
 * @ingroup       BootstrapComponents
24
 * @author        Tobias Oetterer
25
 */
26
27
namespace BootstrapComponents\Components;
28
29
use BootstrapComponents\ComponentLibrary;
30
use BootstrapComponents\AbstractComponent;
31
use BootstrapComponents\NestingController;
32
use BootstrapComponents\ParserOutputHelper;
33
use \Html;
34
use \MWException;
35
36
/**
37
 * Class Card
38
 *
39
 * Class for component 'card'
40
 *
41
 * @see   https://github.com/oetterer/BootstrapComponents/blob/master/docs/components.md#Card
42
 * @since 4.0
43
 */
44
class Card extends AbstractComponent {
45
46
	/**
47
	 * Indicates, whether this panel is collapsible
48
	 *
49
	 * @var bool $collapsible
50
	 */
51
	private $collapsible;
52
53
	/**
54
	 * If true, indicates that we are inside an accordion
55
	 *
56
	 * @var bool $insideAccordion
57
	 */
58
	private $insideAccordion;
59
60
	/**
61
	 * Card constructor.
62
	 *
63
	 * @param ComponentLibrary   $componentLibrary
64
	 * @param ParserOutputHelper $parserOutputHelper
65
	 * @param NestingController  $nestingController
66
	 *
67
	 * @throws MWException
68
	 */
69
	public function __construct( $componentLibrary, $parserOutputHelper, $nestingController ) {
70
		parent::__construct( $componentLibrary, $parserOutputHelper, $nestingController );
71
		$this->collapsible = false;
72
		$this->insideAccordion = $this->isInsideAccordion();
73
	}
74
75
	/**
76
	 * @inheritdoc
77
	 *
78
	 * @param string $input
79
	 */
80
	protected function placeMe( $input ) {
81
82
		$this->collapsible = $this->getValueFor( 'collapsible' ) || $this->isInsideAccordion();
83
84
		$outerClass = $this->calculateOuterClassAttribute();
85
		$innerClass = $this->calculateInnerClassAttribute();
86
		$bodyClass = $this->calculateBodyClassAttribute();
87
88
		list ( $outerClass, $style ) = $this->processCss( $outerClass, [] );
89
90
		return Html::rawElement(
91
			'div',
92
			[
93
				'class' => $this->arrayToString( $outerClass, ' ' ),
94
				'style' => $this->arrayToString( $style, ';' ),
95
			],
96
			$this->processAdditionToPanel( 'header' )
97
			. Html::rawElement(
98
				'div',
99
				[
100
					'id'    => $this->getId(),
101
					'class' => $this->arrayToString( $innerClass, ' ' ),
102
				],
103
				Html::rawElement(
104
					'div',
105
					[
106
						'class' => $this->arrayToString( $bodyClass, ' ' ),
107
					],
108
					$input
109
				)
110
				. $this->processAdditionToPanel( 'footer' )
111
			)
112
		);
113
	}
114
115
	/**
116
	 * Calculates the css class from the attributes array for the text body
117
	 *
118
	 * @return array
119
	 */
120
	private function calculateBodyClassAttribute() {
121
		$class = [ 'card-body' ];
122
		if ( $this->hasValueFor( 'color' ) && ( $this->getValueFor( 'color', 'primary' ) != 'light' ) ) {
123
			$class[] = 'text-' . $this->getValueFor( 'color', 'primary' );
124
		}
125
		return $class;
126
	}
127
128
	/**
129
	 * Calculates the css class from the attributes array for the "inner" section (div around body and footer)
130
	 *
131
	 * @return bool|array
132
	 */
133
	private function calculateInnerClassAttribute() {
134
135
		$class = false;
136
		if ( $this->isCollapsible() ) {
137
			$class = [ 'card-collapse', 'collapse', 'fade' ];
138
			if ( $this->getValueFor( 'active' ) ) {
139
				$class[] = 'in';
140
			}
141
		}
142
		return $class;
143
	}
144
145
	/**
146
	 * Calculates the css class string from the attributes array
147
	 *
148
	 * @return string[]
149
	 */
150
	private function calculateOuterClassAttribute() {
151
152
		$class = [ 'card' ];
153
		if ( $this->hasValueFor( 'background' ) ) {
154
			$class[] = 'bg-' . $this->getValueFor( 'background', 'primary' );
155
			if ( $this->getValueFor( 'background', 'primary' ) != 'light' ) {
156
				$class[] = 'text-white';
157
			}
158
		} elseif ( $this->hasValueFor( 'color' ) ) {
159
			$class[] = 'border-' . $this->getValueFor( 'color', 'primary' );
160
		}
161
		return $class;
162
	}
163
164
	/**
165
	 * Returns my data parent attribute (the one to put in the heading toggle when inside an accordion).
166
	 *
167
	 * @return string
168
	 */
169
	private function getDataParent() {
170
		$parent = $this->getParentComponent();
171
		if ( $parent && $this->isInsideAccordion() && $parent->getId() ) {
172
			return '#' . $parent->getId();
173
		}
174
		return false;
175
	}
176
177
	/**
178
	 * Indicates, whether this panel is collapsible or not.
179
	 *
180
	 * @return bool
181
	 */
182
	private function isCollapsible() {
183
		return $this->collapsible;
184
	}
185
186
	/**
187
	 * Checks, whether this panel is directly inside an accordion.
188
	 *
189
	 * @return bool
190
	 */
191
	private function isInsideAccordion() {
192
		if ( !is_null( $this->insideAccordion ) ) {
193
			return $this->insideAccordion;
194
		}
195
		$parent = $this->getParentComponent();
196
		return $this->insideAccordion = ($parent && ($this->getParentComponent()->getComponentName() == 'accordion'));
197
	}
198
199
	/**
200
	 * Processes the addition heading or footer.
201
	 *
202
	 * This examines $attributes and produces an appropriate heading or footing if corresponding data is found.
203
	 *
204
	 * @param string $type
205
	 *
206
	 * @return string
207
	 */
208
	private function processAdditionToPanel( $type ) {
209
		$inside = $this->getValueFor( $type );
210
211
		if ( empty( $inside ) ) {
212
			if ( $type == 'header' && $this->isInsideAccordion() ) {
213
				$inside = $this->getId();
214
			} else {
215
				return '';
216
			}
217
		}
218
		$newAttributes = [
219
			'class' => 'card-' . $type,
220
		];
221
		if ( $type == 'header' ) {
222
			if ( $this->isCollapsible() ) {
223
				$newAttributes += [
224
						'data-parent' => $this->getDataParent(),
225
						'data-toggle' => 'collapse',
226
						'href'        => '#' . $this->getId(),
227
					];
228
			}
229
			$inside = Html::rawElement(
230
				'h4',
231
				[
232
					'class' => 'card-title',
233
					'style' => 'margin-top:0;padding-top:0;',
234
				],
235
				$inside
236
			);
237
		}
238
239
		return Html::rawElement(
240
			'div',
241
			$newAttributes,
242
			$inside
243
		);
244
	}
245
}
246