* 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/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',
--- /dev/null
+<?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( '-{' => '-{', '}-' => '}-' ) );
+ 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 );
+ }
+}
$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';
wfProfileIn( __METHOD__ );
- $this->setHook( 'pre', array( $this, 'renderPreTag' ) );
CoreParserFunctions::register( $this );
+ CoreTagHooks::register( $this );
$this->initialiseVariables();
wfRunHooks( 'ParserFirstCallInit', array( &$this ) );
* 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;
}
/**
$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('-{' => '-{', '}-' => '}-'));
- $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 ) ) {
}
}
- 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;
}
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.
*/
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
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; }
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 ); }
/** 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;
$this->mUser = $user;
- $this->mUseTeX = $wgUseTeX;
$this->mUseDynamicDates = $wgUseDynamicDates;
$this->mInterwikiMagic = $wgInterwikiMagic;
$this->mAllowExternalImages = $wgAllowExternalImages;
$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'];
'wgNoFollowDomainExceptions' => array(),
'wgThumbnailScriptPath' => false,
'wgUseImageResize' => false,
- 'wgUseTeX' => false,
+ 'wgUseTeX' => isset( $opts['math'] ),
+ 'wgMathDirectory' => $this->uploadDir . '/math',
'wgLocaltimezone' => 'UTC',
'wgAllowExternalImages' => true,
'wgUseTidy' => false,
$GLOBALS['wgMemc'] = new FakeMemCachedClient;
$GLOBALS['wgOut'] = new OutputPage;
- //$GLOBALS['wgMessageCache'] = new MessageCache( new BagOStuff(), false, 0, $GLOBALS['wgDBname'] );
-
MagicWord::clearCache();
global $wgUser;
# 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, '' );
}
/**
"$dir/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg",
"$dir/0/09/Bad.jpg",
+
+ "$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png",
)
);
"$dir/0/09/",
"$dir/0/",
-
"$dir/thumb",
+ "$dir/math/f/a/5",
+ "$dir/math/f/a",
+ "$dir/math/f",
+ "$dir/math",
"$dir",
)
);
* @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) ) {