-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathTabber.php
212 lines (184 loc) · 6.01 KB
/
Tabber.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
<?php
/**
* TabberNeue
* Tabber Class
* Implement <tabber> tag
*
* @package TabberNeue
* @author alistair3149, Eric Fortin, Alexia E. Smith, Ciencia Al Poder
* @license GPL-3.0-or-later
* @link https://www.mediawiki.org/wiki/Extension:TabberNeue
*/
declare( strict_types=1 );
namespace MediaWiki\Extension\TabberNeue;
use Html;
use InvalidArgumentException;
use MediaWiki\MediaWikiServices;
use Parser;
use PPFrame;
use Sanitizer;
use TemplateParser;
class Tabber {
/** @var bool */
private static $parseTabName = false;
/** @var bool */
private static $useLegacyId = false;
/**
* Parser callback for <tabber> tag
*
* @param string|null $input
* @param array $args
* @param Parser $parser Mediawiki Parser Object
* @param PPFrame $frame Mediawiki PPFrame Object
*
* @return string HTML
*/
public static function parserHook( ?string $input, array $args, Parser $parser, PPFrame $frame ) {
if ( $input === null ) {
return '';
}
$config = MediaWikiServices::getInstance()->getMainConfig();
$parserOutput = $parser->getOutput();
self::$parseTabName = $config->get( 'TabberNeueParseTabName' );
self::$useLegacyId = $config->get( 'TabberNeueUseLegacyTabIds' );
$count = count( $parserOutput->getExtensionData( 'tabber-count' ) ?? [] );
$html = self::render( $input, $count, $args, $parser, $frame );
$parserOutput->appendExtensionData( 'tabber-count', ++$count );
$parserOutput->addModuleStyles( [ 'ext.tabberNeue.init.styles' ] );
$parserOutput->addModules( [ 'ext.tabberNeue' ] );
$parser->addTrackingCategory( 'tabberneue-tabber-category' );
return $html;
}
/**
* Renders the necessary HTML for a <tabber> tag.
*
* @param string $input The input URL between the beginning and ending tags.
* @param int $count Current Tabber count
* @param array $args
* @param Parser $parser Mediawiki Parser Object
* @param PPFrame $frame Mediawiki PPFrame Object
*
* @return string HTML
*/
public static function render( string $input, int $count, array $args, Parser $parser, PPFrame $frame ): string {
$attr = [
'id' => "tabber-$count",
'class' => 'tabber tabber--init'
];
foreach ( $args as $attribute => $value ) {
$attr = Sanitizer::mergeAttributes( $attr, [ $attribute => $value ] );
}
$data = [
'array-tabs' => [],
'html-attributes' => Sanitizer::safeEncodeTagAttributes( Sanitizer::validateTagAttributes( $attr, 'div' ) )
];
$arr = explode( '|-|', $input );
foreach ( $arr as $tab ) {
$tabData = self::getTabData( $tab, $count, $parser, $frame );
if ( $tabData === [] ) {
continue;
}
$data['array-tabs'][] = [
'content' => $tabData['content'],
'label' => $tabData['label'],
'tabId' => "tabber-tab-{$tabData['id']}",
'tabpanelId' => self::$useLegacyId ? $tabData['id'] : "tabber-tabpanel-{$tabData['id']}"
];
}
$templateParser = new TemplateParser( __DIR__ . '/templates' );
return $templateParser->processTemplate( 'Tabber', $data );
}
/**
* Get parsed tab labels
*
* @param string $label tab label wikitext
* @param Parser $parser Mediawiki Parser Object
*
* @return string
*/
private static function getTabLabel( string $label, Parser $parser ): string {
$label = trim( $label );
if ( $label === '' ) {
return '';
}
if ( !self::$parseTabName ) {
// Only plain text is needed
// Use language converter to get variant title and also escape html
$label = $parser->getTargetLanguageConverter()->convertHtml( $label );
} else {
// Might contains HTML
$label = $parser->recursiveTagParseFully( $label );
$label = $parser->stripOuterParagraph( $label );
}
return $label;
}
/**
* Get parsed tab content
*
* @param string $content tab content wikitext
* @param Parser $parser Mediawiki Parser Object
* @param PPFrame $frame Mediawiki PPFrame Object
*
* @return string
*/
private static function getTabContent( string $content, Parser $parser, PPFrame $frame ): string {
$content = trim( $content );
if ( $content === '' ) {
return '';
}
// Insert a new line for these characters in wikitext (#151)
// Seems like there is no way to get rid of the mw-empty-elt paragraphs sadly
$wikitextCharacters = [ '*', '#', ';', ':', '[' ];
$needsNewLine = in_array( substr( $content, 0, 1 ), $wikitextCharacters );
if ( $needsNewLine ) {
$content = "\n$content\n";
}
return $parser->recursiveTagParse( $content, $frame );
}
/**
* Get individual tab data from wikitext.
*
* @param string $tab tab wikitext
* @param int $count Current Tabber count
* @param Parser $parser Mediawiki Parser Object
* @param PPFrame $frame Mediawiki PPFrame Object
*
* @return array
* @throws MWException
*/
private static function getTabData( string $tab, int $count, Parser $parser, PPFrame $frame ): array {
$data = [];
if ( empty( trim( $tab ) ) ) {
return $data;
}
// Use array_pad to make sure at least 2 array values are always returned
[ $label, $content ] = array_pad( explode( '=', $tab, 2 ), 2, '' );
$data['label'] = self::getTabLabel( $label, $parser );
// Label is empty, we cannot generate tabber
if ( $data['label'] === '' ) {
return $data;
}
$data['content'] = self::getTabContent( $content, $parser, $frame );
$isContentHTML = strpos( $content, '<' ) === 0;
if ( $data['content'] && !$isContentHTML ) {
// If $content does not have any HTML element (i.e. just a text node), wrap it in <p/>
$data['content'] = Html::rawElement( 'p', [], $data['content'] );
}
$id = Sanitizer::escapeIdForAttribute( htmlspecialchars( $data['label'] ) );
if ( self::$useLegacyId === true ) {
$parserOutput = $parser->getOutput();
$existingIds = $parserOutput->getExtensionData( 'tabber-ids' ) ?? [];
if ( in_array( $id, $existingIds ) ) {
throw new InvalidArgumentException(
'Duplicated Tabber labels is not allowed with $wgTabberNeueUseLegacyTabIds = true.' .
'Label was: ' . $label
);
}
$parserOutput->appendExtensionData( 'tabber-ids', $id );
} else {
$id = "$id-$count";
}
$data['id'] = $id;
return $data;
}
}