From c7a8875329494a1f184049c670c05c518af742b2 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Wed, 3 Feb 2010 07:10:58 +0000 Subject: [PATCH] * Fix for r57997 and bug 21222: move math, gallery, pre and nowiki to a new module called CoreTagHooks, analogous to CoreParserFunctions. * Extended the return interface for tag hooks in a way analogous to the one for parser functions, allowing and to specify that they want to be in the nowiki replacement array instead of the general replacement array. * Removed ParserOptions::setUseTeX() and related. If is going to be registered in firstCallInit(), then it needs to be stable across multiple parser calls and not change based on parser options. Only one extension caller. In parserTests.inc: * Fixed parser test failures due to $wgMathDirectory not being properly set up. The math directory of the host wiki was being used, leading to a parser test failure if it was not writable. * Fixed message cache hack from r15502. Made parser tests not fail in the case where a tested message is overwritten by the local wiki. All tests now pass on my installation. --- includes/AutoLoader.php | 1 + includes/parser/CoreTagHooks.php | 49 ++++++++++++++ includes/parser/Parser.php | 108 +++++++++++------------------- includes/parser/ParserOptions.php | 6 +- maintenance/parserTests.inc | 22 +++--- 5 files changed, 102 insertions(+), 84 deletions(-) create mode 100644 includes/parser/CoreTagHooks.php diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index d6288f5db8..c3fe7b1453 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -436,6 +436,7 @@ $wgAutoloadLocalClasses = array( # includes/parser 'CoreLinkFunctions' => 'includes/parser/CoreLinkFunctions.php', 'CoreParserFunctions' => 'includes/parser/CoreParserFunctions.php', + 'CoreTagHooks' => 'includes/parser/CoreTagHooks.php', 'DateFormatter' => 'includes/parser/DateFormatter.php', 'LinkHolderArray' => 'includes/parser/LinkHolderArray.php', 'LinkMarkerReplacer' => 'includes/parser/Parser_LinkHooks.php', diff --git a/includes/parser/CoreTagHooks.php b/includes/parser/CoreTagHooks.php new file mode 100644 index 0000000000..b389e50d16 --- /dev/null +++ b/includes/parser/CoreTagHooks.php @@ -0,0 +1,49 @@ +setHook( 'pre', array( __CLASS__, 'pre' ) ); + $parser->setHook( 'nowiki', array( __CLASS__, 'nowiki' ) ); + $parser->setHook( 'gallery', array( __CLASS__, 'gallery' ) ); + if ( $wgRawHtml ) { + $parser->setHook( 'html', array( __CLASS__, 'html' ) ); + } + if ( $wgUseTeX ) { + $parser->setHook( 'math', array( __CLASS__, 'math' ) ); + } + } + + static function pre( $text, $attribs, $parser ) { + // Backwards-compatibility hack + $content = StringUtils::delimiterReplace( '', '', '$1', $text, 'i' ); + + $attribs = Sanitizer::validateTagAttributes( $attribs, 'pre' ); + return Xml::openElement( 'pre', $attribs ) . + Xml::escapeTagsOnly( $content ) . + ''; + } + + static function html( $content, $attributes, $parser ) { + global $wgRawHtml; + if( $wgRawHtml ) { + return array( $content, 'markerType' => 'nowiki' ); + } else { + throw new MWException( ' extension tag encountered unexpectedly' ); + } + } + + static function nowiki( $content, $attributes, $parser ) { + $content = strtr( $content, array( '-{' => '-{', '}-' => '}-' ) ); + return array( Xml::escapeTagsOnly( $content ), 'markerType' => 'nowiki' ); + } + + static function math( $content, $attributes, $parser ) { + global $wgContLang; + return $output = $wgContLang->armourMath( MathRenderer::renderMath( $content, $attributes ) ); + } + + static function gallery( $content, $attributes, $parser ) { + return $parser->renderImageGallery( $content, $attributes ); + } +} diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index 67ec76088a..a26b49fc9c 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -129,7 +129,7 @@ class Parser $this->mFunctionHooks = array(); $this->mFunctionTagHooks = array(); $this->mFunctionSynonyms = array( 0 => array(), 1 => array() ); - $this->mDefaultStripList = $this->mStripList = array( 'nowiki', 'gallery' ); + $this->mDefaultStripList = $this->mStripList = array(); $this->mUrlProtocols = wfUrlProtocols(); $this->mExtLinkBracketedRegex = '/\[(\b(' . wfUrlProtocols() . ')'. '[^][<>"\\x00-\\x20\\x7F]+) *([^\]\\x0a\\x0d]*?)\]/S'; @@ -172,8 +172,8 @@ class Parser wfProfileIn( __METHOD__ ); - $this->setHook( 'pre', array( $this, 'renderPreTag' ) ); CoreParserFunctions::register( $this ); + CoreTagHooks::register( $this ); $this->initialiseVariables(); wfRunHooks( 'ParserFirstCallInit', array( &$this ) ); @@ -614,15 +614,7 @@ class Parser * Get a list of strippable XML-like elements */ function getStripList() { - global $wgRawHtml; - $elements = $this->mStripList; - if( $wgRawHtml ) { - $elements[] = 'html'; - } - if( $this->mOptions->getUseTeX() ) { - $elements[] = 'math'; - } - return $elements; + return $this->mStripList; } /** @@ -3282,58 +3274,47 @@ class Parser $name = $frame->expand( $params['name'] ); $attrText = !isset( $params['attr'] ) ? null : $frame->expand( $params['attr'] ); $content = !isset( $params['inner'] ) ? null : $frame->expand( $params['inner'] ); - $marker = "{$this->mUniqPrefix}-$name-" . sprintf('%08X', $this->mMarkerIndex++) . self::MARKER_SUFFIX; $isFunctionTag = isset( $this->mFunctionTagHooks[strtolower($name)] ) && ( $this->ot['html'] || $this->ot['pre'] ); + if ( $isFunctionTag ) { + $markerType = 'none'; + } else { + $markerType = 'general'; + } if ( $this->ot['html'] || $isFunctionTag ) { $name = strtolower( $name ); $attributes = Sanitizer::decodeTagAttributes( $attrText ); if ( isset( $params['attributes'] ) ) { $attributes = $attributes + $params['attributes']; } - switch ( $name ) { - case 'html': - if( $wgRawHtml ) { - $output = $content; - break; - } else { - throw new MWException( ' extension tag encountered unexpectedly' ); - } - case 'nowiki': - $content = strtr($content, array('-{' => '-{', '}-' => '}-')); - $output = Xml::escapeTagsOnly( $content ); - break; - case 'gallery': - $output = $this->renderImageGallery( $content, $attributes ); - break; - case 'math': - if ( $this->mOptions->getUseTeX() ) { - $output = $wgContLang->armourMath( - MathRenderer::renderMath( $content, $attributes ) ); - break; - } - /* else let a tag hook handle it (bug 21222) */ - default: - if( isset( $this->mTagHooks[$name] ) ) { - # Workaround for PHP bug 35229 and similar - if ( !is_callable( $this->mTagHooks[$name] ) ) { - throw new MWException( "Tag hook for $name is not callable\n" ); - } - $output = call_user_func_array( $this->mTagHooks[$name], - array( $content, $attributes, $this, $frame ) ); - } elseif( isset( $this->mFunctionTagHooks[$name] ) ) { - list( $callback, $flags ) = $this->mFunctionTagHooks[$name]; - if( !is_callable( $callback ) ) - throw new MWException( "Tag hook for $name is not callable\n" ); - - $output = call_user_func_array( $callback, - array( &$this, $frame, $content, $attributes ) ); - } else { - $output = 'Invalid tag extension name: ' . - htmlspecialchars( $name ) . ''; - } + + if( isset( $this->mTagHooks[$name] ) ) { + # Workaround for PHP bug 35229 and similar + if ( !is_callable( $this->mTagHooks[$name] ) ) { + throw new MWException( "Tag hook for $name is not callable\n" ); + } + $output = call_user_func_array( $this->mTagHooks[$name], + array( $content, $attributes, $this, $frame ) ); + } elseif( isset( $this->mFunctionTagHooks[$name] ) ) { + list( $callback, $flags ) = $this->mFunctionTagHooks[$name]; + if( !is_callable( $callback ) ) + throw new MWException( "Tag hook for $name is not callable\n" ); + + $output = call_user_func_array( $callback, + array( &$this, $frame, $content, $attributes ) ); + } else { + $output = 'Invalid tag extension name: ' . + htmlspecialchars( $name ) . ''; + } + + if ( is_array( $output ) ) { + // Extract flags to local scope (to override $markerType) + $flags = $output; + $output = $flags[0]; + unset( $flags[0] ); + extract( $flags ); } } else { if ( is_null( $attrText ) ) { @@ -3353,12 +3334,14 @@ class Parser } } - if( $isFunctionTag ) { + if( $markerType === 'none' ) { return $output; - } elseif ( $name === 'html' || $name === 'nowiki' ) { + } elseif ( $markerType === 'nowiki' ) { $this->mStripState->nowiki->setPair( $marker, $output ); - } else { + } elseif ( $markerType === 'general' ) { $this->mStripState->general->setPair( $marker, $output ); + } else { + throw new MWException( __METHOD__.': invalid marker type' ); } return $marker; } @@ -4341,19 +4324,6 @@ class Parser return $this->mLinkHolders->replaceText( $text ); } - /** - * Tag hook handler for 'pre'. - */ - function renderPreTag( $text, $attribs ) { - // Backwards-compatibility hack - $content = StringUtils::delimiterReplace( '', '', '$1', $text, 'i' ); - - $attribs = Sanitizer::validateTagAttributes( $attribs, 'pre' ); - return Xml::openElement( 'pre', $attribs ) . - Xml::escapeTagsOnly( $content ) . - ''; - } - /** * Renders an image gallery from a text with one line per image. * text labels may be given by using |-style alternative text. E.g. diff --git a/includes/parser/ParserOptions.php b/includes/parser/ParserOptions.php index 91bd2c4bcb..985bba28ec 100644 --- a/includes/parser/ParserOptions.php +++ b/includes/parser/ParserOptions.php @@ -7,7 +7,6 @@ */ class ParserOptions { # All variables are supposed to be private in theory, although in practise this is not the case. - var $mUseTeX; # Use texvc to expand tags var $mUseDynamicDates; # Use DateFormatter to format dates var $mInterwikiMagic; # Interlanguage links are removed and returned in an array var $mAllowExternalImages; # Allow external images inline @@ -36,7 +35,6 @@ class ParserOptions { var $mIsSectionPreview; # Parsing the page for a "preview" operation on a single section var $mIsPrintable; # Parsing the printable version of the page - function getUseTeX() { return $this->mUseTeX; } function getUseDynamicDates() { return $this->mUseDynamicDates; } function getInterwikiMagic() { return $this->mInterwikiMagic; } function getAllowExternalImages() { return $this->mAllowExternalImages; } @@ -81,7 +79,6 @@ class ParserOptions { return $this->mTimestamp; } - function setUseTeX( $x ) { return wfSetVar( $this->mUseTeX, $x ); } function setUseDynamicDates( $x ) { return wfSetVar( $this->mUseDynamicDates, $x ); } function setInterwikiMagic( $x ) { return wfSetVar( $this->mInterwikiMagic, $x ); } function setAllowExternalImages( $x ) { return wfSetVar( $this->mAllowExternalImages, $x ); } @@ -122,7 +119,7 @@ class ParserOptions { /** Get user options */ function initialiseFromUser( $userInput ) { - global $wgUseTeX, $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages; + global $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages; global $wgAllowExternalImagesFrom, $wgEnableImageWhitelist, $wgAllowSpecialInclusion, $wgMaxArticleSize; global $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth, $wgCleanSignatures; global $wgExternalLinkTarget; @@ -142,7 +139,6 @@ class ParserOptions { $this->mUser = $user; - $this->mUseTeX = $wgUseTeX; $this->mUseDynamicDates = $wgUseDynamicDates; $this->mInterwikiMagic = $wgInterwikiMagic; $this->mAllowExternalImages = $wgAllowExternalImages; diff --git a/maintenance/parserTests.inc b/maintenance/parserTests.inc index 8624dc64cb..26eee2478e 100644 --- a/maintenance/parserTests.inc +++ b/maintenance/parserTests.inc @@ -442,11 +442,6 @@ class ParserTest { $user = new User(); $options = ParserOptions::newFromUser( $user ); - if ( isset( $opts['math'] ) ) { - # XXX this should probably be done by the ParserOptions - $options->setUseTex(true); - } - $m = array(); if (isset( $opts['title'] ) ) { $titleText = $opts['title']; @@ -641,7 +636,8 @@ class ParserTest { 'wgNoFollowDomainExceptions' => array(), 'wgThumbnailScriptPath' => false, 'wgUseImageResize' => false, - 'wgUseTeX' => false, + 'wgUseTeX' => isset( $opts['math'] ), + 'wgMathDirectory' => $this->uploadDir . '/math', 'wgLocaltimezone' => 'UTC', 'wgAllowExternalImages' => true, 'wgUseTidy' => false, @@ -689,8 +685,6 @@ class ParserTest { $GLOBALS['wgMemc'] = new FakeMemCachedClient; $GLOBALS['wgOut'] = new OutputPage; - //$GLOBALS['wgMessageCache'] = new MessageCache( new BagOStuff(), false, 0, $GLOBALS['wgDBname'] ); - MagicWord::clearCache(); global $wgUser; @@ -848,6 +842,10 @@ class ParserTest { # Reinitialise the LocalisationCache to match the database state Language::getLocalisationCache()->unloadAll(); + + # Make a new message cache + global $wgMessageCache, $wgMemc; + $wgMessageCache = new MessageCache( $wgMemc, true, 3600, '' ); } /** @@ -954,6 +952,8 @@ class ParserTest { "$dir/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg", "$dir/0/09/Bad.jpg", + + "$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png", ) ); @@ -969,8 +969,11 @@ class ParserTest { "$dir/0/09/", "$dir/0/", - "$dir/thumb", + "$dir/math/f/a/5", + "$dir/math/f/a", + "$dir/math/f", + "$dir/math", "$dir", ) ); @@ -1122,7 +1125,6 @@ class ParserTest { * @param int $line the input line number, for reporting errors */ private function addArticle($name, $text, $line) { - global $wgMessageCache; $this->setupGlobals(); $title = Title::newFromText( $name ); if ( is_null($title) ) { -- 2.20.1