Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 99 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
Listings | |
0.00% |
0 / 99 |
|
0.00% |
0 / 10 |
2352 | |
0.00% |
0 / 1 |
onParserFirstCallInit | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
buyListings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
doListings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
drinkListings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
eatListings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
otherListings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
seeListings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
sleepListings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getParsedSymbol | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
listingsTag | |
0.00% |
0 / 82 |
|
0.00% |
0 / 1 |
1482 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\Listings; |
4 | |
5 | use MediaWiki\Hook\ParserFirstCallInitHook; |
6 | use MediaWiki\Html\Html; |
7 | use MediaWiki\Parser\Sanitizer; |
8 | use Parser; |
9 | |
10 | class Listings implements ParserFirstCallInitHook { |
11 | |
12 | /** |
13 | * Register parser hooks |
14 | * |
15 | * @param Parser $parser |
16 | */ |
17 | public function onParserFirstCallInit( $parser ) { |
18 | $parser->setHook( 'buy', [ self::class, 'buyListings' ] ); |
19 | $parser->setHook( 'do', [ self::class, 'doListings' ] ); |
20 | $parser->setHook( 'drink', [ self::class, 'drinkListings' ] ); |
21 | $parser->setHook( 'eat', [ self::class, 'eatListings' ] ); |
22 | $parser->setHook( 'listing', [ self::class, 'otherlistings' ] ); |
23 | $parser->setHook( 'see', [ self::class, 'seeListings' ] ); |
24 | $parser->setHook( 'sleep', [ self::class, 'sleepListings' ] ); |
25 | } |
26 | |
27 | /** |
28 | * @param string $input |
29 | * @param array $args |
30 | * @param Parser $parser |
31 | * @return string |
32 | */ |
33 | public static function buyListings( $input, array $args, $parser ) { |
34 | return self::listingsTag( 'buy', $input, $args, $parser ); |
35 | } |
36 | |
37 | /** |
38 | * @param string $input |
39 | * @param array $args |
40 | * @param Parser $parser |
41 | * @return string |
42 | */ |
43 | public static function doListings( $input, array $args, $parser ) { |
44 | return self::listingsTag( 'do', $input, $args, $parser ); |
45 | } |
46 | |
47 | /** |
48 | * @param string $input |
49 | * @param array $args |
50 | * @param Parser $parser |
51 | * @return string |
52 | */ |
53 | public static function drinkListings( $input, array $args, $parser ) { |
54 | return self::listingsTag( 'drink', $input, $args, $parser ); |
55 | } |
56 | |
57 | /** |
58 | * @param string $input |
59 | * @param array $args |
60 | * @param Parser $parser |
61 | * @return string |
62 | */ |
63 | public static function eatListings( $input, array $args, $parser ) { |
64 | return self::listingsTag( 'eat', $input, $args, $parser ); |
65 | } |
66 | |
67 | /** |
68 | * @param string $input |
69 | * @param array $args |
70 | * @param Parser $parser |
71 | * @return string |
72 | */ |
73 | public static function otherListings( $input, array $args, $parser ) { |
74 | return self::listingsTag( 'listing', $input, $args, $parser ); |
75 | } |
76 | |
77 | /** |
78 | * @param string $input |
79 | * @param array $args |
80 | * @param Parser $parser |
81 | * @return string |
82 | */ |
83 | public static function seeListings( $input, array $args, $parser ) { |
84 | return self::listingsTag( 'see', $input, $args, $parser ); |
85 | } |
86 | |
87 | /** |
88 | * @param string $input |
89 | * @param array $args |
90 | * @param Parser $parser |
91 | * @return string |
92 | */ |
93 | public static function sleepListings( $input, array $args, $parser ) { |
94 | return self::listingsTag( 'sleep', $input, $args, $parser ); |
95 | } |
96 | |
97 | /** |
98 | * This method handles messages for phone, fax, tollfree, email |
99 | * and processes the following messages: |
100 | * - listings-phone, listings-phone-symbol |
101 | * - listings-fax, listings-fax-symbol |
102 | * - listings-tollfree, listings-tollfree-symbol |
103 | * - listings-email, listings-email-symbol |
104 | * |
105 | * @param string $symbolType |
106 | * @return string |
107 | */ |
108 | private static function getParsedSymbol( string $symbolType ): string { |
109 | $symbolType = wfMessage( "listings-$symbolType" )->inContentLanguage()->escaped(); |
110 | $symbol = wfMessage( "listings-$symbolType-symbol" )->inContentLanguage()->parse(); |
111 | return $symbol !== '' ? "<abbr title='$symbolType'>$symbol</abbr>" : $symbolType; |
112 | } |
113 | |
114 | /** |
115 | * @param string $aType |
116 | * @param string $input |
117 | * @param array $args |
118 | * @param Parser $parser |
119 | * @return string |
120 | */ |
121 | private static function listingsTag( $aType, $input, $args, $parser ) { |
122 | /* |
123 | * if a {{listings}} template exists, |
124 | * feed tag name and parameter list to template verbatim and exit |
125 | */ |
126 | $listingsTemplate = ''; |
127 | if ( !wfMessage( 'listings-template' )->inContentLanguage()->isDisabled() ) { |
128 | $listingsTemplate = wfMessage( 'listings-template' )->inContentLanguage()->text(); |
129 | } |
130 | if ( $listingsTemplate !== '' ) { |
131 | $inputText = '{{' . $listingsTemplate . '|type=' . $aType; |
132 | foreach ( $args as $key => $value ) { |
133 | $inputText .= '|' . $key . '=' . $value; |
134 | } |
135 | $inputText .= '|' . $input . '}}'; |
136 | return $parser->internalParse( $inputText ); |
137 | } |
138 | |
139 | /* |
140 | * if no pre-defined template exists, generate listing from parameters normally |
141 | */ |
142 | |
143 | // @todo Should the args be made safe HTML? |
144 | |
145 | $position = ''; |
146 | $lat = ( isset( $args['lat'] ) && is_numeric( $args['lat'] ) ) ? $args['lat'] : 361; |
147 | $long = ( isset( $args['long'] ) && is_numeric( $args['long'] ) ) ? $args['long'] : 361; |
148 | // @fixme: incorrect validation |
149 | if ( $lat < 361 && $long < 361 && |
150 | !wfMessage( 'listings-position-template' )->inContentLanguage()->isDisabled() |
151 | ) { |
152 | $positionTemplate = wfMessage( 'listings-position-template', $lat, $long ) |
153 | ->inContentLanguage()->text(); |
154 | if ( $positionTemplate !== '' ) { |
155 | $parsedTemplate = $parser->internalParse( '{{' . $positionTemplate . '}}' ); |
156 | // @todo FIXME: i18n issue (hard coded colon/space) |
157 | $position = wfMessage( 'listings-position' )->inContentLanguage() |
158 | ->rawParams( $parsedTemplate )->escaped(); |
159 | } |
160 | } |
161 | |
162 | // @fixme: a lot of localisation-unfriendly patchwork below |
163 | $name = $args['name'] ?? wfMessage( 'listings-unknown' )->inContentLanguage()->text(); |
164 | $out = Html::element( 'strong', [], $name ); |
165 | |
166 | $url = $args['url'] ?? ''; |
167 | if ( $url !== '' ) { |
168 | $sanitizedHref = Sanitizer::validateAttributes( |
169 | [ 'href' => $url ], |
170 | [ 'href' => true ] |
171 | ); |
172 | if ( isset( $sanitizedHref['href'] ) ) { |
173 | $out = Html::rawElement( 'a', |
174 | $sanitizedHref + [ 'class' => 'external text', 'rel' => 'nofollow', 'title' => $name ], |
175 | $out |
176 | ); |
177 | } |
178 | } |
179 | |
180 | $alt = isset( $args['alt'] ) ? $parser->internalParse( $args['alt'] ) : ''; |
181 | if ( $alt !== '' ) { |
182 | // @todo FIXME: i18n issue (hard coded parentheses) |
183 | $out .= ' (<em>' . $alt . '</em>)'; |
184 | } |
185 | |
186 | $address = isset( $args['address'] ) ? $parser->internalParse( $args['address'] ) : ''; |
187 | $directions = isset( $args['directions'] ) ? $parser->internalParse( $args['directions'] ) : ''; |
188 | if ( ( $address !== '' ) || ( $directions !== '' ) || ( $position !== '' ) ) { |
189 | $out .= ', ' . $address; |
190 | if ( ( $directions !== '' ) || ( $position !== '' ) ) { |
191 | // @todo FIXME: i18n issue (hard coded parentheses) |
192 | $out .= ' (<em>' . $directions; |
193 | if ( ( $directions !== '' ) && ( $position !== '' ) ) { |
194 | // @todo FIXME: i18n issue (hard coded comma list or list to text) |
195 | $out .= ', '; |
196 | } |
197 | if ( $position !== '' ) { |
198 | $out .= $position; |
199 | } |
200 | $out .= '</em>)'; |
201 | } |
202 | } |
203 | |
204 | $phone = $args['phone'] ?? ''; |
205 | $tollFree = $args['tollfree'] ?? ''; |
206 | if ( ( $phone !== '' ) || ( $tollFree !== '' ) ) { |
207 | $phoneSymbol = self::getParsedSymbol( 'phone' ); |
208 | // @todo FIXME: i18n issue (hard coded comma list, space) |
209 | $out .= ', ' . $phoneSymbol . ' ' . htmlspecialchars( $phone ); |
210 | if ( $tollFree !== '' ) { |
211 | $tollFreeSymbol = self::getParsedSymbol( 'tollfree' ); |
212 | // @todo FIXME: i18n issue (hard coded parentheses) |
213 | $out .= ' (' . $tollFreeSymbol . ': ' . htmlspecialchars( $tollFree ) . ')'; |
214 | } |
215 | } |
216 | |
217 | $fax = $args['fax'] ?? ''; |
218 | if ( $fax !== '' ) { |
219 | $faxSymbol = self::getParsedSymbol( 'fax' ); |
220 | // @todo FIXME: i18n issue (hard coded comma list, colon/space) |
221 | $out .= ', ' . $faxSymbol . ': ' . htmlspecialchars( $fax ); |
222 | } |
223 | |
224 | $email = $args['email'] ?? ''; |
225 | if ( $email !== '' ) { |
226 | $emailSymbol = self::getParsedSymbol( 'email' ); |
227 | // @todo FIXME: i18n issue (hard comma list, coded colon/space) |
228 | $out .= ', ' . $emailSymbol . ': ' |
229 | . Html::element( 'a', [ 'class' => 'email', 'href' => "mailto:$email" ], $email ); |
230 | } |
231 | // @todo FIXME: i18n issue (hard coded text) |
232 | $out .= '. '; |
233 | |
234 | $hours = $args['hours'] ?? ''; |
235 | if ( $hours !== '' ) { |
236 | $out .= htmlspecialchars( $hours ) . '. '; |
237 | } |
238 | |
239 | $checkin = $args['checkin'] ?? ''; |
240 | $checkout = $args['checkout'] ?? ''; |
241 | if ( ( $checkin !== '' ) || ( $checkout !== '' ) ) { |
242 | if ( $checkin !== '' ) { |
243 | $out .= wfMessage( 'listings-checkin', $checkin )->inContentLanguage()->escaped(); |
244 | if ( $checkout !== '' ) { |
245 | // @todo FIXME: i18n issue (hard coded comma list) |
246 | $out .= ', '; |
247 | } |
248 | } |
249 | if ( $checkout !== '' ) { |
250 | $out .= wfMessage( 'listings-checkout', $checkout )->inContentLanguage()->escaped(); |
251 | } |
252 | // @todo FIXME: i18n issue (hard coded wut?) |
253 | $out .= '. '; |
254 | } |
255 | |
256 | $price = $args['price'] ?? ''; |
257 | if ( $price !== '' ) { |
258 | // @todo FIXME: i18n issue (hard coded text) |
259 | $out .= htmlspecialchars( $price ) . '. '; |
260 | } |
261 | |
262 | return $out . $parser->internalParse( $input ); |
263 | } |
264 | } |