Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
81.82% |
243 / 297 |
|
44.44% |
12 / 27 |
CRAP | |
0.00% |
0 / 1 |
PageContentHandler | |
81.82% |
243 / 297 |
|
44.44% |
12 / 27 |
105.03 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getContentClass | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
canBeUsedOn | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
serializeContent | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
serializeContentInJson | |
93.75% |
15 / 16 |
|
0.00% |
0 / 1 |
3.00 | |||
serializeContentInWikitext | |
94.12% |
16 / 17 |
|
0.00% |
0 / 1 |
3.00 | |||
unserializeContent | |
66.67% |
6 / 9 |
|
0.00% |
0 / 1 |
5.93 | |||
preSaveTransform | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
1 | |||
supportsPreloadContent | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
preloadTransform | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
1 | |||
unserializeContentInJson | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
3 | |||
unserializeContentInWikitext | |
97.62% |
41 / 42 |
|
0.00% |
0 / 1 |
8 | |||
cleanDeprecatedWrappers | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
5 | |||
getActionOverrides | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getSlotDiffRendererWithOptions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
makeEmptyContent | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
merge3 | |
96.43% |
27 / 28 |
|
0.00% |
0 / 1 |
8 | |||
getAutosummary | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
5 | |||
makeRedirectContent | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
supportsRedirects | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isParserCacheSupported | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSecondaryDataUpdates | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getDeletionUpdates | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getIndexTitle | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
buildIndexQualityStatsUpdate | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
getPageLanguage | |
36.36% |
4 / 11 |
|
0.00% |
0 / 1 |
8.12 | |||
fillParserOutput | |
84.91% |
45 / 53 |
|
0.00% |
0 / 1 |
6.12 |
1 | <?php |
2 | |
3 | namespace ProofreadPage\Page; |
4 | |
5 | use MediaWiki\Category\TrackingCategories; |
6 | use MediaWiki\Content\Content; |
7 | use MediaWiki\Content\Renderer\ContentParseParams; |
8 | use MediaWiki\Content\TextContentHandler; |
9 | use MediaWiki\Content\Transform\PreloadTransformParams; |
10 | use MediaWiki\Content\Transform\PreSaveTransformParams; |
11 | use MediaWiki\Content\WikitextContent; |
12 | use MediaWiki\Content\WikitextContentHandler; |
13 | use MediaWiki\Context\IContextSource; |
14 | use MediaWiki\Html\Html; |
15 | use MediaWiki\MediaWikiServices; |
16 | use MediaWiki\Parser\ParserOutput; |
17 | use MediaWiki\Revision\SlotRenderingProvider; |
18 | use MediaWiki\Title\Title; |
19 | use MWContentSerializationException; |
20 | use ProofreadPage\Context; |
21 | use ProofreadPage\Index\IndexTemplateStyles; |
22 | use ProofreadPage\Index\UpdateIndexQualityStats; |
23 | use ProofreadPage\MultiFormatSerializerUtils; |
24 | use UnexpectedValueException; |
25 | |
26 | /** |
27 | * @license GPL-2.0-or-later |
28 | * |
29 | * Content handler for a Page: pages |
30 | */ |
31 | class PageContentHandler extends TextContentHandler { |
32 | |
33 | use MultiFormatSerializerUtils; |
34 | |
35 | protected WikitextContentHandler $wikitextContentHandler; |
36 | private TrackingCategories $trackingCategories; |
37 | |
38 | /** |
39 | * @param string $modelId |
40 | */ |
41 | public function __construct( $modelId = CONTENT_MODEL_PROOFREAD_PAGE ) { |
42 | parent::__construct( $modelId, [ CONTENT_FORMAT_WIKITEXT, CONTENT_FORMAT_JSON ] ); |
43 | $services = MediaWikiServices::getInstance(); |
44 | $this->wikitextContentHandler = $services->getContentHandlerFactory() |
45 | ->getContentHandler( CONTENT_MODEL_WIKITEXT ); |
46 | $this->trackingCategories = $services->getTrackingCategories(); |
47 | } |
48 | |
49 | /** |
50 | * @return string |
51 | */ |
52 | protected function getContentClass() { |
53 | return PageContent::class; |
54 | } |
55 | |
56 | /** |
57 | * @inheritDoc |
58 | */ |
59 | public function canBeUsedOn( Title $title ) { |
60 | return parent::canBeUsedOn( $title ) && |
61 | $title->getNamespace() === Context::getDefaultContext()->getPageNamespaceId(); |
62 | } |
63 | |
64 | /** |
65 | * @param PageContent $content |
66 | * @param string|null $format |
67 | * @return string |
68 | * @suppress PhanParamSignatureMismatch Intentional mismatching Content |
69 | */ |
70 | public function serializeContent( Content $content, $format = null ) { |
71 | $this->checkFormat( $format ); |
72 | |
73 | switch ( $format ) { |
74 | case CONTENT_FORMAT_JSON: |
75 | return $this->serializeContentInJson( $content ); |
76 | default: |
77 | return $this->serializeContentInWikitext( $content ); |
78 | } |
79 | } |
80 | |
81 | /** |
82 | * @param PageContent $content |
83 | * @return string |
84 | */ |
85 | private function serializeContentInJson( PageContent $content ) { |
86 | $level = $content->getLevel(); |
87 | $user = $level->getUser(); |
88 | |
89 | if ( $user ) { |
90 | if ( $user->isHidden() ) { |
91 | $userName = wfMessage( 'rev-deleted-user' )->inContentLanguage()->text(); |
92 | } else { |
93 | $userName = $user->getName(); |
94 | } |
95 | } else { |
96 | $userName = null; |
97 | } |
98 | |
99 | return json_encode( [ |
100 | 'header' => $content->getHeader()->serialize(), |
101 | 'body' => $content->getBody()->serialize(), |
102 | 'footer' => $content->getFooter()->serialize(), |
103 | 'level' => [ |
104 | 'level' => $level->getLevel(), |
105 | 'user' => $userName |
106 | ] |
107 | ] ); |
108 | } |
109 | |
110 | /** |
111 | * @param PageContent $content |
112 | * @return string |
113 | */ |
114 | private function serializeContentInWikitext( PageContent $content ) { |
115 | $level = $content->getLevel(); |
116 | $user = $level->getUser(); |
117 | |
118 | if ( $user ) { |
119 | if ( $user->isHidden() ) { |
120 | $userName = wfMessage( 'rev-deleted-user' )->inContentLanguage()->text(); |
121 | } else { |
122 | $userName = $user->getName(); |
123 | } |
124 | } else { |
125 | $userName = null; |
126 | } |
127 | |
128 | $text = |
129 | '<noinclude>' . |
130 | '<pagequality level="' . $level->getLevel() . '" user="' . $userName . '" />' . |
131 | $content->getHeader()->serialize() . |
132 | '</noinclude>' . |
133 | $content->getBody()->serialize() . |
134 | '<noinclude>' . |
135 | $content->getFooter()->serialize() . |
136 | '</noinclude>'; |
137 | |
138 | return $text; |
139 | } |
140 | |
141 | /** |
142 | * @param string $text |
143 | * @param string|null $format |
144 | * @return PageContent |
145 | */ |
146 | public function unserializeContent( $text, $format = null ) { |
147 | if ( $format === null ) { |
148 | $format = self::guessDataFormat( $text, true ); |
149 | } |
150 | |
151 | switch ( $format ) { |
152 | case CONTENT_FORMAT_JSON: |
153 | return $this->unserializeContentInJson( $text ); |
154 | case CONTENT_FORMAT_WIKITEXT: |
155 | return $this->unserializeContentInWikitext( $text ); |
156 | default: |
157 | throw new UnexpectedValueException( |
158 | "Format ' . $format . ' is not supported for content model " . $this->getModelID() |
159 | ); |
160 | } |
161 | } |
162 | |
163 | /** |
164 | * @inheritDoc |
165 | */ |
166 | public function preSaveTransform( |
167 | Content $content, |
168 | PreSaveTransformParams $pstParams |
169 | ): Content { |
170 | '@phan-var PageContent $content'; |
171 | |
172 | $contentHandlerFactory = MediaWikiServices::getInstance()->getContentHandlerFactory(); |
173 | $contentClass = $this->getContentClass(); |
174 | $header = $content->getHeader(); |
175 | $body = $content->getBody(); |
176 | $footer = $content->getFooter(); |
177 | |
178 | return new $contentClass( |
179 | $contentHandlerFactory->getContentHandler( $header->getModel() ) |
180 | ->preSaveTransform( $header, $pstParams ), |
181 | $contentHandlerFactory->getContentHandler( $body->getModel() ) |
182 | ->preSaveTransform( $body, $pstParams ), |
183 | $contentHandlerFactory->getContentHandler( $footer->getModel() ) |
184 | ->preSaveTransform( $footer, $pstParams ), |
185 | $content->getLevel() |
186 | ); |
187 | } |
188 | |
189 | /** |
190 | * @inheritDoc |
191 | */ |
192 | public function supportsPreloadContent(): bool { |
193 | return true; |
194 | } |
195 | |
196 | /** |
197 | * @inheritDoc |
198 | */ |
199 | public function preloadTransform( |
200 | Content $content, |
201 | PreloadTransformParams $pltparams |
202 | ): Content { |
203 | '@phan-var PageContent $content'; |
204 | $contentHandlerFactory = MediaWikiServices::getInstance()->getContentHandlerFactory(); |
205 | $contentClass = $this->getContentClass(); |
206 | $header = $content->getHeader(); |
207 | $body = $content->getBody(); |
208 | $footer = $content->getFooter(); |
209 | |
210 | return new $contentClass( |
211 | $contentHandlerFactory->getContentHandler( $header->getModel() ) |
212 | ->preloadTransform( $header, $pltparams ), |
213 | $contentHandlerFactory->getContentHandler( $body->getModel() ) |
214 | ->preloadTransform( $body, $pltparams ), |
215 | $contentHandlerFactory->getContentHandler( $footer->getModel() ) |
216 | ->preloadTransform( $footer, $pltparams ), |
217 | $content->getLevel() |
218 | ); |
219 | } |
220 | |
221 | /** |
222 | * @param string $text |
223 | * @return PageContent |
224 | * @throws MWContentSerializationException |
225 | * @suppress PhanTypeMismatchArgument |
226 | */ |
227 | private function unserializeContentInJson( $text ) { |
228 | $array = json_decode( $text, true ); |
229 | |
230 | if ( !is_array( $array ) ) { |
231 | throw new MWContentSerializationException( |
232 | 'The serialization is an invalid JSON array.' |
233 | ); |
234 | } |
235 | self::assertArrayKeyExistsInSerialization( 'header', $array ); |
236 | self::assertArrayKeyExistsInSerialization( 'body', $array ); |
237 | self::assertArrayKeyExistsInSerialization( 'footer', $array ); |
238 | self::assertArrayKeyExistsInSerialization( 'level', $array ); |
239 | self::assertArrayKeyExistsInSerialization( 'level', $array['level'] ); |
240 | |
241 | $user = array_key_exists( 'user', $array['level'] ) |
242 | ? PageLevel::getUserFromUserName( $array['level']['user'] ) |
243 | : null; |
244 | |
245 | return new PageContent( |
246 | $this->wikitextContentHandler->unserializeContent( $array['header'] ), |
247 | $this->wikitextContentHandler->unserializeContent( $array['body'] ), |
248 | $this->wikitextContentHandler->unserializeContent( $array['footer'] ), |
249 | new PageLevel( $array['level']['level'], $user ) |
250 | ); |
251 | } |
252 | |
253 | /** |
254 | * @param string $text |
255 | * @return PageContent |
256 | * @suppress PhanTypeMismatchArgument |
257 | */ |
258 | private function unserializeContentInWikitext( $text ) { |
259 | $header = ''; |
260 | $footer = ''; |
261 | $proofreader = ''; |
262 | $level = 1; |
263 | |
264 | $cleanHeader = false; |
265 | $cleanBody = false; |
266 | $cleanFooter = false; |
267 | |
268 | if ( preg_match( '/^<noinclude>(.*?)\n*<\/noinclude>(.*)<noinclude>(.*?)<\/noinclude>$/s', |
269 | $text, $m ) |
270 | ) { |
271 | $header = $m[1]; |
272 | $body = $m[2]; |
273 | $footer = $m[3]; |
274 | $cleanFooter = true; |
275 | } elseif ( preg_match( '/^<noinclude>(.*?)\n*<\/noinclude>(.*?)$/s', $text, $m ) ) { |
276 | $header = $m[1]; |
277 | $body = $m[2]; |
278 | $cleanBody = true; |
279 | } else { |
280 | $body = $text; |
281 | } |
282 | |
283 | if ( preg_match( |
284 | '/^<pagequality level="([0-4])" user="(.*?)" *(?:\/>|> *<\/pagequality>)(.*?)$/s', |
285 | $header, $m ) |
286 | ) { |
287 | $level = intval( $m[1] ); |
288 | $proofreader = $m[2]; |
289 | $header = $m[3]; |
290 | $cleanHeader = true; |
291 | } elseif ( |
292 | preg_match( '/^\{\{PageQuality\|([0-4])(?:\|(.*?))?\}\}(.*)/is', $header, $m ) |
293 | ) { |
294 | $level = intval( $m[1] ); |
295 | $proofreader = $m[2]; |
296 | $header = $m[3]; |
297 | $cleanHeader = true; |
298 | } |
299 | |
300 | if ( $cleanHeader ) { |
301 | if ( $cleanFooter ) { |
302 | [ $header, $footer ] = $this->cleanDeprecatedWrappers( $header, $footer ); |
303 | } elseif ( $cleanBody ) { |
304 | [ $header, $body ] = $this->cleanDeprecatedWrappers( $header, $body ); |
305 | } else { |
306 | // notice that second parameter is unused |
307 | [ $header, ] = $this->cleanDeprecatedWrappers( $header, '' ); |
308 | } |
309 | } |
310 | |
311 | return new PageContent( |
312 | $this->wikitextContentHandler->unserializeContent( $header ), |
313 | $this->wikitextContentHandler->unserializeContent( $body ), |
314 | $this->wikitextContentHandler->unserializeContent( $footer ), |
315 | new PageLevel( $level, PageLevel::getUserFromUserName( $proofreader ) ) |
316 | ); |
317 | } |
318 | |
319 | /** |
320 | * @param string $header |
321 | * @param string $footer |
322 | * @return string[] |
323 | */ |
324 | protected function cleanDeprecatedWrappers( $header, $footer ) { |
325 | $cleanedHeader = false; |
326 | if ( preg_match( '/^(.*?)<div class="pagetext">(.*?)$/s', $header, $mt ) ) { |
327 | $header = $mt[2]; |
328 | $cleanedHeader = true; |
329 | } elseif ( preg_match( '/^(.*?)<div>(.*?)$/s', $header, $mt ) ) { |
330 | $header = $mt[2]; |
331 | $cleanedHeader = true; |
332 | } |
333 | |
334 | if ( $cleanedHeader && preg_match( '/^(.*?)<\/div>$/s', $footer, $mt ) ) { |
335 | $footer = $mt[1]; |
336 | } |
337 | |
338 | return [ $header, $footer ]; |
339 | } |
340 | |
341 | /** |
342 | * @inheritDoc |
343 | */ |
344 | public function getActionOverrides() { |
345 | return [ |
346 | 'edit' => PageEditAction::class, |
347 | 'submit' => PageSubmitAction::class, |
348 | 'view' => PageViewAction::class |
349 | ]; |
350 | } |
351 | |
352 | /** |
353 | * @inheritDoc |
354 | */ |
355 | protected function getSlotDiffRendererWithOptions( IContextSource $context, $options = [] ) { |
356 | return new PageSlotDiffRenderer( $context ); |
357 | } |
358 | |
359 | /** |
360 | * @inheritDoc |
361 | * @suppress PhanTypeMismatchArgument |
362 | */ |
363 | public function makeEmptyContent() { |
364 | return new PageContent( |
365 | $this->wikitextContentHandler->makeEmptyContent(), |
366 | $this->wikitextContentHandler->makeEmptyContent(), |
367 | $this->wikitextContentHandler->makeEmptyContent(), |
368 | new PageLevel() |
369 | ); |
370 | } |
371 | |
372 | /** |
373 | * @param PageContent $oldContent |
374 | * @param PageContent $myContent |
375 | * @param PageContent $yourContent |
376 | * @return PageContent|false |
377 | * @suppress PhanParamSignatureMismatch Intentional mismatching Content |
378 | */ |
379 | public function merge3( Content $oldContent, Content $myContent, Content $yourContent ) { |
380 | $this->checkModelID( $oldContent->getModel() ); |
381 | $this->checkModelID( $myContent->getModel() ); |
382 | $this->checkModelID( $yourContent->getModel() ); |
383 | |
384 | if ( $myContent->getLevel()->getLevel() !== $yourContent->getLevel()->getLevel() ) { |
385 | return false; |
386 | } |
387 | |
388 | $wikitextHandler = MediaWikiServices::getInstance() |
389 | ->getContentHandlerFactory() |
390 | ->getContentHandler( CONTENT_MODEL_WIKITEXT ); |
391 | $mergedHeader = $myContent->getHeader()->equals( $yourContent->getHeader() ) |
392 | ? $myContent->getHeader() |
393 | : $wikitextHandler->merge3( |
394 | $oldContent->getHeader(), $myContent->getHeader(), $yourContent->getHeader() |
395 | ); |
396 | $mergedBody = $myContent->getBody()->equals( $yourContent->getBody() ) |
397 | ? $myContent->getBody() |
398 | : $wikitextHandler->merge3( |
399 | $oldContent->getBody(), $myContent->getBody(), $yourContent->getBody() |
400 | ); |
401 | $mergedFooter = $myContent->getFooter()->equals( $yourContent->getFooter() ) |
402 | ? $yourContent->getFooter() |
403 | : $wikitextHandler->merge3( |
404 | $oldContent->getFooter(), $myContent->getFooter(), $yourContent->getFooter() |
405 | ); |
406 | |
407 | if ( !$mergedHeader || !$mergedBody || !$mergedFooter ) { |
408 | return false; |
409 | } |
410 | |
411 | return new PageContent( |
412 | $mergedHeader, $mergedBody, $mergedFooter, $yourContent->getLevel() |
413 | ); |
414 | } |
415 | |
416 | /** |
417 | * @inheritDoc |
418 | */ |
419 | public function getAutosummary( |
420 | ?Content $oldContent = null, ?Content $newContent = null, $flags = 0 |
421 | ) { |
422 | $summary = parent::getAutosummary( $oldContent, $newContent, $flags ); |
423 | |
424 | if ( $newContent instanceof PageContent && |
425 | ( $oldContent === null || ( $oldContent instanceof PageContent && |
426 | !$newContent->getLevel()->equals( $oldContent->getLevel() ) ) ) |
427 | ) { |
428 | $summary = trim( '/* ' . $newContent->getLevel()->getLevelCategoryName() . |
429 | ' */ ' . $summary ); |
430 | } |
431 | |
432 | return $summary; |
433 | } |
434 | |
435 | /** |
436 | * @inheritDoc |
437 | * @todo is it the right content for redirects? |
438 | * @suppress PhanTypeMismatchArgument |
439 | */ |
440 | public function makeRedirectContent( Title $destination, $text = '' ) { |
441 | return new PageContent( |
442 | $this->wikitextContentHandler->makeEmptyContent(), |
443 | $this->wikitextContentHandler->makeRedirectContent( $destination, $text ), |
444 | $this->wikitextContentHandler->makeEmptyContent(), |
445 | new PageLevel() |
446 | ); |
447 | } |
448 | |
449 | /** |
450 | * @inheritDoc |
451 | */ |
452 | public function supportsRedirects() { |
453 | return true; |
454 | } |
455 | |
456 | /** |
457 | * @inheritDoc |
458 | */ |
459 | public function isParserCacheSupported() { |
460 | return true; |
461 | } |
462 | |
463 | /** |
464 | * @inheritDoc |
465 | */ |
466 | public function getSecondaryDataUpdates( |
467 | Title $title, |
468 | Content $content, |
469 | $role, |
470 | SlotRenderingProvider $slotOutput |
471 | ) { |
472 | $updates = parent::getSecondaryDataUpdates( $title, $content, $role, $slotOutput ); |
473 | |
474 | $indexTitle = $this->getIndexTitle( $title ); |
475 | if ( $indexTitle !== null ) { |
476 | $indexTitle->invalidateCache(); |
477 | $updates[] = $this->buildIndexQualityStatsUpdate( $title, $indexTitle, $content ); |
478 | } |
479 | |
480 | return $updates; |
481 | } |
482 | |
483 | /** |
484 | * @inheritDoc |
485 | */ |
486 | public function getDeletionUpdates( Title $title, $role ) { |
487 | $updates = parent::getDeletionUpdates( $title, $role ); |
488 | |
489 | $indexTitle = $this->getIndexTitle( $title ); |
490 | if ( $indexTitle !== null ) { |
491 | $updates[] = $this->buildIndexQualityStatsUpdate( $title, $indexTitle ); |
492 | } |
493 | |
494 | return $updates; |
495 | } |
496 | |
497 | /** |
498 | * @param Title $pageTitle |
499 | * @return Title|null |
500 | */ |
501 | private function getIndexTitle( Title $pageTitle ): ?Title { |
502 | return Context::getDefaultContext()->getIndexForPageLookup()->getIndexForPageTitle( $pageTitle ); |
503 | } |
504 | |
505 | /** |
506 | * @param Title $pageTitle |
507 | * @param Title $indexTitle |
508 | * @param Content|null $pageContent |
509 | * @return UpdateIndexQualityStats |
510 | */ |
511 | private function buildIndexQualityStatsUpdate( |
512 | Title $pageTitle, |
513 | Title $indexTitle, |
514 | ?Content $pageContent = null |
515 | ): UpdateIndexQualityStats { |
516 | $context = Context::getDefaultContext(); |
517 | $newLevel = ( $pageContent instanceof PageContent ) |
518 | ? $pageContent->getLevel()->getLevel() |
519 | : null; |
520 | return new UpdateIndexQualityStats( |
521 | MediaWikiServices::getInstance()->getDBLoadBalancer(), |
522 | $context->getPageQualityLevelLookup(), |
523 | $context->getPaginationFactory()->getPaginationForIndexTitle( $indexTitle ), |
524 | $indexTitle, |
525 | $pageTitle, |
526 | $newLevel |
527 | ); |
528 | } |
529 | |
530 | /** |
531 | * @inheritDoc |
532 | */ |
533 | public function getPageLanguage( Title $title, ?Content $content = null ) { |
534 | $context = Context::getDefaultContext(); |
535 | $indexTitle = $context->getIndexForPageLookup()->getIndexForPageTitle( $title ); |
536 | if ( $indexTitle ) { |
537 | $indexContent = $context->getIndexContentLookup()->getIndexContentForTitle( $indexTitle ); |
538 | $indexLang = $context->getCustomIndexFieldsParser()->getContentLanguage( $indexContent ); |
539 | if ( $indexLang ) { |
540 | // if unrecognized, uses $wgContentLanguage |
541 | $services = MediaWikiServices::getInstance(); |
542 | return $services->getLanguageNameUtils()->isKnownLanguageTag( $indexLang ) ? |
543 | $services->getLanguageFactory()->getLanguage( $indexLang ) : |
544 | $services->getContentLanguage(); |
545 | } |
546 | } |
547 | return parent::getPageLanguage( $title, $content ); |
548 | } |
549 | |
550 | /** |
551 | * @inheritDoc |
552 | */ |
553 | protected function fillParserOutput( |
554 | Content $content, |
555 | ContentParseParams $cpoParams, |
556 | ParserOutput &$parserOutput |
557 | ) { |
558 | '@phan-var PageContent $content'; |
559 | $title = Title::castFromPageReference( $cpoParams->getPage() ); |
560 | '@phan-var Title $title'; |
561 | if ( $content->isRedirect() ) { |
562 | $parserOutput = $this->wikitextContentHandler->getParserOutput( $content->getBody(), $cpoParams ); |
563 | return; |
564 | } |
565 | |
566 | $context = Context::getDefaultContext(); |
567 | $indexTitle = $context->getIndexForPageLookup()->getIndexForPageTitle( $title ); |
568 | |
569 | // create content |
570 | $wikitext = trim( |
571 | $content->getHeader()->getText() |
572 | . "\n\n" |
573 | . $content->getBody()->getText() |
574 | . $content->getFooter()->getText() |
575 | ); |
576 | |
577 | $indexTs = null; |
578 | if ( $indexTitle !== null ) { |
579 | $indexTs = new IndexTemplateStyles( $indexTitle ); |
580 | // newline so that following wikitext that needs to start on a newline |
581 | // like tables, lists, etc, can do so. |
582 | $wikitext = $indexTs->getIndexTemplateStyles( '.pagetext' ) . "\n" . $wikitext; |
583 | } |
584 | $wikitextContent = new WikitextContent( $wikitext ); |
585 | |
586 | $parserOutput = new ParserOutput(); |
587 | $this->wikitextContentHandler->fillParserOutputInternal( $wikitextContent, $cpoParams, $parserOutput ); |
588 | $this->trackingCategories->addTrackingCategory( |
589 | $parserOutput, |
590 | $content->getLevel()->getLevelCategoryKey(), |
591 | $title |
592 | ); |
593 | $parserOutput->setNumericPageProperty( |
594 | 'proofread_page_quality_level', |
595 | $content->getLevel()->getLevel() |
596 | ); |
597 | |
598 | $poText = $parserOutput |
599 | ->runOutputPipeline( $cpoParams->getParserOptions(), [ 'enableSectionEditLinks' => false ] ) |
600 | ->getContentHolderText(); |
601 | |
602 | // html container |
603 | $html = Html::openElement( 'div', |
604 | [ 'class' => 'prp-page-qualityheader quality' . $content->getLevel()->getLevel() ] ) . |
605 | wfMessage( 'proofreadpage_quality' . $content->getLevel()->getLevel() . '_message' ) |
606 | ->title( $title )->inContentLanguage()->parse() . |
607 | Html::closeElement( 'div' ) . |
608 | Html::openElement( 'div', [ 'class' => 'pagetext' ] ) . |
609 | $poText . |
610 | Html::closeElement( 'div' ); |
611 | $parserOutput->setText( $html ); |
612 | |
613 | $pageDisplayHandler = new PageDisplayHandler( $context ); |
614 | $jsVars = $pageDisplayHandler->getPageJsConfigVars( $title, $content ); |
615 | foreach ( $jsVars as $key => $value ) { |
616 | $parserOutput->setJsConfigVar( $key, $value ); |
617 | } |
618 | |
619 | // add modules |
620 | $parserOutput->addModuleStyles( [ 'ext.proofreadpage.base' ] ); |
621 | |
622 | // add scan image to dependencies |
623 | $parserOutput->addImage( strtok( $title->getDBkey(), '/' ) ); |
624 | |
625 | // add the styles.css as a dependency (even if it doesn't exist yet) |
626 | if ( $indexTs !== null ) { |
627 | $stylesPage = $indexTs->getTemplateStylesPage(); |
628 | |
629 | if ( $stylesPage ) { |
630 | $parserOutput->addTemplate( |
631 | $stylesPage, |
632 | $stylesPage->getArticleID(), |
633 | $stylesPage->getLatestRevID() ); |
634 | } |
635 | } |
636 | } |
637 | } |