var $mLinkID;
var $mIncludeSizes, $mPPNodeCount, $mGeneratedPPNodeCount, $mHighestExpansionDepth;
var $mDefaultSort;
- var $mTplExpandCache; # empty-frame expansion cache
var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores;
var $mExpensiveFunctionCount; # number of expensive parser function calls
var $mShowToc, $mForceTocPosition;
var $mLangLinkLanguages;
/**
- * Constructor
- *
+ * @var boolean Recursive call protection.
+ * This variable should be treated as if it were private.
+ */
+ public $mInParse = false;
+
+ /**
* @param array $conf
*/
public function __construct( $conf = array() ) {
* Allow extensions to clean up when the parser is cloned
*/
function __clone() {
+ $this->mInParse = false;
wfRunHooks( 'ParserCloned', array( $this ) );
}
$this->mStripState = new StripState( $this->mUniqPrefix );
# Clear these on every parse, bug 4549
- $this->mTplExpandCache = $this->mTplRedirCache = $this->mTplDomCache = array();
+ $this->mTplRedirCache = $this->mTplDomCache = array();
$this->mShowToc = true;
$this->mForceTocPosition = false;
* @param int $revid Number to pass in {{REVISIONID}}
* @return ParserOutput A ParserOutput
*/
- public function parse( $text, Title $title, ParserOptions $options, $linestart = true, $clearState = true, $revid = null ) {
+ public function parse( $text, Title $title, ParserOptions $options,
+ $linestart = true, $clearState = true, $revid = null
+ ) {
/**
* First pass--just handle <nowiki> sections, pass the rest off
* to internalParse() which does all the real work.
wfProfileIn( __METHOD__ );
wfProfileIn( $fname );
+ if ( $clearState ) {
+ $magicScopeVariable = $this->lock();
+ }
+
$this->startParse( $title, $options, self::OT_HTML, $clearState );
$this->mInputSize = strlen( $text );
* If $frame is not provided, then template variables (e.g., {{{1}}}) within $text are not expanded
*
* @param string $text Text extension wants to have parsed
- * @param PPFrame $frame The frame to use for expanding any template variables
+ * @param bool|PPFrame $frame The frame to use for expanding any template variables
*
* @return string
*/
/**
* Expand templates and variables in the text, producing valid, static wikitext.
* Also removes comments.
+ * Do not call this function recursively.
* @param string $text
* @param Title $title
* @param ParserOptions $options
* @param int|null $revid
+ * @param bool|PPFrame $frame
* @return mixed|string
*/
- function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null ) {
+ function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null, $frame = false ) {
wfProfileIn( __METHOD__ );
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, self::OT_PREPROCESS, true );
if ( $revid !== null ) {
$this->mRevisionId = $revid;
}
wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
- $text = $this->replaceVariables( $text );
+ $text = $this->replaceVariables( $text, $frame );
$text = $this->mStripState->unstripBoth( $text );
wfProfileOut( __METHOD__ );
return $text;
* hook.
*
* @param string $text Text to be expanded
- * @param PPFrame $frame The frame to use for expanding any template variables
+ * @param bool|PPFrame $frame The frame to use for expanding any template variables
* @return string
* @since 1.19
*/
$text = $msg->params( $params )->plain();
# Parser (re)initialisation
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, self::OT_PLAIN, true );
$flags = PPFrame::NO_ARGS | PPFrame::NO_TEMPLATES;
array_push( $tr_history, false );
array_push( $td_history, false );
array_push( $last_tag_history, '' );
- } elseif ( $first_character === '|' || $first_character === '!' || substr( $line, 0, 2 ) === '|+' ) {
+ } elseif ( $first_character === '|'
+ || $first_character === '!'
+ || substr( $line, 0, 2 ) === '|+'
+ ) {
# This might be cell elements, td, th or captions
if ( substr( $line, 0, 2 ) === '|+' ) {
$first_character = '+';
}
wfRunHooks( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
- $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ), false, array_keys( $this->mTransparentTagHooks ) );
+ $text = Sanitizer::removeHTMLtags(
+ $text,
+ array( &$this, 'attributeStripCallback' ),
+ false,
+ array_keys( $this->mTransparentTagHooks )
+ );
wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
# Tables need to come after variable replacement for things to work
$bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
if ( $bits === false ) {
wfProfileOut( __METHOD__ );
- throw new MWException( "PCRE needs to be compiled with --enable-unicode-properties in order for MediaWiki to function" );
+ throw new MWException( "PCRE needs to be compiled with "
+ . "--enable-unicode-properties in order for MediaWiki to function" );
}
$s = array_shift( $bits );
/**
* make an image if it's allowed, either through the global
* option, through the exception, or through the on-wiki whitelist
- * @private
*
- * $param string $url
+ * @param string $url
*
* @return string
*/
- function maybeMakeExternalImage( $url ) {
+ private function maybeMakeExternalImage( $url ) {
$imagesfrom = $this->mOptions->getAllowExternalImagesFrom();
$imagesexception = !empty( $imagesfrom );
$text = false;
} else {
$imagematch = false;
}
+
if ( $this->mOptions->getAllowExternalImages()
- || ( $imagesexception && $imagematch ) ) {
+ || ( $imagesexception && $imagematch )
+ ) {
if ( preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
# Image found
$text = Linker::makeExternalImage( $url );
}
}
if ( !$text && $this->mOptions->getEnableImageWhitelist()
- && preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
- $whitelist = explode( "\n", wfMessage( 'external_image_whitelist' )->inContentLanguage()->text() );
+ && preg_match( self::EXT_IMAGE_REGEX, $url )
+ ) {
+ $whitelist = explode(
+ "\n",
+ wfMessage( 'external_image_whitelist' )->inContentLanguage()->text()
+ );
+
foreach ( $whitelist as $entry ) {
# Sanitize the regex fragment, make it case-insensitive, ignore blank entries/comments
if ( strpos( $entry, '#' ) === 0 || $entry === '' ) {
$useSubpages = $this->areSubpagesAllowed();
wfProfileOut( __METHOD__ . '-setup' );
+ // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
# Loop for each link
for ( ; $line !== false && $line !== null; $a->next(), $line = $a->current() ) {
+ // @codingStandardsIgnoreStart
+
# Check for excessive memory usage
if ( $holders->isBig() ) {
# Too big
$m[1] = str_replace( array( '<', '>' ), array( '<', '>' ), rawurldecode( $m[1] ) );
}
$trail = $m[3];
- } elseif ( preg_match( $e1_img, $line, $m ) ) { # Invalid, but might be an image with a link in its caption
+ } elseif ( preg_match( $e1_img, $line, $m ) ) {
+ # Invalid, but might be an image with a link in its caption
$might_be_img = true;
$text = $m[2];
if ( strpos( $m[1], '%' ) !== false ) {
if ( $noforce ) {
# Interwikis
wfProfileIn( __METHOD__ . "-interwiki" );
- if ( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && Language::fetchLanguageName( $iw, null, 'mw' ) ) {
+ if ( $iw && $this->mOptions->getInterwikiMagic()
+ && $nottalk && Language::fetchLanguageName( $iw, null, 'mw' )
+ ) {
// XXX: the above check prevents links to sites with identifiers that are not language codes
# Bug 24502: filter duplicates
$result = $this->closeParagraph();
if ( '*' === $char ) {
- $result .= "<ul>\n<li>";
+ $result .= "<ul><li>";
} elseif ( '#' === $char ) {
- $result .= "<ol>\n<li>";
+ $result .= "<ol><li>";
} elseif ( ':' === $char ) {
- $result .= "<dl>\n<dd>";
+ $result .= "<dl><dd>";
} elseif ( ';' === $char ) {
- $result .= "<dl>\n<dt>";
+ $result .= "<dl><dt>";
$this->mDTopen = true;
} else {
$result = '<!-- ERR 1 -->';
}
/**
- * TODO: document
+ * @todo Document
* @param string $char
* @private
*
*/
function closeList( $char ) {
if ( '*' === $char ) {
- $text = "</li>\n</ul>";
+ $text = "</li></ul>";
} elseif ( '#' === $char ) {
- $text = "</li>\n</ol>";
+ $text = "</li></ol>";
} elseif ( ':' === $char ) {
if ( $this->mDTopen ) {
$this->mDTopen = false;
- $text = "</dt>\n</dl>";
+ $text = "</dt></dl>";
} else {
- $text = "</dd>\n</dl>";
+ $text = "</dd></dl>";
}
} else {
return '<!-- ERR 3 -->';
}
- return $text . "\n";
+ return $text;
}
/**#@-*/
}
# Open prefixes where appropriate.
+ if ( $lastPrefix && $prefixLength > $commonPrefixLength ) {
+ $output .= "\n";
+ }
while ( $prefixLength > $commonPrefixLength ) {
$char = substr( $prefix, $commonPrefixLength, 1 );
$output .= $this->openList( $char );
}
++$commonPrefixLength;
}
+ if ( !$prefixLength && $lastPrefix ) {
+ $output .= "\n";
+ }
$lastPrefix = $prefix2;
}
wfProfileIn( __METHOD__ . "-paragraph" );
# No prefix (not in list)--go to paragraph mode
# XXX: use a stack for nestable elements like span, table and div
- $openmatch = preg_match( '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS', $t );
+ $openmatch = preg_match(
+ '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
+ . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS',
+ $t
+ );
$closematch = preg_match(
- '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|' .
- '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|' . $this->mUniqPrefix . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS', $t );
+ '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
+ . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
+ . $this->mUniqPrefix
+ . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
+ $t
+ );
+
if ( $openmatch or $closematch ) {
$paragraphStack = false;
- # TODO bug 5718: paragraph closed
+ # @todo bug 5718: paragraph closed
$output .= $this->closeParagraph();
if ( $preOpenMatch and !$preCloseMatch ) {
$this->mInPre = true;
}
$inBlockElem = !$closematch;
} elseif ( !$inBlockElem && !$this->mInPre ) {
- if ( ' ' == substr( $t, 0, 1 ) and ( $this->mLastSection === 'pre' || trim( $t ) != '' ) and !$inBlockquote ) {
+ if ( ' ' == substr( $t, 0, 1 )
+ && ( $this->mLastSection === 'pre' || trim( $t ) != '' )
+ && !$inBlockquote
+ ) {
# pre
if ( $this->mLastSection !== 'pre' ) {
$paragraphStack = false;
$this->mInPre = false;
}
if ( $paragraphStack === false ) {
- $output .= $t . "\n";
+ $output .= $t;
+ if ( $prefixLength === 0 ) {
+ $output .= "\n";
+ }
}
}
while ( $prefixLength ) {
$output .= $this->closeList( $prefix2[$prefixLength - 1] );
--$prefixLength;
+ if ( !$prefixLength ) {
+ $output .= "\n";
+ }
}
if ( $this->mLastSection != '' ) {
$output .= '</' . $this->mLastSection . '>';
* @return string
*/
function getVariableValue( $index, $frame = false ) {
- global $wgContLang, $wgSitename, $wgServer;
+ global $wgContLang, $wgSitename, $wgServer, $wgServerName;
global $wgArticlePath, $wgScriptPath, $wgStylePath;
if ( is_null( $this->mTitle ) ) {
$value = wfEscapeWikiText( $this->mTitle->getRootText() );
break;
case 'rootpagenamee':
- $value = wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getRootText() ) ) );
+ $value = wfEscapeWikiText( wfUrlEncode( str_replace(
+ ' ',
+ '_',
+ $this->mTitle->getRootText()
+ ) ) );
break;
case 'basepagename':
$value = wfEscapeWikiText( $this->mTitle->getBaseText() );
break;
case 'basepagenamee':
- $value = wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getBaseText() ) ) );
+ $value = wfEscapeWikiText( wfUrlEncode( str_replace(
+ ' ',
+ '_',
+ $this->mTitle->getBaseText()
+ ) ) );
break;
case 'talkpagename':
if ( $this->mTitle->canTalk() ) {
$value = $this->mTitle->getNamespace();
break;
case 'talkspace':
- $value = $this->mTitle->canTalk() ? str_replace( '_', ' ', $this->mTitle->getTalkNsText() ) : '';
+ $value = $this->mTitle->canTalk()
+ ? str_replace( '_', ' ', $this->mTitle->getTalkNsText() )
+ : '';
break;
case 'talkspacee':
$value = $this->mTitle->canTalk() ? wfUrlencode( $this->mTitle->getTalkNsText() ) : '';
$value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'w' ) );
break;
case 'localdayname':
- $value = $pageLang->getWeekdayName( (int)MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1 );
+ $value = $pageLang->getWeekdayName(
+ (int)MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1
+ );
break;
case 'localyear':
$value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'Y' ), true );
break;
case 'localtime':
- $value = $pageLang->time( MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ), false, false );
+ $value = $pageLang->time(
+ MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ),
+ false,
+ false
+ );
break;
case 'localhour':
$value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'H' ), true );
case 'server':
return $wgServer;
case 'servername':
- $serverParts = wfParseUrl( $wgServer );
- return $serverParts && isset( $serverParts['host'] ) ? $serverParts['host'] : $wgServer;
+ return $wgServerName;
case 'scriptpath':
return $wgScriptPath;
case 'stylepath':
break;
default:
$ret = null;
- wfRunHooks( 'ParserGetVariableValueSwitch', array( &$this, &$this->mVarCache, &$index, &$ret, &$frame ) );
+ wfRunHooks(
+ 'ParserGetVariableValueSwitch',
+ array( &$this, &$this->mVarCache, &$index, &$ret, &$frame )
+ );
+
return $ret;
}
* self::OT_HTML: all templates and extension tags
*
* @param string $text The text to transform
- * @param PPFrame $frame Object describing the arguments passed to the template.
- * Arguments may also be provided as an associative array, as was the usual case before MW1.12.
- * Providing arguments this way may be useful for extensions wishing to perform variable replacement explicitly.
- * @param bool $argsOnly Only do argument (triple-brace) expansion, not double-brace expansion
- * @private
- *
+ * @param bool|PPFrame $frame Object describing the arguments passed to the
+ * template. Arguments may also be provided as an associative array, as
+ * was the usual case before MW1.12. Providing arguments this way may be
+ * useful for extensions wishing to perform variable replacement
+ * explicitly.
+ * @param bool $argsOnly Only do argument (triple-brace) expansion, not
+ * double-brace expansion.
* @return string
*/
- function replaceVariables( $text, $frame = false, $argsOnly = false ) {
+ public function replaceVariables( $text, $frame = false, $argsOnly = false ) {
# Is there any text? Also, Prevent too big inclusions!
if ( strlen( $text ) < 1 || strlen( $text ) > $this->mOptions->getMaxIncludeSize() ) {
return $text;
if ( $frame === false ) {
$frame = $this->getPreprocessor()->newFrame();
} elseif ( !( $frame instanceof PPFrame ) ) {
- wfDebug( __METHOD__ . " called using plain parameters instead of a PPFrame instance. Creating custom frame.\n" );
+ wfDebug( __METHOD__ . " called using plain parameters instead of "
+ . "a PPFrame instance. Creating custom frame.\n" );
$frame = $this->getPreprocessor()->newCustomFrame( $frame );
}
* 'expansion-depth-exceeded' (corresponding messages:
* 'expansion-depth-exceeded-warning',
* 'expansion-depth-exceeded-category')
- * @param int|null $current Current value
- * @param int|null $max Maximum allowed, when an explicit limit has been
+ * @param string|int|null $current Current value
+ * @param string|int|null $max Maximum allowed, when an explicit limit has been
* exceeded, provide the values (optional)
*/
function limitationWarn( $limitationType, $current = '', $max = '' ) {
* replacing any variables or templates within the template.
*
* @param array $piece The parts of the template
- * $piece['title']: the title, i.e. the part before the |
- * $piece['parts']: the parameter array
- * $piece['lineStart']: whether the brace was at the start of a line
+ * $piece['title']: the title, i.e. the part before the |
+ * $piece['parts']: the parameter array
+ * $piece['lineStart']: whether the brace was at the start of a line
* @param PPFrame $frame The current frame, contains template arguments
- * @throws MWException
+ * @throws Exception
* @return string The text of the template
- * @private
*/
- function braceSubstitution( $piece, $frame ) {
+ public function braceSubstitution( $piece, $frame ) {
wfProfileIn( __METHOD__ );
wfProfileIn( __METHOD__ . '-setup' );
- # Flags
- $found = false; # $text has been filled
- $nowiki = false; # wiki markup in $text should be escaped
- $isHTML = false; # $text is HTML, armour it against wikitext transformation
- $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered
- $isChildObj = false; # $text is a DOM node needing expansion in a child frame
- $isLocalObj = false; # $text is a DOM node needing expansion in the current frame
+ // Flags
+
+ // $text has been filled
+ $found = false;
+ // wiki markup in $text should be escaped
+ $nowiki = false;
+ // $text is HTML, armour it against wikitext transformation
+ $isHTML = false;
+ // Force interwiki transclusion to be done in raw mode not rendered
+ $forceRawInterwiki = false;
+ // $text is a DOM node needing expansion in a child frame
+ $isChildObj = false;
+ // $text is a DOM node needing expansion in the current frame
+ $isLocalObj = false;
# Title object, where $text came from
$title = false;
$originalTitle = $part1;
# $args is a list of argument nodes, starting from index 0, not including $part1
- # @todo FIXME: If piece['parts'] is null then the call to getLength() below won't work b/c this $args isn't an object
+ # @todo FIXME: If piece['parts'] is null then the call to getLength()
+ # below won't work b/c this $args isn't an object
$args = ( null == $piece['parts'] ) ? array() : $piece['parts'];
wfProfileOut( __METHOD__ . '-setup' );
// "uselang" will have no effect since the Language object
// is forced to the one defined in ParserOptions.
$pageArgs = array();
- for ( $i = 0; $i < $args->getLength(); $i++ ) {
+ $argsLength = $args->getLength();
+ for ( $i = 0; $i < $argsLength; $i++ ) {
$bits = $args->item( $i )->splitArg();
if ( strval( $bits['index'] ) === '' ) {
$name = trim( $frame->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
$text = $newFrame->expand( $text, PPFrame::RECOVER_ORIG );
} elseif ( $titleText !== false && $newFrame->isEmpty() ) {
# Expansion is eligible for the empty-frame cache
- if ( isset( $this->mTplExpandCache[$titleText] ) ) {
- $text = $this->mTplExpandCache[$titleText];
- } else {
- $text = $newFrame->expand( $text );
- $this->mTplExpandCache[$titleText] = $text;
- }
+ $text = $newFrame->cachedExpand( $titleText, $text );
} else {
# Uncached expansion
$text = $newFrame->expand( $text );
preg_replace( '/^:/', '', $originalTitle );
$text = "[[:$originalTitle]]";
}
- $text .= $this->insertStripItem( '<!-- WARNING: template omitted, post-expand include size too large -->' );
+ $text .= $this->insertStripItem( '<!-- WARNING: template omitted, '
+ . 'post-expand include size too large -->' );
$this->limitationWarn( 'post-expand-template-inclusion' );
}
* @param PPFrame $frame The current frame, contains template arguments
* @param string $function Function name
* @param array $args Arguments to the function
+ * @throws MWException
* @return array
*/
public function callParserFunction( $frame, $function, array $args = array() ) {
* @return array ( string or false, Title )
*/
function fetchTemplateAndTitle( $title ) {
- $templateCb = $this->mOptions->getTemplateCallback(); # Defaults to Parser::statelessFetchTemplate()
+ // Defaults to Parser::statelessFetchTemplate()
+ $templateCb = $this->mOptions->getTemplateCallback();
$stuff = call_user_func( $templateCb, $title, $this );
$text = $stuff['text'];
$finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
* Can be overridden via ParserOptions::setTemplateCallback().
*
* @param Title $title
- * @param Parser $parser
+ * @param bool|Parser $parser
*
* @return array
*/
$status = $req->execute(); // Status object
if ( $status->isOK() ) {
$text = $req->getContent();
- } elseif ( $req->getStatus() != 200 ) { // Though we failed to fetch the content, this status is useless.
- return wfMessage( 'scarytranscludefailed-httpstatus', $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text();
+ } elseif ( $req->getStatus() != 200 ) {
+ // Though we failed to fetch the content, this status is useless.
+ return wfMessage( 'scarytranscludefailed-httpstatus' )
+ ->params( $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text();
} else {
return wfMessage( 'scarytranscludefailed', $url )->inContentLanguage()->text();
}
$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;
+ $marker = "{$this->mUniqPrefix}-$name-"
+ . sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
$isFunctionTag = isset( $this->mFunctionTagHooks[strtolower( $name )] ) &&
( $this->ot['html'] || $this->ot['pre'] );
if ( isset( $this->mDoubleUnderscores['notoc'] ) && !$this->mForceTocPosition ) {
$this->mShowToc = false;
}
- if ( isset( $this->mDoubleUnderscores['hiddencat'] ) && $this->mTitle->getNamespace() == NS_CATEGORY ) {
+ if ( isset( $this->mDoubleUnderscores['hiddencat'] )
+ && $this->mTitle->getNamespace() == NS_CATEGORY
+ ) {
$this->addTrackingCategory( 'hidden-category-category' );
}
# (bug 8068) Allow control over whether robots index a page.
# Get all headlines for numbering them and adding funky stuff like [edit]
# links - this is for later, but we need the number of headlines right now
$matches = array();
- $numMatches = preg_match_all( '/<H(?P<level>[1-6])(?P<attrib>.*?' . '>)\s*(?P<header>[\s\S]*?)\s*<\/H[1-6] *>/i', $text, $matches );
+ $numMatches = preg_match_all(
+ '/<H(?P<level>[1-6])(?P<attrib>.*?' . '>)\s*(?P<header>[\s\S]*?)\s*<\/H[1-6] *>/i',
+ $text,
+ $matches
+ );
# if there are fewer than 4 headlines in the article, do not show TOC
# unless it's been explicitly enabled.
# We strip any parameter from accepted tags (second regex), except dir="rtl|ltr" from <span>,
# to allow setting directionality in toc items.
$tocline = preg_replace(
- array( '#<(?!/?(span|sup|sub|i|b)(?: [^>]*)?>).*?' . '>#', '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|i|b))(?: .*?)?' . '>#' ),
+ array(
+ '#<(?!/?(span|sup|sub|i|b)(?: [^>]*)?>).*?' . '>#',
+ '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|i|b))(?: .*?)?' . '>#'
+ ),
array( '', '<$1>' ),
$safeHeadline
);
# Don't number the heading if it is the only one (looks silly)
if ( count( $matches[3] ) > 1 && $this->mOptions->getNumberHeadings() ) {
# the two are different if the line contains a link
- $headline = Html::element( 'span', array( 'class' => 'mw-headline-number' ), $numbering ) . ' ' . $headline;
+ $headline = Html::element(
+ 'span',
+ array( 'class' => 'mw-headline-number' ),
+ $numbering
+ ) . ' ' . $headline;
}
# Create the anchor for linking from the TOC to the section
# that sections inside <includeonly> should be counted.
$editlinkArgs = array( $titleText, "T-$sectionIndex"/*, null */ );
} else {
- $editlinkArgs = array( $this->mTitle->getPrefixedText(), $sectionIndex, $headlineHint );
+ $editlinkArgs = array(
+ $this->mTitle->getPrefixedText(),
+ $sectionIndex,
+ $headlineHint
+ );
}
- // We use a bit of pesudo-xml for editsection markers. The language converter is run later on
- // Using a UNIQ style marker leads to the converter screwing up the tokens when it converts stuff
- // And trying to insert strip tags fails too. At this point all real inputted tags have already been escaped
- // so we don't have to worry about a user trying to input one of these markers directly.
- // We use a page and section attribute to stop the language converter from converting these important bits
- // of data, but put the headline hint inside a content block because the language converter is supposed to
+ // We use a bit of pesudo-xml for editsection markers. The
+ // language converter is run later on. Using a UNIQ style marker
+ // leads to the converter screwing up the tokens when it
+ // converts stuff. And trying to insert strip tags fails too. At
+ // this point all real inputted tags have already been escaped,
+ // so we don't have to worry about a user trying to input one of
+ // these markers directly. We use a page and section attribute
+ // to stop the language converter from converting these
+ // important bits of data, but put the headline hint inside a
+ // content block because the language converter is supposed to
// be able to convert that piece of data.
$editlink = '<mw:editsection page="' . htmlspecialchars( $editlinkArgs[0] );
$editlink .= '" section="' . htmlspecialchars( $editlinkArgs[1] ) . '"';
* @param bool $clearState Whether to clear the parser state first
* @return string The altered wiki markup
*/
- public function preSaveTransform( $text, Title $title, User $user, ParserOptions $options, $clearState = true ) {
+ public function preSaveTransform( $text, Title $title, User $user,
+ ParserOptions $options, $clearState = true
+ ) {
+ if ( $clearState ) {
+ $magicScopeVariable = $this->lock();
+ }
$this->startParse( $title, $options, self::OT_WIKI, $clearState );
$this->setUser( $user );
$tc = '[' . Title::legalChars() . ']';
$nc = '[ _0-9A-Za-z\x80-\xff-]'; # Namespaces can use non-ascii!
- $p1 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\))\\|]]/"; # [[ns:page (context)|]]
- $p4 = "/\[\[(:?$nc+:|:|)($tc+?)( ?($tc+))\\|]]/"; # [[ns:page(context)|]] (double-width brackets, added in r40257)
- $p3 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\)|)((?:, |,)$tc+|)\\|]]/"; # [[ns:page (context), context|]] (using either single or double-width comma)
- $p2 = "/\[\[\\|($tc+)]]/"; # [[|page]] (reverse pipe trick: add context from page title)
+ // [[ns:page (context)|]]
+ $p1 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\))\\|]]/";
+ // [[ns:page(context)|]] (double-width brackets, added in r40257)
+ $p4 = "/\[\[(:?$nc+:|:|)($tc+?)( ?($tc+))\\|]]/";
+ // [[ns:page (context), context|]] (using either single or double-width comma)
+ $p3 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\)|)((?:, |,)$tc+|)\\|]]/";
+ // [[|page]] (reverse pipe trick: add context from page title)
+ $p2 = "/\[\[\\|($tc+)]]/";
# try $p1 first, to turn "[[A, B (C)|]]" into "[[A, B (C)|A, B]]"
$text = preg_replace( $p1, '[[\\1\\2\\3|\\2]]', $text );
$nickText = wfEscapeWikiText( $nickname );
$msgName = $user->isAnon() ? 'signature-anon' : 'signature';
- return wfMessage( $msgName, $userText, $nickText )->inContentLanguage()->title( $this->getTitle() )->text();
+ return wfMessage( $msgName, $userText, $nickText )->inContentLanguage()
+ ->title( $this->getTitle() )->text();
}
/**
public function cleanSig( $text, $parsing = false ) {
if ( !$parsing ) {
global $wgTitle;
+ $magicScopeVariable = $this->lock();
$this->startParse( $wgTitle, new ParserOptions, self::OT_PREPROCESS, true );
}
* @param int $outputType
* @param bool $clearState
*/
- public function startExternalParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
+ public function startExternalParse( Title $title = null, ParserOptions $options,
+ $outputType, $clearState = true
+ ) {
$this->startParse( $title, $options, $outputType, $clearState );
}
* @param int $outputType
* @param bool $clearState
*/
- private function startParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
+ private function startParse( Title $title = null, ParserOptions $options,
+ $outputType, $clearState = true
+ ) {
$this->setTitle( $title );
$this->mOptions = $options;
$this->setOutputType( $outputType );
/**
* @param string $caption
- * @param LinkHolderArray $holders
+ * @param LinkHolderArray|bool $holders
* @return mixed|string
*/
protected function stripAltText( $caption, $holders ) {
* values, so they can be safely tested and escaped.
*
* @param string $text
- * @param PPFrame $frame
+ * @param bool|PPFrame $frame
* @return string
*/
function attributeStripCallback( &$text, $frame = false ) {
* @return array
*/
function getTags() {
- return array_merge( array_keys( $this->mTransparentTagHooks ), array_keys( $this->mTagHooks ), array_keys( $this->mFunctionTagHooks ) );
+ return array_merge(
+ array_keys( $this->mTransparentTagHooks ),
+ array_keys( $this->mTagHooks ),
+ array_keys( $this->mFunctionTagHooks )
+ );
}
/**
list( $element, $content, $params, $tag ) = $data;
$tagName = strtolower( $element );
if ( isset( $this->mTransparentTagHooks[$tagName] ) ) {
- $output = call_user_func_array( $this->mTransparentTagHooks[$tagName], array( $content, $params, $this ) );
+ $output = call_user_func_array(
+ $this->mTransparentTagHooks[$tagName],
+ array( $content, $params, $this )
+ );
} else {
$output = $tag;
}
*/
private function extractSections( $text, $section, $mode, $newText = '' ) {
global $wgTitle; # not generally used but removes an ugly failure mode
+
+ $magicScopeVariable = $this->lock();
$this->startParse( $wgTitle, new ParserOptions, self::OT_PLAIN, true );
$outText = '';
$frame = $this->getPreprocessor()->newFrame();
* @return string
*/
function testSrvus( $text, Title $title, ParserOptions $options, $outputType = self::OT_HTML ) {
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, $outputType, true );
$text = $this->replaceVariables( $text );
}
return $parsedWidthParam;
}
+
+ /**
+ * Lock the current instance of the parser.
+ *
+ * This is meant to stop someone from calling the parser
+ * recursively and messing up all the strip state.
+ *
+ * @throws MWException If parser is in a parse
+ * @return ScopedCallback The lock will be released once the return value goes out of scope.
+ */
+ protected function lock() {
+ if ( $this->mInParse ) {
+ throw new MWException( "Parser state cleared while parsing. "
+ . "Did you call Parser::parse recursively?" );
+ }
+ $this->mInParse = true;
+
+ $that = $this;
+ $recursiveCheck = new ScopedCallback( function() use ( $that ) {
+ $that->mInParse = false;
+ } );
+
+ return $recursiveCheck;
+ }
+
+ /**
+ * Strip outer <p></p> tag from the HTML source of a single paragraph.
+ *
+ * Returns original HTML if the <p/> tag has any attributes, if there's no wrapping <p/> tag,
+ * or if there is more than one <p/> tag in the input HTML.
+ *
+ * @param string $html
+ * @return string
+ * @since 1.24
+ */
+ public static function stripOuterParagraph( $html ) {
+ $m = array();
+ if ( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $html, $m ) ) {
+ if ( strpos( $m[1], '</p>' ) === false ) {
+ $html = $m[1];
+ }
+ }
+
+ return $html;
+ }
}