* http://www.mediawiki.org/ * * 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. * http://www.gnu.org/copyleft/gpl.html */ /** * Hooks for the Scribunto extension. */ class ScribuntoHooks { /** * Get software information for Special:Version * * @param array &$software * @return bool */ public static function getSoftwareInfo( array &$software ) { $engine = Scribunto::newDefaultEngine(); $engine->setTitle( Title::makeTitle( NS_SPECIAL, 'Version' ) ); $engine->getSoftwareInfo( $software ); return true; } /** * Register parser hooks. * * @param Parser $parser * @return bool */ public static function setupParserHook( Parser &$parser ) { $parser->setFunctionHook( 'invoke', 'ScribuntoHooks::invokeHook', Parser::SFH_OBJECT_ARGS ); return true; } /** * Called when the interpreter is to be reset. * * @param Parser $parser * @return bool */ public static function clearState( Parser &$parser ) { Scribunto::resetParserEngine( $parser ); return true; } /** * Called when the parser is cloned * * @param Parser $parser * @return bool */ public static function parserCloned( Parser $parser ) { $parser->scribunto_engine = null; return true; } /** * Hook function for {{#invoke:module|func}} * * @param Parser $parser * @param PPFrame $frame * @param array $args * @throws MWException * @throws ScribuntoException * @return string */ public static function invokeHook( Parser &$parser, PPFrame $frame, array $args ) { if ( !@constant( get_class( $frame ) . '::SUPPORTS_INDEX_OFFSET' ) ) { throw new MWException( 'Scribunto needs MediaWiki 1.20 or later (Preprocessor::SUPPORTS_INDEX_OFFSET)' ); } try { if ( count( $args ) < 2 ) { throw new ScribuntoException( 'scribunto-common-nofunction' ); } $moduleName = trim( $frame->expand( $args[0] ) ); $engine = Scribunto::getParserEngine( $parser ); $title = Title::makeTitleSafe( NS_MODULE, $moduleName ); if ( !$title || Scribunto::isDocPage( $title ) ) { throw new ScribuntoException( 'scribunto-common-nosuchmodule', array( 'args' => array( $moduleName ) ) ); } $module = $engine->fetchModuleFromParser( $title ); if ( !$module ) { throw new ScribuntoException( 'scribunto-common-nosuchmodule', array( 'args' => array( $moduleName ) ) ); } $functionName = trim( $frame->expand( $args[1] ) ); $bits = $args[1]->splitArg(); unset( $args[0] ); unset( $args[1] ); // If $bits['index'] is empty, then the function name was parsed as a // key=value pair (because of an equals sign in it), and since it didn't // have an index, we don't need the index offset. $childFrame = $frame->newChild( $args, $title, $bits['index'] === '' ? 0 : 1 ); $result = $module->invoke( $functionName, $childFrame ); return UtfNormal::cleanUp( strval( $result ) ); } catch( ScribuntoException $e ) { $trace = $e->getScriptTraceHtml( array( 'msgOptions' => array( 'content' ) ) ); $html = Html::element( 'p', array(), $e->getMessage() ); if ( $trace !== false ) { $html .= Html::element( 'p', array(), wfMessage( 'scribunto-common-backtrace' )->inContentLanguage()->text() ) . $trace; } else { $html .= Html::element( 'p', array(), wfMessage( 'scribunto-common-no-details' )->inContentLanguage()->text() ); } $out = $parser->getOutput(); if ( !isset( $out->scribunto_errors ) ) { $out->addOutputHook( 'ScribuntoError' ); $out->scribunto_errors = array(); $parser->addTrackingCategory( 'scribunto-common-error-category' ); } $out->scribunto_errors[] = $html; $id = 'mw-scribunto-error-' . ( count( $out->scribunto_errors ) - 1 ); $parserError = htmlspecialchars( $e->getMessage() ); // #iferror-compatible error element return "" . $parserError. ""; } } /** * @param Title $title * @param string &$languageCode * @return bool */ public static function getCodeLanguage( Title $title, &$languageCode ) { global $wgScribuntoUseCodeEditor; if( $wgScribuntoUseCodeEditor && $title->getNamespace() == NS_MODULE && !Scribunto::isDocPage( $title ) ) { $engine = Scribunto::newDefaultEngine(); if( $engine->getCodeEditorLanguage() ) { $languageCode = $engine->getCodeEditorLanguage(); return false; } } return true; } /** * Set the Scribunto content handler for modules * * @param Title $title * @param string &$model * @return bool */ public static function contentHandlerDefaultModelFor( Title $title, &$model ) { if( $title->getNamespace() == NS_MODULE && !Scribunto::isDocPage( $title ) ) { $model = 'Scribunto'; return false; } return true; } /** * Adds report of number of evaluations by the single wikitext page. * * @deprecated * @param Parser $parser * @param string $report * @return bool */ public static function reportLimits( Parser $parser, &$report ) { if ( Scribunto::isParserEnginePresent( $parser ) ) { $engine = Scribunto::getParserEngine( $parser ); $report .= $engine->getLimitReport(); } return true; } /** * Adds report of number of evaluations by the single wikitext page. * * @param Parser $parser * @param ParserOutput $output * @return bool */ public static function reportLimitData( Parser $parser, ParserOutput $output ) { // Unhook the deprecated hook, since the new one exists. global $wgHooks; unset( $wgHooks['ParserLimitReport']['scribunto'] ); if ( Scribunto::isParserEnginePresent( $parser ) ) { $engine = Scribunto::getParserEngine( $parser ); $engine->reportLimitData( $output ); } return true; } /** * Formats the limit report data * * @param string $key * @param string &$value * @param string &$report * @param bool $isHTML * @param bool $localize * @return bool */ public static function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) { $engine = Scribunto::newDefaultEngine(); return $engine->formatLimitData( $key, $value, $report, $isHTML, $localize ); } /** * Adds the module namespaces. * * @param string[] $list * @return bool */ public static function addCanonicalNamespaces( array &$list ) { $list[NS_MODULE] = 'Module'; $list[NS_MODULE_TALK] = 'Module_talk'; return true; } /** * EditPageBeforeEditChecks hook * * @param EditPage $editor * @param array $checkboxes Checkbox array * @param int $tabindex Current tabindex * @return bool */ public static function beforeEditChecks( EditPage &$editor, &$checkboxes, &$tabindex ) { if ( $editor->getTitle()->getNamespace() !== NS_MODULE ) { return true; } if ( Scribunto::isDocPage( $editor->getTitle() ) ) { return true; } global $wgOut; $wgOut->addModules( 'ext.scribunto.edit' ); $editor->editFormTextAfterTools = '
'; return true; } /** * EditPageBeforeEditButtons hook * * @param EditPage $editor * @param array $buttons Button array * @param int $tabindex Current tabindex * @return bool */ public static function beforeEditButtons( EditPage &$editor, array &$buttons, &$tabindex ) { if ( $editor->getTitle()->getNamespace() !== NS_MODULE ) { return true; } if ( Scribunto::isDocPage( $editor->getTitle() ) ) { return true; } unset( $buttons['preview'] ); return true; } /** * @param EditPage $editor * @param string $text * @param string $error * @param string $summary * @return bool */ public static function validateScript( EditPage $editor, $text, &$error, $summary ) { global $wgOut; $title = $editor->getTitle(); if( $title->getNamespace() != NS_MODULE ) { return true; } if ( Scribunto::isDocPage( $title ) ) { return true; } $engine = Scribunto::newDefaultEngine(); $engine->setTitle( $title ); $status = $engine->validate( $text, $title->getPrefixedDBkey() ); if( $status->isOK() ) { return true; } $errmsg = $status->getWikiText( 'scribunto-error-short', 'scribunto-error-long' ); $error = <<