* Fix for r57997 and bug 21222: move math, gallery, pre and nowiki to a new module...
authorTim Starling <tstarling@users.mediawiki.org>
Wed, 3 Feb 2010 07:10:58 +0000 (07:10 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Wed, 3 Feb 2010 07:10:58 +0000 (07:10 +0000)
* Extended the return interface for tag hooks in a way analogous to the one for parser functions, allowing <nowiki> and <html> to specify that they want to be in the nowiki replacement array instead of the general replacement array.
* Removed ParserOptions::setUseTeX() and related. If <math> 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
includes/parser/CoreTagHooks.php [new file with mode: 0644]
includes/parser/Parser.php
includes/parser/ParserOptions.php
maintenance/parserTests.inc

index d6288f5..c3fe7b1 100644 (file)
@@ -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 (file)
index 0000000..b389e50
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+class CoreTagHooks {
+       static function register( $parser ) {
+               global $wgRawHtml, $wgUseTeX;
+               $parser->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( '<nowiki>', '</nowiki>', '$1', $text, 'i' );
+
+               $attribs = Sanitizer::validateTagAttributes( $attribs, 'pre' );
+               return Xml::openElement( 'pre', $attribs ) .
+                       Xml::escapeTagsOnly( $content ) .
+                       '</pre>';
+       }
+
+       static function html( $content, $attributes, $parser ) {
+               global $wgRawHtml;
+               if( $wgRawHtml ) {
+                       return array( $content, 'markerType' => 'nowiki' );
+               } else {
+                       throw new MWException( '<html> extension tag encountered unexpectedly' );
+               }
+       }
+
+       static function nowiki( $content, $attributes, $parser ) {
+               $content = strtr( $content, array( '-{' => '-&#123;', '}-' => '&#125;-' ) );
+               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 );
+       }
+}
index 67ec760..a26b49f 100644 (file)
@@ -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( '<html> extension tag encountered unexpectedly' );
-                                       }
-                               case 'nowiki':
-                                       $content = strtr($content, array('-{' => '-&#123;', '}-' => '&#125;-'));
-                                       $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 = '<span class="error">Invalid tag extension name: ' .
-                                                       htmlspecialchars( $name ) . '</span>';
-                                       }
+
+                       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 = '<span class="error">Invalid tag extension name: ' .
+                                       htmlspecialchars( $name ) . '</span>';
+                       }
+
+                       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( '<nowiki>', '</nowiki>', '$1', $text, 'i' );
-
-               $attribs = Sanitizer::validateTagAttributes( $attribs, 'pre' );
-               return Xml::openElement( 'pre', $attribs ) .
-                       Xml::escapeTagsOnly( $content ) .
-                       '</pre>';
-       }
-
        /**
         * Renders an image gallery from a text with one line per image.
         * text labels may be given by using |-style alternative text. E.g.
index 91bd2c4..985bba2 100644 (file)
@@ -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 <math> 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;
index 8624dc6..26eee24 100644 (file)
@@ -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) ) {