Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
54 / 54 |
Hooks | |
100.00% |
1 / 1 |
|
100.00% |
4 / 4 |
19 | |
100.00% |
54 / 54 |
showError | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
onOutputPageParserOutput | |
100.00% |
1 / 1 |
4 | |
100.00% |
11 / 11 |
|||
onParserFirstCallInit | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
createTagHandler | |
100.00% |
1 / 1 |
13 | |
100.00% |
33 / 33 |
<?php | |
/** | |
* Copyright (C) 2021 Brandon Fowler | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License along | |
* with this program; if not, write to the Free Software Foundation, Inc., | |
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
*/ | |
namespace MediaWiki\Extension\UseResource; | |
use ContentHandler; | |
use CssContent; | |
use Html; | |
use JavaScriptContent; | |
use MediaWiki\Hook\OutputPageParserOutputHook; | |
use MediaWiki\Hook\ParserFirstCallInitHook; | |
use MediaWiki\Revision\SlotRecord; | |
use OutputPage; | |
use Parser; | |
use ParserOutput; | |
use ResourceLoader; | |
use TextContent; | |
use Title; | |
/** | |
* Hook handlers for the UseResource extension | |
*/ | |
class Hooks implements OutputPageParserOutputHook, ParserFirstCallInitHook { | |
/** | |
* Show an error message | |
* @param Parser $parser Current Parser object | |
* @param string $key The key of the message | |
* @param mixed ...$args Message parameters | |
* @return string HTML | |
*/ | |
private static function showError( $parser, $key, ...$args ) { | |
$parser->addTrackingCategory( 'useresource-error-category' ); | |
return Html::rawElement( | |
'strong', | |
[ 'class' => 'error' ], | |
wfMessage( $key, ...$args )->inContentLanguage()->parse() | |
); | |
} | |
/** | |
* Handler for the OutputPageParserOutput hook | |
* @param OutputPage $out | |
* @param ParserOutput $parserOutput | |
*/ | |
public function onOutputPageParserOutput( $out, $parserOutput ): void { | |
$data = $parserOutput->getExtensionData( 'useresource' ); | |
if ( !$data ) { | |
return; | |
} | |
if ( !empty( $data['js'] ) ) { | |
$out->getResourceLoader()->register( 'ext.useresource', [ | |
'class' => Module::class, | |
'code' => $data['js'] | |
] ); | |
$out->addModules( 'ext.useresource' ); | |
} | |
if ( !empty( $data['css'] ) ) { | |
$out->addHeadItem( 'useresource', '<style>' . $data['css'] . '</style>' ); | |
} | |
} | |
/** | |
* Handler for the ParserFirstCallInit hook | |
* @param Parser $parser | |
*/ | |
public function onParserFirstCallInit( $parser ) { | |
$parser->setHook( 'usescript', self::createTagHandler( | |
'js', JavaScriptContent::class, CONTENT_MODEL_JAVASCRIPT, [ '!function(){', '}();' ] | |
) ); | |
$parser->setHook( 'usestyle', self::createTagHandler( | |
'css', CssContent::class, CONTENT_MODEL_CSS, [] | |
) ); | |
} | |
/** | |
* Create a tag handler function | |
* @param string $type The language of the content | |
* @param string $class The required content class, must be a child of TextContent | |
* @param string $model The model id | |
* @param string[] $wrap Two element array with text to wrap around the code | |
* @return callable A callback compatible with Parser::setHook | |
*/ | |
public static function createTagHandler( $type, $class, $model, $wrap ) { | |
return function ( $input, array $args, Parser $parser, $frame ) use ( $type, $class, $model, $wrap ) { | |
if ( !isset( $args['src'] ) || trim( $args['src'] ) === '' ) { | |
return self::showError( $parser, 'useresource-empty-src' ); | |
} | |
$title = Title::newFromText( $args['src'], NS_MEDIAWIKI ); | |
if ( !$title ) { | |
return self::showError( $parser, 'useresource-invalid-title' ); | |
} | |
if ( !$title->inNamespace( NS_MEDIAWIKI ) ) { | |
return self::showError( | |
$parser, | |
'useresource-invalid-namespace', | |
$title->getFullText(), | |
$parser->getContentLanguage()->getFormattedNsText( NS_MEDIAWIKI ) | |
); | |
} | |
$revRecord = $parser->fetchCurrentRevisionRecordOfTitle( $title ); | |
$articleID = $title->getArticleID(); | |
$content = $revRecord ? $revRecord->getContent( SlotRecord::MAIN, $revRecord::RAW ) : null; | |
// Register as a template so the page is re-parsed when the script is edited | |
$parser->getOutput()->addTemplate( $title, $articleID, $revRecord ? $revRecord->getId() : null ); | |
if ( !$content ) { | |
return self::showError( $parser, 'useresource-no-content', $title->getFullText() ); | |
} | |
if ( !is_a( $content, $class ) || !$content instanceof TextContent ) { | |
return self::showError( | |
$parser, | |
'useresource-invalid-content', | |
$title->getFullText(), | |
ContentHandler::getLocalizedName( $model ), | |
ContentHandler::getLocalizedName( $content->getModel() ) | |
); | |
} | |
$data = $parser->getOutput()->getExtensionData( 'useresource' ) ?? [ 'pages' => [] ]; | |
if ( in_array( $articleID, $data['pages'] ) ) { | |
return ''; | |
} | |
$data['pages'][] = $articleID; | |
$text = $content->getText(); | |
if ( $text ) { | |
$text = ResourceLoader::filter( 'minify-' . $type, $text ); | |
$data[$type] = ( $data[$type] ?? '' ) . ( $wrap ? $wrap[0] . $text . $wrap[1] : $text ); | |
} | |
$parser->getOutput()->setExtensionData( 'useresource', $data ); | |
return ''; | |
}; | |
} | |
} |