Completed
Push — master ( 552173...c8702c )
by Tobias
12:00 queued 43s
created

Popover   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 2
dl 0
loc 93
ccs 44
cts 44
cp 1
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B placeMe() 0 19 5
B buildHtmlElements() 0 30 2
A calculatePopoverClassAttribute() 0 7 2
A stripLinksFrom() 0 9 2
1
<?php
2
/**
3
 * Contains the component class for rendering a popover.
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\AbstractComponent;
30
use \Html;
31
32
/**
33
 * Class Popover
34
 *
35
 * Class for component 'popover'
36
 *
37
 * @see   https://github.com/oetterer/BootstrapComponents/blob/master/docs/components.md#Popover
38
 * @since 1.0
39
 */
40
class Popover extends AbstractComponent {
41
	/**
42
	 * @inheritdoc
43
	 *
44
	 * @param string $input
45
	 */
46 6
	public function placeMe( $input ) {
47 6
		$heading = $this->getValueFor( 'heading' );
48 6
		$text    = $this->getValueFor( 'text' );
49 6
		if ( $heading === false || !strlen( $heading ) ) {
50 2
			return $this->getParserOutputHelper()->renderErrorMessage( 'bootstrap-components-popover-heading-missing' );
51
		}
52 5
		if ( $text === false || !strlen( $text ) ) {
53 2
			return $this->getParserOutputHelper()->renderErrorMessage( 'bootstrap-components-popover-text-missing' );
54
		}
55
56 4
		list( $tag, $text, $attributes ) = $this->buildHtmlElements( $input, (string)$text, (string)$heading );
57
58
		// I cannot use the button class here, because it needs a target and also does not accept pre-processed attributes.
59 4
		return Html::rawElement(
60 4
			$tag,
61 4
			$attributes,
62
			$text
63 4
		);
64
	}
65
66
	/**
67
	 * @param string $input
68
	 * @param string $text
69
	 * @param string $heading
70
	 *
71
	 * @return array $tag, $text, $attributes
72
	 */
73 4
	private function buildHtmlElements( $input, $text, $heading ) {
74 4
		list ( $class, $style ) = $this->processCss( $this->calculatePopoverClassAttribute(), [] );
75
76 4
		list ( $text, $target ) = $this->stripLinksFrom( $text, '' );
77
78
		$attributes = [
79 4
			'class'          => $this->arrayToString( $class, ' ' ),
80 4
			'style'          => $this->arrayToString( $style, ';' ),
81 4
			'id'             => $this->getId(),
82 4
		];
83 4
		if ( empty( $target ) ) {
84
			// this is the normal popover process
85 4
			$attributes = array_merge(
86 4
				$attributes,
87
				[
88 4
					'data-toggle'    => 'popover',
89 4
					'title'          => $heading,
90 4
					'data-content'   => str_replace( "\n", " ", trim( $input ) ),
91 4
					'data-placement' => $this->getValueFor( 'placement' ),
92 4
					'data-trigger'   => $this->getValueFor( 'trigger' ),
93
				]
94 4
			);
95 4
			$tag = "button";
96 4
		} else {
97 1
			$attributes['href'] = $target;
98 1
			$attributes['role'] = 'button';
99 1
			$tag = "a";
100
		}
101 4
		return [ $tag, $text, $attributes ];
102
	}
103
104
	/**
105
	 * Calculates the class attribute value from the passed attributes
106
	 *
107
	 * @return string[]
108
	 */
109 4
	private function calculatePopoverClassAttribute() {
110 4
		$class = [ 'btn', 'btn-' . $this->getValueFor( 'color', 'info' ) ];
111 4
		if ( $size = $this->getValueFor( 'size' ) ) {
112 2
			$class[] = 'btn-' . $size;
113 2
		}
114 4
		return $class;
115
	}
116
117
	/**
118
	 * @param string $text
119
	 * @param string $target
120
	 *
121
	 * @return string[]
122
	 */
123 4
	private function stripLinksFrom( $text, $target ) {
124 4
		if ( preg_match( '~<a.+href=.([^>]+Special:Upload[^"]+)[^>]*>(.+)</a>~', $text, $matches ) ) {
125
			// we have an non existing image as text, return image name as text and upload url as target
126
			// since $text was already parsed and html_encoded and Html::rawElement will do this again,
127
			// we need to decode the html special characters in target aka $matches[1]
128 1
			return [ $matches[2], htmlspecialchars_decode( $matches[1] ) ];
129
		}
130 4
		return [ preg_replace( '~^(.*)(<a.+href=[^>]+>)(.+)(</a>)(.*)$~ms', '\1\3\5', $text ), $target ];
131
	}
132
}