2004-02-26 13:37:26 +00:00
|
|
|
|
<?php
|
2004-09-02 23:28:24 +00:00
|
|
|
|
/**
|
2012-04-30 09:22:16 +00:00
|
|
|
|
* PHP parser that converts wiki markup to HTML.
|
|
|
|
|
|
*
|
|
|
|
|
|
* 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
|
2007-05-01 23:41:44 +00:00
|
|
|
|
*
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
|
* @file
|
|
|
|
|
|
* @ingroup Parser
|
2004-09-02 23:28:24 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
2012-04-30 09:22:16 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @defgroup Parser Parser
|
|
|
|
|
|
*/
|
2006-06-02 20:54:34 +00:00
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
|
/**
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* PHP Parser - Processes wiki markup (which uses a more user-friendly
|
2007-04-04 05:22:37 +00:00
|
|
|
|
* syntax, such as "[[link]]" for making links), and provides a one-way
|
|
|
|
|
|
* transformation of that wiki markup it into XHTML output / markup
|
|
|
|
|
|
* (which in turn the browser understands, and can display).
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* There are seven main entry points into the Parser class:
|
|
|
|
|
|
*
|
|
|
|
|
|
* - Parser::parse()
|
2010-03-30 21:53:56 +00:00
|
|
|
|
* produces HTML output
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* - Parser::preSaveTransform().
|
2010-03-30 21:53:56 +00:00
|
|
|
|
* produces altered wiki markup.
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* - Parser::preprocess()
|
2010-03-30 21:53:56 +00:00
|
|
|
|
* removes HTML comments and expands templates
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* - Parser::cleanSig() and Parser::cleanSigInSig()
|
2010-03-30 21:53:56 +00:00
|
|
|
|
* Cleans a signature before saving it to preferences
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* - Parser::getSection()
|
2010-12-26 19:30:10 +00:00
|
|
|
|
* Return the content of a section from an article for section editing
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* - Parser::replaceSection()
|
2010-12-26 19:30:10 +00:00
|
|
|
|
* Replaces a section by number inside an article
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* - Parser::getPreloadText()
|
2010-03-30 21:53:56 +00:00
|
|
|
|
* Removes <noinclude> sections, and <includeonly> tags.
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
|
|
|
|
|
* Globals used:
|
2011-10-19 14:16:01 +00:00
|
|
|
|
* object: $wgContLang
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* @warning $wgUser or $wgTitle or $wgRequest or $wgLang. Keep them away!
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* @par Settings:
|
|
|
|
|
|
* $wgLocaltimezone
|
|
|
|
|
|
* $wgNamespacesWithSubpages
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2012-07-10 15:18:20 +00:00
|
|
|
|
* @par Settings only within ParserOptions:
|
|
|
|
|
|
* $wgAllowExternalImages
|
|
|
|
|
|
* $wgAllowSpecialInclusion
|
|
|
|
|
|
* $wgInterwikiMagic
|
|
|
|
|
|
* $wgMaxArticleSize
|
|
|
|
|
|
* $wgUseDynamicDates
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
|
* @ingroup Parser
|
2004-09-02 23:28:24 +00:00
|
|
|
|
*/
|
2010-03-30 21:20:05 +00:00
|
|
|
|
class Parser {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Update this version number when the ParserOutput format
|
|
|
|
|
|
* changes in an incompatible way, so the parser cache
|
|
|
|
|
|
* can automatically discard old data.
|
|
|
|
|
|
*/
|
2011-09-02 23:14:08 +00:00
|
|
|
|
const VERSION = '1.6.4';
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2011-02-23 06:58:15 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Update this version number when the output of serialiseHalfParsedText()
|
|
|
|
|
|
* changes in an incompatible way
|
|
|
|
|
|
*/
|
|
|
|
|
|
const HALF_PARSED_VERSION = 2;
|
|
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# Flags for Parser::setFunctionHook
|
|
|
|
|
|
# Also available as global constants from Defines.php
|
|
|
|
|
|
const SFH_NO_HASH = 1;
|
|
|
|
|
|
const SFH_OBJECT_ARGS = 2;
|
|
|
|
|
|
|
|
|
|
|
|
# Constants needed for external link processing
|
|
|
|
|
|
# Everything except bracket, space, or control characters
|
2011-07-27 18:03:01 +00:00
|
|
|
|
# \p{Zs} is unicode 'separator, space' category. It covers the space 0x20
|
|
|
|
|
|
# as well as U+3000 is IDEOGRAPHIC SPACE for bug 19052
|
|
|
|
|
|
const EXT_LINK_URL_CLASS = '[^][<>"\\x00-\\x20\\x7F\p{Zs}]';
|
|
|
|
|
|
const EXT_IMAGE_REGEX = '/^(http:\/\/|https:\/\/)([^][<>"\\x00-\\x20\\x7F\p{Zs}]+)
|
|
|
|
|
|
\\/([A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]+)\\.((?i)gif|png|jpg|jpeg)$/Sxu';
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# State constants for the definition list colon extraction
|
2007-11-20 10:55:08 +00:00
|
|
|
|
const COLON_STATE_TEXT = 0;
|
|
|
|
|
|
const COLON_STATE_TAG = 1;
|
|
|
|
|
|
const COLON_STATE_TAGSTART = 2;
|
|
|
|
|
|
const COLON_STATE_CLOSETAG = 3;
|
|
|
|
|
|
const COLON_STATE_TAGSLASH = 4;
|
|
|
|
|
|
const COLON_STATE_COMMENT = 5;
|
|
|
|
|
|
const COLON_STATE_COMMENTDASH = 6;
|
|
|
|
|
|
const COLON_STATE_COMMENTDASHDASH = 7;
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Flags for preprocessToDom
|
2008-01-05 12:39:12 +00:00
|
|
|
|
const PTD_FOR_INCLUSION = 1;
|
2008-01-22 10:47:44 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Allowed values for $this->mOutputType
|
|
|
|
|
|
# Parameter to startExternalParse().
|
|
|
|
|
|
const OT_HTML = 1; # like parse()
|
|
|
|
|
|
const OT_WIKI = 2; # like preSaveTransform()
|
|
|
|
|
|
const OT_PREPROCESS = 3; # like preprocess()
|
2008-01-22 10:47:44 +00:00
|
|
|
|
const OT_MSG = 3;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
const OT_PLAIN = 4; # like extractSections() - portions of the original are returned unchanged.
|
2008-03-27 00:00:25 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Marker Suffix needs to be accessible staticly.
|
2008-03-27 00:00:25 +00:00
|
|
|
|
const MARKER_SUFFIX = "-QINU\x7f";
|
|
|
|
|
|
|
2004-06-12 06:15:09 +00:00
|
|
|
|
# Persistent:
|
2010-12-10 18:48:11 +00:00
|
|
|
|
var $mTagHooks = array();
|
|
|
|
|
|
var $mTransparentTagHooks = array();
|
|
|
|
|
|
var $mFunctionHooks = array();
|
|
|
|
|
|
var $mFunctionSynonyms = array( 0 => array(), 1 => array() );
|
|
|
|
|
|
var $mFunctionTagHooks = array();
|
|
|
|
|
|
var $mStripList = array();
|
|
|
|
|
|
var $mDefaultStripList = array();
|
|
|
|
|
|
var $mVarCache = array();
|
|
|
|
|
|
var $mImageParams = array();
|
|
|
|
|
|
var $mImageParamsMagicArray = array();
|
|
|
|
|
|
var $mMarkerIndex = 0;
|
|
|
|
|
|
var $mFirstCall = true;
|
2011-05-26 19:52:56 +00:00
|
|
|
|
|
|
|
|
|
|
# Initialised by initialiseVariables()
|
2011-05-28 17:18:50 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @var MagicWordArray
|
|
|
|
|
|
*/
|
2011-05-26 19:52:56 +00:00
|
|
|
|
var $mVariables;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @var MagicWordArray
|
|
|
|
|
|
*/
|
|
|
|
|
|
var $mSubstWords;
|
2010-12-10 18:48:11 +00:00
|
|
|
|
var $mConf, $mPreprocessor, $mExtLinkBracketedRegex, $mUrlProtocols; # Initialised in constructor
|
2008-01-22 10:10:21 +00:00
|
|
|
|
|
2004-02-29 08:43:29 +00:00
|
|
|
|
# Cleared with clearState():
|
2011-04-08 23:53:59 +00:00
|
|
|
|
/**
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @var ParserOutput
|
2011-04-08 23:53:59 +00:00
|
|
|
|
*/
|
|
|
|
|
|
var $mOutput;
|
|
|
|
|
|
var $mAutonumber, $mDTopen;
|
2011-02-24 11:59:51 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @var StripState
|
|
|
|
|
|
*/
|
|
|
|
|
|
var $mStripState;
|
|
|
|
|
|
|
2006-07-03 11:07:00 +00:00
|
|
|
|
var $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
|
2011-05-26 19:52:56 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @var LinkHolderArray
|
|
|
|
|
|
*/
|
|
|
|
|
|
var $mLinkHolders;
|
|
|
|
|
|
|
|
|
|
|
|
var $mLinkID;
|
2012-05-04 20:44:14 +00:00
|
|
|
|
var $mIncludeSizes, $mPPNodeCount, $mHighestExpansionDepth, $mDefaultSort;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
var $mTplExpandCache; # empty-frame expansion cache
|
2008-02-20 08:53:12 +00:00
|
|
|
|
var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
var $mExpensiveFunctionCount; # number of expensive parser function calls
|
2011-08-05 00:33:03 +00:00
|
|
|
|
var $mShowToc, $mForceTocPosition;
|
2011-02-27 15:23:41 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @var User
|
|
|
|
|
|
*/
|
2010-12-10 18:17:20 +00:00
|
|
|
|
var $mUser; # User object; only used when doing pre-save transform
|
2004-02-29 08:43:29 +00:00
|
|
|
|
|
2006-02-02 13:42:50 +00:00
|
|
|
|
# Temporary
|
|
|
|
|
|
# These are variables reset at least once per parse regardless of $clearState
|
2011-02-19 01:02:56 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @var ParserOptions
|
|
|
|
|
|
*/
|
|
|
|
|
|
var $mOptions;
|
2011-02-27 15:23:41 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @var Title
|
|
|
|
|
|
*/
|
2010-03-30 21:53:56 +00:00
|
|
|
|
var $mTitle; # Title context, used for self-link rendering and similar things
|
|
|
|
|
|
var $mOutputType; # Output type, one of the OT_xxx constants
|
|
|
|
|
|
var $ot; # Shortcut alias, see setOutputType()
|
2010-12-10 18:17:20 +00:00
|
|
|
|
var $mRevisionObject; # The revision object of the specified revision ID
|
2010-03-30 21:53:56 +00:00
|
|
|
|
var $mRevisionId; # ID to display in {{REVISIONID}} tags
|
|
|
|
|
|
var $mRevisionTimestamp; # The timestamp of the specified revision ID
|
2011-06-03 01:04:24 +00:00
|
|
|
|
var $mRevisionUser; # User to display in {{REVISIONUSER}} tag
|
2010-03-30 21:53:56 +00:00
|
|
|
|
var $mRevIdForTs; # The revision ID which was used to fetch the timestamp
|
2004-02-29 08:43:29 +00:00
|
|
|
|
|
2011-05-28 17:18:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @var string
|
|
|
|
|
|
*/
|
|
|
|
|
|
var $mUniqPrefix;
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Constructor
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $conf array
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2011-04-02 14:48:22 +00:00
|
|
|
|
public function __construct( $conf = array() ) {
|
2008-01-24 04:29:56 +00:00
|
|
|
|
$this->mConf = $conf;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$this->mUrlProtocols = wfUrlProtocols();
|
2012-04-14 17:07:51 +00:00
|
|
|
|
$this->mExtLinkBracketedRegex = '/\[((' . $this->mUrlProtocols . ')'.
|
2011-07-27 18:03:01 +00:00
|
|
|
|
self::EXT_LINK_URL_CLASS.'+)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/Su';
|
2008-01-21 16:36:08 +00:00
|
|
|
|
if ( isset( $conf['preprocessorClass'] ) ) {
|
|
|
|
|
|
$this->mPreprocessorClass = $conf['preprocessorClass'];
|
2011-05-31 06:10:23 +00:00
|
|
|
|
} elseif ( defined( 'MW_COMPILED' ) ) {
|
|
|
|
|
|
# Preprocessor_Hash is much faster than Preprocessor_DOM in compiled mode
|
|
|
|
|
|
$this->mPreprocessorClass = 'Preprocessor_Hash';
|
2008-09-04 06:19:27 +00:00
|
|
|
|
} elseif ( extension_loaded( 'domxml' ) ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# PECL extension that conflicts with the core DOM extension (bug 13770)
|
2008-09-04 06:19:27 +00:00
|
|
|
|
wfDebug( "Warning: you have the obsolete domxml extension for PHP. Please remove it!\n" );
|
|
|
|
|
|
$this->mPreprocessorClass = 'Preprocessor_Hash';
|
2008-08-11 17:24:35 +00:00
|
|
|
|
} elseif ( extension_loaded( 'dom' ) ) {
|
2008-07-07 03:31:00 +00:00
|
|
|
|
$this->mPreprocessorClass = 'Preprocessor_DOM';
|
2008-01-21 16:36:08 +00:00
|
|
|
|
} else {
|
2008-06-10 17:14:36 +00:00
|
|
|
|
$this->mPreprocessorClass = 'Preprocessor_Hash';
|
2008-01-21 16:36:08 +00:00
|
|
|
|
}
|
2011-05-31 06:10:23 +00:00
|
|
|
|
wfDebug( __CLASS__ . ": using preprocessor: {$this->mPreprocessorClass}\n" );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2008-08-26 06:48:24 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Reduce memory usage to reduce the impact of circular references
|
|
|
|
|
|
*/
|
|
|
|
|
|
function __destruct() {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( isset( $this->mLinkHolders ) ) {
|
2011-04-27 20:05:39 +00:00
|
|
|
|
unset( $this->mLinkHolders );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
}
|
2008-08-26 06:48:24 +00:00
|
|
|
|
foreach ( $this as $name => $value ) {
|
|
|
|
|
|
unset( $this->$name );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-07-03 11:07:00 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Do various kinds of initialisation on the first call of the parser
|
|
|
|
|
|
*/
|
|
|
|
|
|
function firstCallInit() {
|
|
|
|
|
|
if ( !$this->mFirstCall ) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2008-01-17 08:58:24 +00:00
|
|
|
|
$this->mFirstCall = false;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2006-07-03 11:07:00 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2008-02-20 08:53:12 +00:00
|
|
|
|
CoreParserFunctions::register( $this );
|
2010-02-03 07:10:58 +00:00
|
|
|
|
CoreTagHooks::register( $this );
|
2006-07-03 11:07:00 +00:00
|
|
|
|
$this->initialiseVariables();
|
2008-01-17 08:58:24 +00:00
|
|
|
|
|
|
|
|
|
|
wfRunHooks( 'ParserFirstCallInit', array( &$this ) );
|
2006-07-03 11:07:00 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-10-17 08:49:27 +00:00
|
|
|
|
}
|
2006-07-03 11:07:00 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Clear Parser state
|
|
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2004-06-12 06:15:09 +00:00
|
|
|
|
function clearState() {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2006-07-03 11:07:00 +00:00
|
|
|
|
if ( $this->mFirstCall ) {
|
|
|
|
|
|
$this->firstCallInit();
|
|
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$this->mOutput = new ParserOutput;
|
2011-02-08 16:32:30 +00:00
|
|
|
|
$this->mOptions->registerWatcher( array( $this->mOutput, 'recordOption' ) );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$this->mAutonumber = 0;
|
2005-01-31 22:59:55 +00:00
|
|
|
|
$this->mLastSection = '';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$this->mDTopen = false;
|
2004-03-20 15:03:26 +00:00
|
|
|
|
$this->mIncludeCount = array();
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$this->mArgStack = false;
|
2004-06-01 22:19:22 +00:00
|
|
|
|
$this->mInPre = false;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$this->mLinkHolders = new LinkHolderArray( $this );
|
|
|
|
|
|
$this->mLinkID = 0;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$this->mRevisionObject = $this->mRevisionTimestamp =
|
|
|
|
|
|
$this->mRevisionId = $this->mRevisionUser = null;
|
2009-10-02 09:09:18 +00:00
|
|
|
|
$this->mVarCache = array();
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$this->mUser = null;
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-05-26 12:11:54 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Prefix for temporary replacement strings for the multipass parser.
|
|
|
|
|
|
* \x07 should never appear in input as it's disallowed in XML.
|
|
|
|
|
|
* Using it at the front also gives us a little extra robustness
|
|
|
|
|
|
* since it shouldn't match when butted up against identifier-like
|
|
|
|
|
|
* string constructs.
|
2007-11-20 10:55:08 +00:00
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* Must not consist of all title characters, or else it will change
|
2007-11-20 10:55:08 +00:00
|
|
|
|
* the behaviour of <nowiki> in a link.
|
2006-05-26 12:11:54 +00:00
|
|
|
|
*/
|
2010-07-25 20:51:16 +00:00
|
|
|
|
$this->mUniqPrefix = "\x7fUNIQ" . self::getRandomString();
|
2011-02-23 06:58:15 +00:00
|
|
|
|
$this->mStripState = new StripState( $this->mUniqPrefix );
|
2005-12-24 23:05:18 +00:00
|
|
|
|
|
2008-02-05 08:23:58 +00:00
|
|
|
|
|
2006-02-02 13:42:50 +00:00
|
|
|
|
# Clear these on every parse, bug 4549
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$this->mTplExpandCache = $this->mTplRedirCache = $this->mTplDomCache = array();
|
2006-02-02 13:42:50 +00:00
|
|
|
|
|
2006-05-23 07:19:01 +00:00
|
|
|
|
$this->mShowToc = true;
|
|
|
|
|
|
$this->mForceTocPosition = false;
|
2006-08-10 21:28:49 +00:00
|
|
|
|
$this->mIncludeSizes = array(
|
|
|
|
|
|
'post-expand' => 0,
|
2007-11-20 10:55:08 +00:00
|
|
|
|
'arg' => 0,
|
2006-08-10 21:28:49 +00:00
|
|
|
|
);
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$this->mPPNodeCount = 0;
|
2012-05-04 20:44:14 +00:00
|
|
|
|
$this->mHighestExpansionDepth = 0;
|
2006-12-29 10:39:35 +00:00
|
|
|
|
$this->mDefaultSort = false;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$this->mHeadings = array();
|
2008-02-20 08:53:12 +00:00
|
|
|
|
$this->mDoubleUnderscores = array();
|
2008-04-07 22:11:31 +00:00
|
|
|
|
$this->mExpensiveFunctionCount = 0;
|
2006-07-02 17:43:32 +00:00
|
|
|
|
|
2008-01-24 04:29:56 +00:00
|
|
|
|
# Fix cloning
|
|
|
|
|
|
if ( isset( $this->mPreprocessor ) && $this->mPreprocessor->parser !== $this ) {
|
|
|
|
|
|
$this->mPreprocessor = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-12-24 23:05:18 +00:00
|
|
|
|
wfRunHooks( 'ParserClearState', array( &$this ) );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2006-01-07 13:09:30 +00:00
|
|
|
|
/**
|
2005-12-30 09:33:11 +00:00
|
|
|
|
* Convert wikitext to HTML
|
|
|
|
|
|
* Do not call this function recursively.
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2008-08-09 13:31:15 +00:00
|
|
|
|
* @param $text String: text we want to parse
|
2011-04-18 12:43:53 +00:00
|
|
|
|
* @param $title Title object
|
2008-08-09 13:31:15 +00:00
|
|
|
|
* @param $options ParserOptions
|
|
|
|
|
|
* @param $linestart boolean
|
|
|
|
|
|
* @param $clearState boolean
|
|
|
|
|
|
* @param $revid Int: number to pass in {{REVISIONID}}
|
2004-09-21 05:49:12 +00:00
|
|
|
|
* @return ParserOutput a ParserOutput
|
|
|
|
|
|
*/
|
2008-08-09 13:31:15 +00:00
|
|
|
|
public function parse( $text, Title $title, ParserOptions $options, $linestart = true, $clearState = true, $revid = null ) {
|
2005-12-30 09:33:11 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* First pass--just handle <nowiki> sections, pass the rest off
|
|
|
|
|
|
* to internalParse() which does all the real work.
|
|
|
|
|
|
*/
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2011-09-22 20:31:23 +00:00
|
|
|
|
global $wgUseTidy, $wgAlwaysUseTidy, $wgDisableLangConversion, $wgDisableTitleConversion;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$fname = __METHOD__.'-' . wfGetCaller();
|
2006-11-12 10:47:10 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
wfProfileIn( $fname );
|
|
|
|
|
|
|
2011-02-22 15:05:08 +00:00
|
|
|
|
$this->startParse( $title, $options, self::OT_HTML, $clearState );
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2012-03-16 00:29:26 +00:00
|
|
|
|
# Remove the strip marker tag prefix from the input, if present.
|
|
|
|
|
|
if ( $clearState ) {
|
|
|
|
|
|
$text = str_replace( $this->mUniqPrefix, '', $text );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-07-10 18:25:56 +00:00
|
|
|
|
$oldRevisionId = $this->mRevisionId;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$oldRevisionObject = $this->mRevisionObject;
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$oldRevisionTimestamp = $this->mRevisionTimestamp;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$oldRevisionUser = $this->mRevisionUser;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $revid !== null ) {
|
2006-07-10 18:25:56 +00:00
|
|
|
|
$this->mRevisionId = $revid;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$this->mRevisionObject = null;
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$this->mRevisionTimestamp = null;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$this->mRevisionUser = null;
|
2006-07-10 18:25:56 +00:00
|
|
|
|
}
|
2011-01-23 16:07:13 +00:00
|
|
|
|
|
2006-11-21 09:53:45 +00:00
|
|
|
|
wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# No more strip!
|
2006-11-21 09:53:45 +00:00
|
|
|
|
wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
|
2005-04-21 06:30:48 +00:00
|
|
|
|
$text = $this->internalParse( $text );
|
2012-06-17 00:34:36 +00:00
|
|
|
|
wfRunHooks( 'ParserAfterParse', array( &$this, &$text, &$this->mStripState ) );
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$text = $this->mStripState->unstripGeneral( $text );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-04-15 14:59:46 +00:00
|
|
|
|
# Clean up special characters, only run once, next-to-last before doBlockLevels
|
2005-04-21 01:33:32 +00:00
|
|
|
|
$fixtags = array(
|
|
|
|
|
|
# french spaces, last one Guillemet-left
|
|
|
|
|
|
# only if there is something before the space
|
2011-08-04 22:20:52 +00:00
|
|
|
|
'/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1 ',
|
2005-04-21 01:33:32 +00:00
|
|
|
|
# french spaces, Guillemet-right
|
2010-05-30 17:33:59 +00:00
|
|
|
|
'/(\\302\\253) /' => '\\1 ',
|
|
|
|
|
|
'/ (!\s*important)/' => ' \\1', # Beware of CSS magic word !important, bug #11874.
|
2005-04-21 01:33:32 +00:00
|
|
|
|
);
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$text = preg_replace( array_keys( $fixtags ), array_values( $fixtags ), $text );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-04-15 14:59:46 +00:00
|
|
|
|
$text = $this->doBlockLevels( $text, $linestart );
|
2004-10-08 04:27:07 +00:00
|
|
|
|
|
2004-10-15 17:39:10 +00:00
|
|
|
|
$this->replaceLinkHolders( $text );
|
2005-04-26 20:50:16 +00:00
|
|
|
|
|
2010-04-09 17:56:42 +00:00
|
|
|
|
/**
|
2011-08-11 19:58:23 +00:00
|
|
|
|
* The input doesn't get language converted if
|
2010-04-09 17:56:42 +00:00
|
|
|
|
* a) It's disabled
|
2010-04-09 19:35:14 +00:00
|
|
|
|
* b) Content isn't converted
|
|
|
|
|
|
* c) It's a conversion table
|
2011-08-11 19:58:23 +00:00
|
|
|
|
* d) it is an interface message (which is in the user language)
|
2010-04-09 17:56:42 +00:00
|
|
|
|
*/
|
2010-01-15 19:14:23 +00:00
|
|
|
|
if ( !( $wgDisableLangConversion
|
2010-04-09 19:02:04 +00:00
|
|
|
|
|| isset( $this->mDoubleUnderscores['nocontentconvert'] )
|
2012-03-05 12:14:53 +00:00
|
|
|
|
|| $this->mTitle->isConversionTable() ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
# Run convert unconditionally in 1.18-compatible mode
|
|
|
|
|
|
global $wgBug34832TransitionalRollback;
|
|
|
|
|
|
if ( $wgBug34832TransitionalRollback || !$this->mOptions->getInterfaceMessage() ) {
|
|
|
|
|
|
# The position of the convert() call should not be changed. it
|
|
|
|
|
|
# assumes that the links are all replaced and the only thing left
|
|
|
|
|
|
# is the <nowiki> mark.
|
|
|
|
|
|
$text = $this->getConverterLanguage()->convert( $text );
|
|
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
}
|
2005-04-26 20:50:16 +00:00
|
|
|
|
|
2010-04-09 19:02:04 +00:00
|
|
|
|
/**
|
2011-01-07 01:38:06 +00:00
|
|
|
|
* A converted title will be provided in the output object if title and
|
2011-02-19 19:18:02 +00:00
|
|
|
|
* content conversion are enabled, the article text does not contain
|
|
|
|
|
|
* a conversion-suppressing double-underscore tag, and no
|
2011-01-07 01:38:06 +00:00
|
|
|
|
* {{DISPLAYTITLE:...}} is present. DISPLAYTITLE takes precedence over
|
|
|
|
|
|
* automatic link conversion.
|
2010-04-09 19:02:04 +00:00
|
|
|
|
*/
|
2010-04-09 20:39:56 +00:00
|
|
|
|
if ( !( $wgDisableLangConversion
|
2010-04-09 19:02:04 +00:00
|
|
|
|
|| $wgDisableTitleConversion
|
|
|
|
|
|
|| isset( $this->mDoubleUnderscores['nocontentconvert'] )
|
|
|
|
|
|
|| isset( $this->mDoubleUnderscores['notitleconvert'] )
|
2010-12-11 03:52:35 +00:00
|
|
|
|
|| $this->mOutput->getDisplayTitle() !== false ) )
|
2010-04-10 13:38:50 +00:00
|
|
|
|
{
|
2012-03-05 12:14:53 +00:00
|
|
|
|
$convruletitle = $this->getConverterLanguage()->getConvRuleTitle();
|
2010-04-09 19:02:04 +00:00
|
|
|
|
if ( $convruletitle ) {
|
|
|
|
|
|
$this->mOutput->setTitleText( $convruletitle );
|
2010-04-09 20:27:57 +00:00
|
|
|
|
} else {
|
2012-03-05 12:14:53 +00:00
|
|
|
|
$titleText = $this->getConverterLanguage()->convertTitle( $title );
|
2010-04-10 13:38:50 +00:00
|
|
|
|
$this->mOutput->setTitleText( $titleText );
|
2010-04-09 19:02:04 +00:00
|
|
|
|
}
|
2010-01-08 08:22:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$text = $this->mStripState->unstripNoWiki( $text );
|
2005-07-02 09:15:51 +00:00
|
|
|
|
|
|
|
|
|
|
wfRunHooks( 'ParserBeforeTidy', array( &$this, &$text ) );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2011-02-23 06:58:15 +00:00
|
|
|
|
$text = $this->replaceTransparentTags( $text );
|
2010-02-13 14:41:04 +00:00
|
|
|
|
$text = $this->mStripState->unstripGeneral( $text );
|
|
|
|
|
|
|
2005-04-21 11:40:58 +00:00
|
|
|
|
$text = Sanitizer::normalizeCharReferences( $text );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2010-08-05 19:01:47 +00:00
|
|
|
|
if ( ( $wgUseTidy && $this->mOptions->getTidy() ) || $wgAlwaysUseTidy ) {
|
2009-01-27 15:20:31 +00:00
|
|
|
|
$text = MWTidy::tidy( $text );
|
2006-03-24 16:36:29 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
# attempt to sanitize at least some nesting problems
|
|
|
|
|
|
# (bug #2702 and quite a few others)
|
2006-07-11 17:40:11 +00:00
|
|
|
|
$tidyregs = array(
|
|
|
|
|
|
# ''Something [http://www.cool.com cool''] -->
|
2006-03-24 16:36:29 +00:00
|
|
|
|
# <i>Something</i><a href="http://www.cool.com"..><i>cool></i></a>
|
|
|
|
|
|
'/(<([bi])>)(<([bi])>)?([^<]*)(<\/?a[^<]*>)([^<]*)(<\/\\4>)?(<\/\\2>)/' =>
|
|
|
|
|
|
'\\1\\3\\5\\8\\9\\6\\1\\3\\7\\8\\9',
|
|
|
|
|
|
# fix up an anchor inside another anchor, only
|
|
|
|
|
|
# at least for a single single nested link (bug 3695)
|
|
|
|
|
|
'/(<a[^>]+>)([^<]*)(<a[^>]+>[^<]*)<\/a>(.*)<\/a>/' =>
|
|
|
|
|
|
'\\1\\2</a>\\3</a>\\1\\4</a>',
|
|
|
|
|
|
# fix div inside inline elements- doBlockLevels won't wrap a line which
|
|
|
|
|
|
# contains a div, so fix it up here; replace
|
|
|
|
|
|
# div with escaped text
|
|
|
|
|
|
'/(<([aib]) [^>]+>)([^<]*)(<div([^>]*)>)(.*)(<\/div>)([^<]*)(<\/\\2>)/' =>
|
|
|
|
|
|
'\\1\\3<div\\5>\\6</div>\\8\\9',
|
|
|
|
|
|
# remove empty italic or bold tag pairs, some
|
|
|
|
|
|
# introduced by rules above
|
2006-07-11 17:40:11 +00:00
|
|
|
|
'/<([bi])><\/\\1>/' => '',
|
2006-03-24 16:36:29 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
2006-07-11 17:40:11 +00:00
|
|
|
|
$text = preg_replace(
|
2006-03-24 16:36:29 +00:00
|
|
|
|
array_keys( $tidyregs ),
|
|
|
|
|
|
array_values( $tidyregs ),
|
|
|
|
|
|
$text );
|
2004-10-15 17:39:10 +00:00
|
|
|
|
}
|
2012-05-04 18:56:28 +00:00
|
|
|
|
|
|
|
|
|
|
if ( $this->mExpensiveFunctionCount > $this->mOptions->getExpensiveParserFunctionLimit() ) {
|
|
|
|
|
|
$this->limitationWarn( 'expensive-parserfunction',
|
|
|
|
|
|
$this->mExpensiveFunctionCount,
|
|
|
|
|
|
$this->mOptions->getExpensiveParserFunctionLimit()
|
|
|
|
|
|
);
|
2008-04-07 22:11:31 +00:00
|
|
|
|
}
|
2004-10-15 17:39:10 +00:00
|
|
|
|
|
2005-07-02 09:15:51 +00:00
|
|
|
|
wfRunHooks( 'ParserAfterTidy', array( &$this, &$text ) );
|
|
|
|
|
|
|
2006-08-10 21:28:49 +00:00
|
|
|
|
# Information on include size limits, for the benefit of users who try to skirt them
|
2007-11-30 14:50:48 +00:00
|
|
|
|
if ( $this->mOptions->getEnableLimitReport() ) {
|
2006-08-10 21:28:49 +00:00
|
|
|
|
$max = $this->mOptions->getMaxIncludeSize();
|
2012-05-04 18:56:28 +00:00
|
|
|
|
$PFreport = "Expensive parser function count: {$this->mExpensiveFunctionCount}/{$this->mOptions->getExpensiveParserFunctionLimit()}\n";
|
2008-04-14 07:45:50 +00:00
|
|
|
|
$limitReport =
|
|
|
|
|
|
"NewPP limit report\n" .
|
2010-08-05 19:01:47 +00:00
|
|
|
|
"Preprocessor node count: {$this->mPPNodeCount}/{$this->mOptions->getMaxPPNodeCount()}\n" .
|
2007-11-30 14:50:48 +00:00
|
|
|
|
"Post-expand include size: {$this->mIncludeSizes['post-expand']}/$max bytes\n" .
|
2008-04-07 22:11:31 +00:00
|
|
|
|
"Template argument size: {$this->mIncludeSizes['arg']}/$max bytes\n".
|
2012-05-04 20:44:14 +00:00
|
|
|
|
"Highest expansion depth: {$this->mHighestExpansionDepth}/{$this->mOptions->getMaxPPExpandDepth()}\n".
|
2008-04-07 22:11:31 +00:00
|
|
|
|
$PFreport;
|
2007-11-30 14:50:48 +00:00
|
|
|
|
wfRunHooks( 'ParserLimitReport', array( $this, &$limitReport ) );
|
|
|
|
|
|
$text .= "\n<!-- \n$limitReport-->\n";
|
2006-08-10 21:28:49 +00:00
|
|
|
|
}
|
2004-03-06 01:49:16 +00:00
|
|
|
|
$this->mOutput->setText( $text );
|
2010-01-15 19:14:23 +00:00
|
|
|
|
|
2006-07-10 18:25:56 +00:00
|
|
|
|
$this->mRevisionId = $oldRevisionId;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$this->mRevisionObject = $oldRevisionObject;
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$this->mRevisionTimestamp = $oldRevisionTimestamp;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$this->mRevisionUser = $oldRevisionUser;
|
2004-03-06 01:49:16 +00:00
|
|
|
|
wfProfileOut( $fname );
|
2006-11-12 10:47:10 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2005-12-30 09:33:11 +00:00
|
|
|
|
|
2004-03-06 01:49:16 +00:00
|
|
|
|
return $this->mOutput;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-08-06 14:01:47 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Recursive parser entry point that can be called from an extension tag
|
|
|
|
|
|
* hook.
|
2009-08-30 06:37:10 +00:00
|
|
|
|
*
|
|
|
|
|
|
* If $frame is not provided, then template variables (e.g., {{{1}}}) within $text are not expanded
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $text String: text extension wants to have parsed
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $frame PPFrame: The frame to use for expanding any template variables
|
2011-06-23 09:26:48 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2006-08-06 14:01:47 +00:00
|
|
|
|
*/
|
2009-08-30 06:37:10 +00:00
|
|
|
|
function recursiveTagParse( $text, $frame=false ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2006-11-23 08:25:56 +00:00
|
|
|
|
wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
|
|
|
|
|
|
wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
|
2009-08-30 06:37:10 +00:00
|
|
|
|
$text = $this->internalParse( $text, false, $frame );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-08-14 07:10:31 +00:00
|
|
|
|
/**
|
2006-08-15 02:24:59 +00:00
|
|
|
|
* Expand templates and variables in the text, producing valid, static wikitext.
|
|
|
|
|
|
* Also removes comments.
|
2012-02-09 21:35:05 +00:00
|
|
|
|
* @return mixed|string
|
2006-08-14 07:10:31 +00:00
|
|
|
|
*/
|
2011-01-26 00:23:39 +00:00
|
|
|
|
function preprocess( $text, Title $title, ParserOptions $options, $revid = null ) {
|
2006-08-14 07:10:31 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2011-02-22 15:05:08 +00:00
|
|
|
|
$this->startParse( $title, $options, self::OT_PREPROCESS, true );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $revid !== null ) {
|
2007-05-31 16:01:26 +00:00
|
|
|
|
$this->mRevisionId = $revid;
|
|
|
|
|
|
}
|
2006-11-21 09:53:45 +00:00
|
|
|
|
wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
|
|
|
|
|
|
wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = $this->replaceVariables( $text );
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$text = $this->mStripState->unstripBoth( $text );
|
2006-08-14 07:10:31 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-08-14 20:22:52 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Recursive parser entry point that can be called from an extension tag
|
|
|
|
|
|
* hook.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $text String: text to be expanded
|
|
|
|
|
|
* @param $frame PPFrame: The frame to use for expanding any template variables
|
|
|
|
|
|
* @return String
|
2012-01-09 19:11:55 +00:00
|
|
|
|
* @since 1.19
|
2011-08-14 20:22:52 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function recursivePreprocess( $text, $frame = false ) {
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
$text = $this->replaceVariables( $text, $frame );
|
|
|
|
|
|
$text = $this->mStripState->unstripBoth( $text );
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-03 02:41:14 +00:00
|
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* Process the wikitext for the "?preload=" feature. (bug 5210)
|
2010-03-03 02:41:14 +00:00
|
|
|
|
*
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* "<noinclude>", "<includeonly>" etc. are parsed as for template
|
|
|
|
|
|
* transclusion, comments, templates, arguments, tags hooks and parser
|
|
|
|
|
|
* functions are untouched.
|
2011-09-11 21:07:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @param $title Title
|
|
|
|
|
|
* @param $options ParserOptions
|
|
|
|
|
|
* @return String
|
2010-03-03 02:41:14 +00:00
|
|
|
|
*/
|
2011-01-26 00:23:39 +00:00
|
|
|
|
public function getPreloadText( $text, Title $title, ParserOptions $options ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Parser (re)initialisation
|
2011-02-22 15:05:08 +00:00
|
|
|
|
$this->startParse( $title, $options, self::OT_PLAIN, true );
|
2010-03-03 02:41:14 +00:00
|
|
|
|
|
|
|
|
|
|
$flags = PPFrame::NO_ARGS | PPFrame::NO_TEMPLATES;
|
|
|
|
|
|
$dom = $this->preprocessToDom( $text, self::PTD_FOR_INCLUSION );
|
2011-02-19 19:18:02 +00:00
|
|
|
|
$text = $this->getPreprocessor()->newFrame()->expand( $dom, $flags );
|
|
|
|
|
|
$text = $this->mStripState->unstripBoth( $text );
|
|
|
|
|
|
return $text;
|
2010-03-03 02:41:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get a random string
|
2011-05-28 17:18:50 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2011-02-23 23:42:04 +00:00
|
|
|
|
static public function getRandomString() {
|
2012-03-20 05:17:40 +00:00
|
|
|
|
return wfRandomString( 16 );
|
2004-03-06 01:49:16 +00:00
|
|
|
|
}
|
2004-03-26 17:14:23 +00:00
|
|
|
|
|
2010-12-10 18:17:20 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Set the current user.
|
|
|
|
|
|
* Should only be used when doing pre-save transform.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $user Mixed: User object or null (to reset)
|
|
|
|
|
|
*/
|
|
|
|
|
|
function setUser( $user ) {
|
|
|
|
|
|
$this->mUser = $user;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-06-10 21:05:58 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Accessor for mUniqPrefix.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return String
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function uniqPrefix() {
|
|
|
|
|
|
if ( !isset( $this->mUniqPrefix ) ) {
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: This is probably *horribly wrong*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
# LanguageConverter seems to want $wgParser's uniqPrefix, however
|
|
|
|
|
|
# if this is called for a parser cache hit, the parser may not
|
|
|
|
|
|
# have ever been initialized in the first place.
|
|
|
|
|
|
# Not really sure what the heck is supposed to be going on here.
|
|
|
|
|
|
return '';
|
|
|
|
|
|
# throw new MWException( "Accessing uninitialized mUniqPrefix" );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $this->mUniqPrefix;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Set the context title
|
2011-05-28 17:18:50 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $t Title
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function setTitle( $t ) {
|
2010-12-11 03:52:35 +00:00
|
|
|
|
if ( !$t || $t instanceof FakeTitle ) {
|
|
|
|
|
|
$t = Title::newFromText( 'NO TITLE' );
|
|
|
|
|
|
}
|
2010-06-10 21:05:58 +00:00
|
|
|
|
|
|
|
|
|
|
if ( strval( $t->getFragment() ) !== '' ) {
|
|
|
|
|
|
# Strip the fragment to avoid various odd effects
|
|
|
|
|
|
$this->mTitle = clone $t;
|
|
|
|
|
|
$this->mTitle->setFragment( '' );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$this->mTitle = $t;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Accessor for the Title object
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return Title object
|
|
|
|
|
|
*/
|
2010-10-16 18:58:29 +00:00
|
|
|
|
function getTitle() {
|
2010-06-10 21:05:58 +00:00
|
|
|
|
return $this->mTitle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Accessor/mutator for the Title object
|
|
|
|
|
|
*
|
2012-02-09 18:01:10 +00:00
|
|
|
|
* @param $x Title object or null to just get the current one
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return Title object
|
|
|
|
|
|
*/
|
|
|
|
|
|
function Title( $x = null ) {
|
|
|
|
|
|
return wfSetVar( $this->mTitle, $x );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Set the output type
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $ot Integer: new value
|
|
|
|
|
|
*/
|
|
|
|
|
|
function setOutputType( $ot ) {
|
|
|
|
|
|
$this->mOutputType = $ot;
|
|
|
|
|
|
# Shortcut alias
|
|
|
|
|
|
$this->ot = array(
|
|
|
|
|
|
'html' => $ot == self::OT_HTML,
|
|
|
|
|
|
'wiki' => $ot == self::OT_WIKI,
|
|
|
|
|
|
'pre' => $ot == self::OT_PREPROCESS,
|
|
|
|
|
|
'plain' => $ot == self::OT_PLAIN,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Accessor/mutator for the output type
|
|
|
|
|
|
*
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @param $x int|null New value or null to just get the current one
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return Integer
|
|
|
|
|
|
*/
|
|
|
|
|
|
function OutputType( $x = null ) {
|
|
|
|
|
|
return wfSetVar( $this->mOutputType, $x );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the ParserOutput object
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return ParserOutput object
|
|
|
|
|
|
*/
|
|
|
|
|
|
function getOutput() {
|
|
|
|
|
|
return $this->mOutput;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the ParserOptions object
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return ParserOptions object
|
|
|
|
|
|
*/
|
|
|
|
|
|
function getOptions() {
|
|
|
|
|
|
return $this->mOptions;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Accessor/mutator for the ParserOptions object
|
|
|
|
|
|
*
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @param $x ParserOptions New value or null to just get the current one
|
|
|
|
|
|
* @return ParserOptions Current ParserOptions object
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function Options( $x = null ) {
|
|
|
|
|
|
return wfSetVar( $this->mOptions, $x );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-28 17:18:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return int
|
|
|
|
|
|
*/
|
2010-06-10 21:05:58 +00:00
|
|
|
|
function nextLinkID() {
|
|
|
|
|
|
return $this->mLinkID++;
|
|
|
|
|
|
}
|
2006-02-28 05:18:36 +00:00
|
|
|
|
|
2011-05-28 17:18:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param $id int
|
|
|
|
|
|
*/
|
2011-02-23 06:58:15 +00:00
|
|
|
|
function setLinkID( $id ) {
|
|
|
|
|
|
$this->mLinkID = $id;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-02-19 01:02:56 +00:00
|
|
|
|
/**
|
2012-03-05 05:53:12 +00:00
|
|
|
|
* Get a language object for use in parser functions such as {{FORMATNUM:}}
|
2011-02-19 01:02:56 +00:00
|
|
|
|
* @return Language
|
|
|
|
|
|
*/
|
2006-07-03 11:07:00 +00:00
|
|
|
|
function getFunctionLang() {
|
2012-03-05 05:53:12 +00:00
|
|
|
|
return $this->getTargetLanguage();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2012-05-03 20:02:27 +00:00
|
|
|
|
* Get the target language for the content being parsed. This is usually the
|
|
|
|
|
|
* language that the content is in.
|
2012-03-05 05:53:12 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getTargetLanguage() {
|
2008-03-07 14:02:12 +00:00
|
|
|
|
$target = $this->mOptions->getTargetLanguage();
|
|
|
|
|
|
if ( $target !== null ) {
|
|
|
|
|
|
return $target;
|
2011-09-07 04:05:37 +00:00
|
|
|
|
} elseif( $this->mOptions->getInterfaceMessage() ) {
|
2011-10-19 14:16:01 +00:00
|
|
|
|
return $this->mOptions->getUserLangObj();
|
2011-09-07 04:05:37 +00:00
|
|
|
|
} elseif( is_null( $this->mTitle ) ) {
|
|
|
|
|
|
throw new MWException( __METHOD__.': $this->mTitle is null' );
|
2008-03-07 14:02:12 +00:00
|
|
|
|
}
|
2011-09-07 04:05:37 +00:00
|
|
|
|
return $this->mTitle->getPageLanguage();
|
2006-07-03 11:07:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-03-05 12:14:53 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the language object for language conversion
|
|
|
|
|
|
*/
|
|
|
|
|
|
function getConverterLanguage() {
|
|
|
|
|
|
global $wgBug34832TransitionalRollback, $wgContLang;
|
|
|
|
|
|
if ( $wgBug34832TransitionalRollback ) {
|
|
|
|
|
|
return $wgContLang;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return $this->getTargetLanguage();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-12-10 18:17:20 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get a User object either from $this->mUser, if set, or from the
|
|
|
|
|
|
* ParserOptions object otherwise
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return User object
|
|
|
|
|
|
*/
|
|
|
|
|
|
function getUser() {
|
2010-12-10 18:23:33 +00:00
|
|
|
|
if ( !is_null( $this->mUser ) ) {
|
2010-12-10 18:17:20 +00:00
|
|
|
|
return $this->mUser;
|
2010-12-10 18:23:33 +00:00
|
|
|
|
}
|
2010-12-10 18:17:20 +00:00
|
|
|
|
return $this->mOptions->getUser();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-01-21 16:36:08 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get a preprocessor object
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return Preprocessor instance
|
2008-01-21 16:36:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getPreprocessor() {
|
|
|
|
|
|
if ( !isset( $this->mPreprocessor ) ) {
|
|
|
|
|
|
$class = $this->mPreprocessorClass;
|
|
|
|
|
|
$this->mPreprocessor = new $class( $this );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $this->mPreprocessor;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-07-03 07:15:53 +00:00
|
|
|
|
/**
|
2006-06-01 19:38:14 +00:00
|
|
|
|
* Replaces all occurrences of HTML-style comments and the given tags
|
2008-02-09 21:48:41 +00:00
|
|
|
|
* in the text with a random marker and returns the next text. The output
|
2006-06-01 19:38:14 +00:00
|
|
|
|
* parameter $matches will be an associative array filled with data in
|
|
|
|
|
|
* the form:
|
2012-07-10 12:48:06 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @code
|
2006-06-01 19:38:14 +00:00
|
|
|
|
* 'UNIQ-xxxxx' => array(
|
|
|
|
|
|
* 'element',
|
|
|
|
|
|
* 'tag content',
|
|
|
|
|
|
* array( 'param' => 'x' ),
|
|
|
|
|
|
* '<element param="x">tag content</element>' ) )
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* @endcode
|
2005-07-03 07:15:53 +00:00
|
|
|
|
*
|
2011-05-28 17:18:50 +00:00
|
|
|
|
* @param $elements array list of element names. Comments are always extracted.
|
|
|
|
|
|
* @param $text string Source text string.
|
|
|
|
|
|
* @param $matches array Out parameter, Array: extracted tags
|
|
|
|
|
|
* @param $uniq_prefix string
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return String: stripped text
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2011-05-01 23:59:41 +00:00
|
|
|
|
public static function extractTagsAndParams( $elements, $text, &$matches, $uniq_prefix = '' ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
static $n = 1;
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$stripped = '';
|
2006-06-01 06:16:55 +00:00
|
|
|
|
$matches = array();
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$taglist = implode( '|', $elements );
|
2009-09-07 00:23:04 +00:00
|
|
|
|
$start = "/<($taglist)(\\s+[^>]*?|\\s*?)(\/?" . ">)|<(!--)/i";
|
2004-03-26 17:14:23 +00:00
|
|
|
|
|
2010-01-27 02:41:22 +00:00
|
|
|
|
while ( $text != '' ) {
|
2005-06-03 08:12:48 +00:00
|
|
|
|
$p = preg_split( $start, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
|
2004-03-26 17:14:23 +00:00
|
|
|
|
$stripped .= $p[0];
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( count( $p ) < 5 ) {
|
2005-06-03 08:12:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( count( $p ) > 5 ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# comment
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$element = $p[4];
|
|
|
|
|
|
$attributes = '';
|
|
|
|
|
|
$close = '';
|
|
|
|
|
|
$inside = $p[5];
|
2006-04-08 04:40:09 +00:00
|
|
|
|
} else {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# tag
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$element = $p[1];
|
|
|
|
|
|
$attributes = $p[2];
|
|
|
|
|
|
$close = $p[3];
|
|
|
|
|
|
$inside = $p[4];
|
2006-04-08 04:40:09 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$marker = "$uniq_prefix-$element-" . sprintf( '%08X', $n++ ) . self::MARKER_SUFFIX;
|
2005-06-03 08:12:48 +00:00
|
|
|
|
$stripped .= $marker;
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2006-06-01 19:38:14 +00:00
|
|
|
|
if ( $close === '/>' ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Empty element tag, <tag />
|
2006-06-01 06:16:55 +00:00
|
|
|
|
$content = null;
|
2005-11-13 04:47:03 +00:00
|
|
|
|
$text = $inside;
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$tail = null;
|
2004-03-26 17:14:23 +00:00
|
|
|
|
} else {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $element === '!--' ) {
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$end = '/(-->)/';
|
2006-06-01 06:16:55 +00:00
|
|
|
|
} else {
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$end = "/(<\\/$element\\s*>)/i";
|
2006-06-01 06:16:55 +00:00
|
|
|
|
}
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$q = preg_split( $end, $inside, 2, PREG_SPLIT_DELIM_CAPTURE );
|
2006-06-01 06:16:55 +00:00
|
|
|
|
$content = $q[0];
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( count( $q ) < 3 ) {
|
2005-11-13 04:47:03 +00:00
|
|
|
|
# No end tag -- let it run out to the end of the text.
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$tail = '';
|
2006-06-01 08:24:22 +00:00
|
|
|
|
$text = '';
|
2005-11-13 04:47:03 +00:00
|
|
|
|
} else {
|
2006-06-01 19:38:14 +00:00
|
|
|
|
$tail = $q[1];
|
|
|
|
|
|
$text = $q[2];
|
2005-11-13 04:47:03 +00:00
|
|
|
|
}
|
2004-03-26 17:14:23 +00:00
|
|
|
|
}
|
2006-10-17 08:49:27 +00:00
|
|
|
|
|
2006-06-01 06:16:55 +00:00
|
|
|
|
$matches[$marker] = array( $element,
|
|
|
|
|
|
$content,
|
|
|
|
|
|
Sanitizer::decodeTagAttributes( $attributes ),
|
2006-06-01 19:38:14 +00:00
|
|
|
|
"<$element$attributes$close$content$tail" );
|
2004-03-26 17:14:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $stripped;
|
2004-04-12 23:59:37 +00:00
|
|
|
|
}
|
2004-03-26 17:14:23 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2007-11-20 10:55:08 +00:00
|
|
|
|
* Get a list of strippable XML-like elements
|
2011-05-28 17:18:50 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return array
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function getStripList() {
|
2010-02-03 07:10:58 +00:00
|
|
|
|
return $this->mStripList;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
2006-10-17 08:49:27 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Add an item to the strip state
|
|
|
|
|
|
* Returns the unique tag which must be inserted into the stripped text
|
|
|
|
|
|
* The tag will be replaced with the original text in unstrip()
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function insertStripItem( $text ) {
|
2008-03-27 00:00:25 +00:00
|
|
|
|
$rnd = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}-" . self::MARKER_SUFFIX;
|
2008-02-05 08:23:58 +00:00
|
|
|
|
$this->mMarkerIndex++;
|
2011-02-23 06:58:15 +00:00
|
|
|
|
$this->mStripState->addGeneral( $rnd, $text );
|
2004-04-09 15:29:33 +00:00
|
|
|
|
return $rnd;
|
|
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* parse the wiki syntax used to render tables
|
|
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2012-02-09 21:35:05 +00:00
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2010-03-30 21:20:05 +00:00
|
|
|
|
function doTableStuff( $text ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2010-12-11 03:52:35 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$lines = StringUtils::explode( "\n", $text );
|
|
|
|
|
|
$out = '';
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$td_history = array(); # Is currently a td tag open?
|
|
|
|
|
|
$last_tag_history = array(); # Save history of last lag activated (td, th or caption)
|
|
|
|
|
|
$tr_history = array(); # Is currently a tr tag open?
|
|
|
|
|
|
$tr_attributes = array(); # history of tr attributes
|
|
|
|
|
|
$has_opened_tr = array(); # Did this table open a <tr> element?
|
|
|
|
|
|
$indent_level = 0; # indent level of the table
|
2008-08-26 14:37:15 +00:00
|
|
|
|
|
2011-01-26 01:16:18 +00:00
|
|
|
|
foreach ( $lines as $outLine ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$line = trim( $outLine );
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( $line === '' ) { # empty line, go to next line
|
|
|
|
|
|
$out .= $outLine."\n";
|
2006-12-04 20:08:53 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2011-09-15 12:10:53 +00:00
|
|
|
|
|
|
|
|
|
|
$first_character = $line[0];
|
2006-10-17 08:49:27 +00:00
|
|
|
|
$matches = array();
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( preg_match( '/^(:*)\{\|(.*)$/', $line , $matches ) ) {
|
|
|
|
|
|
# First check if we are starting a new table
|
|
|
|
|
|
$indent_level = strlen( $matches[1] );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$attributes = $this->mStripState->unstripBoth( $matches[2] );
|
2010-12-10 16:03:57 +00:00
|
|
|
|
$attributes = Sanitizer::fixTagAttributes( $attributes , 'table' );
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$outLine = str_repeat( '<dl><dd>' , $indent_level ) . "<table{$attributes}>";
|
|
|
|
|
|
array_push( $td_history , false );
|
|
|
|
|
|
array_push( $last_tag_history , '' );
|
|
|
|
|
|
array_push( $tr_history , false );
|
|
|
|
|
|
array_push( $tr_attributes , '' );
|
|
|
|
|
|
array_push( $has_opened_tr , false );
|
|
|
|
|
|
} elseif ( count( $td_history ) == 0 ) {
|
|
|
|
|
|
# Don't do any of the following
|
|
|
|
|
|
$out .= $outLine."\n";
|
|
|
|
|
|
continue;
|
|
|
|
|
|
} elseif ( substr( $line , 0 , 2 ) === '|}' ) {
|
|
|
|
|
|
# We are ending a table
|
|
|
|
|
|
$line = '</table>' . substr( $line , 2 );
|
|
|
|
|
|
$last_tag = array_pop( $last_tag_history );
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( !array_pop( $has_opened_tr ) ) {
|
|
|
|
|
|
$line = "<tr><td></td></tr>{$line}";
|
2006-12-04 20:08:53 +00:00
|
|
|
|
}
|
2011-04-15 22:36:09 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( array_pop( $tr_history ) ) {
|
|
|
|
|
|
$line = "</tr>{$line}";
|
2011-04-14 10:02:51 +00:00
|
|
|
|
}
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( array_pop( $td_history ) ) {
|
|
|
|
|
|
$line = "</{$last_tag}>{$line}";
|
2006-12-04 20:08:53 +00:00
|
|
|
|
}
|
2011-09-15 12:10:53 +00:00
|
|
|
|
array_pop( $tr_attributes );
|
|
|
|
|
|
$outLine = $line . str_repeat( '</dd></dl>' , $indent_level );
|
|
|
|
|
|
} elseif ( substr( $line , 0 , 2 ) === '|-' ) {
|
|
|
|
|
|
# Now we have a table row
|
|
|
|
|
|
$line = preg_replace( '#^\|-+#', '', $line );
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
# Whats after the tag is now only attributes
|
2011-04-12 21:27:24 +00:00
|
|
|
|
$attributes = $this->mStripState->unstripBoth( $line );
|
|
|
|
|
|
$attributes = Sanitizer::fixTagAttributes( $attributes, 'tr' );
|
2011-09-15 12:10:53 +00:00
|
|
|
|
array_pop( $tr_attributes );
|
|
|
|
|
|
array_push( $tr_attributes, $attributes );
|
2011-04-13 11:24:38 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$line = '';
|
|
|
|
|
|
$last_tag = array_pop( $last_tag_history );
|
|
|
|
|
|
array_pop( $has_opened_tr );
|
|
|
|
|
|
array_push( $has_opened_tr , true );
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( array_pop( $tr_history ) ) {
|
|
|
|
|
|
$line = '</tr>';
|
2011-04-12 21:27:24 +00:00
|
|
|
|
}
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( array_pop( $td_history ) ) {
|
|
|
|
|
|
$line = "</{$last_tag}>{$line}";
|
2011-04-12 21:27:24 +00:00
|
|
|
|
}
|
2011-04-13 11:24:38 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$outLine = $line;
|
|
|
|
|
|
array_push( $tr_history , false );
|
|
|
|
|
|
array_push( $td_history , false );
|
|
|
|
|
|
array_push( $last_tag_history , '' );
|
|
|
|
|
|
} 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 = '+';
|
|
|
|
|
|
$line = substr( $line , 1 );
|
|
|
|
|
|
}
|
2011-04-13 11:24:38 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$line = substr( $line , 1 );
|
2011-04-13 11:24:38 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( $first_character === '!' ) {
|
|
|
|
|
|
$line = str_replace( '!!' , '||' , $line );
|
2011-04-14 10:02:51 +00:00
|
|
|
|
}
|
2011-04-13 11:24:38 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
# Split up multiple cells on the same line.
|
|
|
|
|
|
# FIXME : This can result in improper nesting of tags processed
|
|
|
|
|
|
# by earlier parser steps, but should avoid splitting up eg
|
|
|
|
|
|
# attribute values containing literal "||".
|
|
|
|
|
|
$cells = StringUtils::explodeMarkup( '||' , $line );
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$outLine = '';
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
# Loop through each table cell
|
|
|
|
|
|
foreach ( $cells as $cell ) {
|
|
|
|
|
|
$previous = '';
|
|
|
|
|
|
if ( $first_character !== '+' ) {
|
|
|
|
|
|
$tr_after = array_pop( $tr_attributes );
|
|
|
|
|
|
if ( !array_pop( $tr_history ) ) {
|
|
|
|
|
|
$previous = "<tr{$tr_after}>\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
array_push( $tr_history , true );
|
|
|
|
|
|
array_push( $tr_attributes , '' );
|
|
|
|
|
|
array_pop( $has_opened_tr );
|
|
|
|
|
|
array_push( $has_opened_tr , true );
|
|
|
|
|
|
}
|
2011-01-26 01:16:18 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$last_tag = array_pop( $last_tag_history );
|
2011-04-12 21:27:24 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( array_pop( $td_history ) ) {
|
|
|
|
|
|
$previous = "</{$last_tag}>\n{$previous}";
|
|
|
|
|
|
}
|
2004-02-29 08:43:29 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( $first_character === '|' ) {
|
|
|
|
|
|
$last_tag = 'td';
|
|
|
|
|
|
} elseif ( $first_character === '!' ) {
|
|
|
|
|
|
$last_tag = 'th';
|
|
|
|
|
|
} elseif ( $first_character === '+' ) {
|
|
|
|
|
|
$last_tag = 'caption';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$last_tag = '';
|
|
|
|
|
|
}
|
2011-04-12 21:27:24 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
array_push( $last_tag_history , $last_tag );
|
|
|
|
|
|
|
|
|
|
|
|
# A cell could contain both parameters and data
|
|
|
|
|
|
$cell_data = explode( '|' , $cell , 2 );
|
|
|
|
|
|
|
|
|
|
|
|
# Bug 553: Note that a '|' inside an invalid link should not
|
|
|
|
|
|
# be mistaken as delimiting cell parameters
|
|
|
|
|
|
if ( strpos( $cell_data[0], '[[' ) !== false ) {
|
|
|
|
|
|
$cell = "{$previous}<{$last_tag}>{$cell}";
|
|
|
|
|
|
} elseif ( count( $cell_data ) == 1 ) {
|
|
|
|
|
|
$cell = "{$previous}<{$last_tag}>{$cell_data[0]}";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$attributes = $this->mStripState->unstripBoth( $cell_data[0] );
|
|
|
|
|
|
$attributes = Sanitizer::fixTagAttributes( $attributes , $last_tag );
|
|
|
|
|
|
$cell = "{$previous}<{$last_tag}{$attributes}>{$cell_data[1]}";
|
|
|
|
|
|
}
|
2011-04-12 21:27:24 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$outLine .= $cell;
|
|
|
|
|
|
array_push( $td_history , true );
|
|
|
|
|
|
}
|
2011-04-13 19:46:09 +00:00
|
|
|
|
}
|
2011-09-15 12:10:53 +00:00
|
|
|
|
$out .= $outLine . "\n";
|
2011-04-12 21:27:24 +00:00
|
|
|
|
}
|
2011-06-24 20:25:16 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
# Closing open td, tr && table
|
|
|
|
|
|
while ( count( $td_history ) > 0 ) {
|
|
|
|
|
|
if ( array_pop( $td_history ) ) {
|
|
|
|
|
|
$out .= "</td>\n";
|
2006-12-04 20:08:53 +00:00
|
|
|
|
}
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( array_pop( $tr_history ) ) {
|
|
|
|
|
|
$out .= "</tr>\n";
|
2011-04-12 21:27:24 +00:00
|
|
|
|
}
|
2011-09-15 12:10:53 +00:00
|
|
|
|
if ( !array_pop( $has_opened_tr ) ) {
|
|
|
|
|
|
$out .= "<tr><td></td></tr>\n" ;
|
2011-04-12 21:27:24 +00:00
|
|
|
|
}
|
2011-09-15 12:10:53 +00:00
|
|
|
|
|
|
|
|
|
|
$out .= "</table>\n";
|
2004-02-28 05:55:13 +00:00
|
|
|
|
}
|
2011-09-15 12:10:53 +00:00
|
|
|
|
|
|
|
|
|
|
# Remove trailing line-ending (b/c)
|
|
|
|
|
|
if ( substr( $out, -1 ) === "\n" ) {
|
|
|
|
|
|
$out = substr( $out, 0, -1 );
|
2011-04-12 21:27:24 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
# special case: don't return empty table
|
|
|
|
|
|
if ( $out === "<table>\n<tr><td></td></tr>\n</table>" ) {
|
|
|
|
|
|
$out = '';
|
|
|
|
|
|
}
|
2006-12-04 20:08:53 +00:00
|
|
|
|
|
2011-09-15 12:10:53 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
|
|
|
|
|
|
return $out;
|
2004-02-28 05:55:13 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Helper function for parse() that transforms wiki markup into
|
2008-01-22 10:47:44 +00:00
|
|
|
|
* HTML. Only called for $mOutputType == self::OT_HTML.
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
* @param $isMain bool
|
|
|
|
|
|
* @param $frame bool
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2011-08-05 00:33:03 +00:00
|
|
|
|
function internalParse( $text, $isMain = true, $frame = false ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2009-06-20 18:25:30 +00:00
|
|
|
|
$origText = $text;
|
2004-04-11 16:46:06 +00:00
|
|
|
|
|
2006-08-06 14:01:47 +00:00
|
|
|
|
# Hook to suspend the parser in this state
|
2006-11-23 08:25:56 +00:00
|
|
|
|
if ( !wfRunHooks( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
return $text ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# if $frame is provided, then use $frame for replacing any variables
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $frame ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# use frame depth to infer how include/noinclude tags should be handled
|
|
|
|
|
|
# depth=0 means this is the top-level document; otherwise it's an included document
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !$frame->depth ) {
|
2009-08-30 06:37:10 +00:00
|
|
|
|
$flag = 0;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else {
|
2009-08-30 06:37:10 +00:00
|
|
|
|
$flag = Parser::PTD_FOR_INCLUSION;
|
2010-04-10 16:44:10 +00:00
|
|
|
|
}
|
2009-08-30 06:37:10 +00:00
|
|
|
|
$dom = $this->preprocessToDom( $text, $flag );
|
|
|
|
|
|
$text = $frame->expand( $dom );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# if $frame is not provided, then use old-style replaceVariables
|
2009-08-30 06:37:10 +00:00
|
|
|
|
$text = $this->replaceVariables( $text );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-06-24 20:43:17 +00:00
|
|
|
|
wfRunHooks( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ), false, array_keys( $this->mTransparentTagHooks ) );
|
2007-04-25 21:23:43 +00:00
|
|
|
|
wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Tables need to come after variable replacement for things to work
|
|
|
|
|
|
# properly; putting them before other transformations should keep
|
|
|
|
|
|
# exciting things like link expansions from showing up in surprising
|
|
|
|
|
|
# places.
|
2006-05-23 07:19:01 +00:00
|
|
|
|
$text = $this->doTableStuff( $text );
|
|
|
|
|
|
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2008-02-20 08:53:12 +00:00
|
|
|
|
$text = $this->doDoubleUnderscore( $text );
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2008-08-25 04:27:40 +00:00
|
|
|
|
$text = $this->doHeadings( $text );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->mOptions->getUseDynamicDates() ) {
|
2008-04-09 18:23:34 +00:00
|
|
|
|
$df = DateFormatter::getInstance();
|
2005-04-20 15:42:08 +00:00
|
|
|
|
$text = $df->reformat( $this->mOptions->getDateFormat(), $text );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-11-28 03:29:50 +00:00
|
|
|
|
$text = $this->replaceInternalLinks( $text );
|
2010-06-23 23:29:54 +00:00
|
|
|
|
$text = $this->doAllQuotes( $text );
|
2010-06-24 13:44:50 +00:00
|
|
|
|
$text = $this->replaceExternalLinks( $text );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-10-25 05:24:23 +00:00
|
|
|
|
# replaceInternalLinks may sometimes leave behind
|
|
|
|
|
|
# absolute URLs, which have to be masked to hide them from replaceExternalLinks
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$text = str_replace( $this->mUniqPrefix.'NOPARSE', '', $text );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-09-26 17:59:08 +00:00
|
|
|
|
$text = $this->doMagicLinks( $text );
|
2009-06-20 18:25:30 +00:00
|
|
|
|
$text = $this->formatHeadings( $text, $origText, $isMain );
|
2004-04-12 16:10:17 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2004-08-07 12:35:59 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Replace special strings like "ISBN xxx" and "RFC xxx" with
|
|
|
|
|
|
* magic external links.
|
2010-01-07 04:13:14 +00:00
|
|
|
|
*
|
2008-08-26 14:37:15 +00:00
|
|
|
|
* DML
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function doMagicLinks( $text ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2011-08-15 12:20:00 +00:00
|
|
|
|
$prots = wfUrlProtocolsWithoutProtRel();
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$urlChar = self::EXT_LINK_URL_CLASS;
|
2006-10-17 08:49:27 +00:00
|
|
|
|
$text = preg_replace_callback(
|
2006-08-06 14:01:47 +00:00
|
|
|
|
'!(?: # Start cases
|
2010-03-24 13:42:37 +00:00
|
|
|
|
(<a[ \t\r\n>].*?</a>) | # m[1]: Skip link text
|
2008-08-26 14:37:15 +00:00
|
|
|
|
(<.*?>) | # m[2]: Skip stuff inside HTML elements' . "
|
|
|
|
|
|
(\\b(?:$prots)$urlChar+) | # m[3]: Free external links" . '
|
|
|
|
|
|
(?:RFC|PMID)\s+([0-9]+) | # m[4]: RFC or PMID, capture number
|
|
|
|
|
|
ISBN\s+(\b # m[5]: ISBN, capture number
|
2010-12-11 03:52:35 +00:00
|
|
|
|
(?: 97[89] [\ \-]? )? # optional 13-digit ISBN prefix
|
|
|
|
|
|
(?: [0-9] [\ \-]? ){9} # 9 digits with opt. delimiters
|
|
|
|
|
|
[0-9Xx] # check digit
|
|
|
|
|
|
\b)
|
2011-07-27 18:03:01 +00:00
|
|
|
|
)!xu', array( &$this, 'magicLinkCallback' ), $text );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-10-17 08:49:27 +00:00
|
|
|
|
return $text;
|
2006-08-06 14:01:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-28 17:18:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @throws MWException
|
|
|
|
|
|
* @param $m array
|
|
|
|
|
|
* @return HTML|string
|
|
|
|
|
|
*/
|
2006-08-06 14:01:47 +00:00
|
|
|
|
function magicLinkCallback( $m ) {
|
2009-02-27 17:56:00 +00:00
|
|
|
|
if ( isset( $m[1] ) && $m[1] !== '' ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
# Skip anchor
|
|
|
|
|
|
return $m[0];
|
2009-02-27 17:56:00 +00:00
|
|
|
|
} elseif ( isset( $m[2] ) && $m[2] !== '' ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
# Skip HTML element
|
|
|
|
|
|
return $m[0];
|
2009-02-27 17:56:00 +00:00
|
|
|
|
} elseif ( isset( $m[3] ) && $m[3] !== '' ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
# Free external link
|
|
|
|
|
|
return $this->makeFreeExternalLink( $m[0] );
|
2009-02-27 17:56:00 +00:00
|
|
|
|
} elseif ( isset( $m[4] ) && $m[4] !== '' ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
# RFC or PMID
|
|
|
|
|
|
if ( substr( $m[0], 0, 3 ) === 'RFC' ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$keyword = 'RFC';
|
|
|
|
|
|
$urlmsg = 'rfcurl';
|
2009-08-20 09:13:29 +00:00
|
|
|
|
$CssClass = 'mw-magiclink-rfc';
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$id = $m[4];
|
|
|
|
|
|
} elseif ( substr( $m[0], 0, 4 ) === 'PMID' ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$keyword = 'PMID';
|
|
|
|
|
|
$urlmsg = 'pubmedurl';
|
2009-08-20 09:13:29 +00:00
|
|
|
|
$CssClass = 'mw-magiclink-pmid';
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$id = $m[4];
|
2006-08-06 14:01:47 +00:00
|
|
|
|
} else {
|
2006-10-17 08:49:27 +00:00
|
|
|
|
throw new MWException( __METHOD__.': unrecognised match type "' .
|
2010-03-30 21:20:05 +00:00
|
|
|
|
substr( $m[0], 0, 20 ) . '"' );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
}
|
2011-02-05 23:06:36 +00:00
|
|
|
|
$url = wfMsgForContent( $urlmsg, $id );
|
2011-04-03 11:44:11 +00:00
|
|
|
|
return Linker::makeExternalLink( $url, "{$keyword} {$id}", true, $CssClass );
|
2009-02-27 17:56:00 +00:00
|
|
|
|
} elseif ( isset( $m[5] ) && $m[5] !== '' ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
# ISBN
|
|
|
|
|
|
$isbn = $m[5];
|
|
|
|
|
|
$num = strtr( $isbn, array(
|
|
|
|
|
|
'-' => '',
|
|
|
|
|
|
' ' => '',
|
|
|
|
|
|
'x' => 'X',
|
|
|
|
|
|
));
|
|
|
|
|
|
$titleObj = SpecialPage::getTitleFor( 'Booksources', $num );
|
|
|
|
|
|
return'<a href="' .
|
2011-12-13 04:58:48 +00:00
|
|
|
|
htmlspecialchars( $titleObj->getLocalUrl() ) .
|
2009-08-20 09:13:29 +00:00
|
|
|
|
"\" class=\"internal mw-magiclink-isbn\">ISBN $isbn</a>";
|
2008-08-26 14:37:15 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
return $m[0];
|
2006-08-06 14:01:47 +00:00
|
|
|
|
}
|
2004-08-04 01:53:29 +00:00
|
|
|
|
}
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Make a free external link, given a user-supplied URL
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $url string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string HTML
|
2008-08-26 14:37:15 +00:00
|
|
|
|
* @private
|
|
|
|
|
|
*/
|
|
|
|
|
|
function makeFreeExternalLink( $url ) {
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
|
|
|
|
|
|
$trail = '';
|
|
|
|
|
|
|
|
|
|
|
|
# The characters '<' and '>' (which were escaped by
|
|
|
|
|
|
# removeHTMLtags()) should not be included in
|
|
|
|
|
|
# URLs, per RFC 2396.
|
|
|
|
|
|
$m2 = array();
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( preg_match( '/&(lt|gt);/', $url, $m2, PREG_OFFSET_CAPTURE ) ) {
|
|
|
|
|
|
$trail = substr( $url, $m2[0][1] ) . $trail;
|
|
|
|
|
|
$url = substr( $url, 0, $m2[0][1] );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Move trailing punctuation to $trail
|
|
|
|
|
|
$sep = ',;\.:!?';
|
|
|
|
|
|
# If there is no left bracket, then consider right brackets fair game too
|
|
|
|
|
|
if ( strpos( $url, '(' ) === false ) {
|
|
|
|
|
|
$sep .= ')';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$numSepChars = strspn( strrev( $url ), $sep );
|
|
|
|
|
|
if ( $numSepChars ) {
|
|
|
|
|
|
$trail = substr( $url, -$numSepChars ) . $trail;
|
|
|
|
|
|
$url = substr( $url, 0, -$numSepChars );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$url = Sanitizer::cleanUrl( $url );
|
|
|
|
|
|
|
|
|
|
|
|
# Is this an external image?
|
|
|
|
|
|
$text = $this->maybeMakeExternalImage( $url );
|
|
|
|
|
|
if ( $text === false ) {
|
|
|
|
|
|
# Not an image, make a link
|
2012-05-03 20:02:27 +00:00
|
|
|
|
$text = Linker::makeExternalLink( $url,
|
2012-03-05 12:14:53 +00:00
|
|
|
|
$this->getConverterLanguage()->markNoConversion($url), true, 'free',
|
2009-01-23 18:03:12 +00:00
|
|
|
|
$this->getExternalLinkAttribs( $url ) );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
# Register it in the output object...
|
|
|
|
|
|
# Replace unnecessary URL escape codes with their equivalent characters
|
|
|
|
|
|
$pasteurized = self::replaceUnusualEscapes( $url );
|
|
|
|
|
|
$this->mOutput->addExternalLink( $pasteurized );
|
|
|
|
|
|
}
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
return $text . $trail;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Parse headers and return html
|
|
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2008-08-25 04:27:40 +00:00
|
|
|
|
function doHeadings( $text ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
for ( $i = 6; $i >= 1; --$i ) {
|
2005-11-29 09:55:50 +00:00
|
|
|
|
$h = str_repeat( '=', $i );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = preg_replace( "/^$h(.+)$h\\s*$/m",
|
|
|
|
|
|
"<h$i>\\1</h$i>", $text );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Replace single quotes with HTML markup
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
2004-09-21 05:49:12 +00:00
|
|
|
|
* @return string the altered text
|
|
|
|
|
|
*/
|
2008-08-25 04:27:40 +00:00
|
|
|
|
function doAllQuotes( $text ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$outtext = '';
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$lines = StringUtils::explode( "\n", $text );
|
2004-05-26 16:29:04 +00:00
|
|
|
|
foreach ( $lines as $line ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$outtext .= $this->doQuotes( $line ) . "\n";
|
2004-05-26 16:29:04 +00:00
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$outtext = substr( $outtext, 0,-1 );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-06-05 04:51:24 +00:00
|
|
|
|
return $outtext;
|
2004-05-26 16:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Helper function for doAllQuotes()
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2008-08-25 04:27:40 +00:00
|
|
|
|
public function doQuotes( $text ) {
|
2010-01-27 02:41:22 +00:00
|
|
|
|
$arr = preg_split( "/(''+)/", $text, -1, PREG_SPLIT_DELIM_CAPTURE );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( count( $arr ) == 1 ) {
|
2004-08-06 20:47:21 +00:00
|
|
|
|
return $text;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else {
|
2010-01-27 02:41:22 +00:00
|
|
|
|
# First, do some preliminary work. This may shift some apostrophes from
|
|
|
|
|
|
# being mark-up to being text. It also counts the number of occurrences
|
|
|
|
|
|
# of bold and italics mark-ups.
|
|
|
|
|
|
$numbold = 0;
|
|
|
|
|
|
$numitalics = 0;
|
2010-11-10 19:19:46 +00:00
|
|
|
|
for ( $i = 0; $i < count( $arr ); $i++ ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( ( $i % 2 ) == 1 ) {
|
2010-01-27 02:41:22 +00:00
|
|
|
|
# If there are ever four apostrophes, assume the first is supposed to
|
|
|
|
|
|
# be text, and the remaining three constitute mark-up for bold text.
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( strlen( $arr[$i] ) == 4 ) {
|
2010-01-27 02:41:22 +00:00
|
|
|
|
$arr[$i-1] .= "'";
|
|
|
|
|
|
$arr[$i] = "'''";
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( strlen( $arr[$i] ) > 5 ) {
|
|
|
|
|
|
# If there are more than 5 apostrophes in a row, assume they're all
|
|
|
|
|
|
# text except for the last 5.
|
2010-01-27 02:41:22 +00:00
|
|
|
|
$arr[$i-1] .= str_repeat( "'", strlen( $arr[$i] ) - 5 );
|
|
|
|
|
|
$arr[$i] = "'''''";
|
|
|
|
|
|
}
|
|
|
|
|
|
# Count the number of occurrences of bold and italics mark-ups.
|
|
|
|
|
|
# We are not counting sequences of five apostrophes.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
if ( strlen( $arr[$i] ) == 2 ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$numitalics++;
|
2010-05-15 10:35:54 +00:00
|
|
|
|
} elseif ( strlen( $arr[$i] ) == 3 ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$numbold++;
|
2010-05-15 10:35:54 +00:00
|
|
|
|
} elseif ( strlen( $arr[$i] ) == 5 ) {
|
|
|
|
|
|
$numitalics++;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$numbold++;
|
|
|
|
|
|
}
|
2010-01-27 02:41:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-08-06 20:47:21 +00:00
|
|
|
|
# If there is an odd number of both bold and italics, it is likely
|
|
|
|
|
|
# that one of the bold ones was meant to be an apostrophe followed
|
|
|
|
|
|
# by italics. Which one we cannot know for certain, but it is more
|
|
|
|
|
|
# likely to be one that has a single-letter word before it.
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( ( $numbold % 2 == 1 ) && ( $numitalics % 2 == 1 ) ) {
|
2010-01-27 02:41:22 +00:00
|
|
|
|
$i = 0;
|
|
|
|
|
|
$firstsingleletterword = -1;
|
|
|
|
|
|
$firstmultiletterword = -1;
|
|
|
|
|
|
$firstspace = -1;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
foreach ( $arr as $r ) {
|
|
|
|
|
|
if ( ( $i % 2 == 1 ) and ( strlen( $r ) == 3 ) ) {
|
|
|
|
|
|
$x1 = substr( $arr[$i-1], -1 );
|
|
|
|
|
|
$x2 = substr( $arr[$i-1], -2, 1 );
|
|
|
|
|
|
if ( $x1 === ' ' ) {
|
|
|
|
|
|
if ( $firstspace == -1 ) {
|
|
|
|
|
|
$firstspace = $i;
|
|
|
|
|
|
}
|
|
|
|
|
|
} elseif ( $x2 === ' ') {
|
2010-05-15 10:35:54 +00:00
|
|
|
|
if ( $firstsingleletterword == -1 ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$firstsingleletterword = $i;
|
|
|
|
|
|
}
|
2010-01-27 02:41:22 +00:00
|
|
|
|
} else {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $firstmultiletterword == -1 ) {
|
|
|
|
|
|
$firstmultiletterword = $i;
|
|
|
|
|
|
}
|
2010-01-27 02:41:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$i++;
|
|
|
|
|
|
}
|
2004-08-07 12:35:59 +00:00
|
|
|
|
|
2010-01-27 02:41:22 +00:00
|
|
|
|
# If there is a single-letter word, use it!
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $firstsingleletterword > -1 ) {
|
|
|
|
|
|
$arr[$firstsingleletterword] = "''";
|
|
|
|
|
|
$arr[$firstsingleletterword-1] .= "'";
|
|
|
|
|
|
} elseif ( $firstmultiletterword > -1 ) {
|
|
|
|
|
|
# If not, but there's a multi-letter word, use that one.
|
|
|
|
|
|
$arr[$firstmultiletterword] = "''";
|
|
|
|
|
|
$arr[$firstmultiletterword-1] .= "'";
|
|
|
|
|
|
} elseif ( $firstspace > -1 ) {
|
|
|
|
|
|
# ... otherwise use the first one that has neither.
|
|
|
|
|
|
# (notice that it is possible for all three to be -1 if, for example,
|
|
|
|
|
|
# there is only one pentuple-apostrophe in the line)
|
|
|
|
|
|
$arr[$firstspace] = "''";
|
|
|
|
|
|
$arr[$firstspace-1] .= "'";
|
2004-08-06 20:47:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-08-07 12:35:59 +00:00
|
|
|
|
|
2004-08-06 20:47:21 +00:00
|
|
|
|
# Now let's actually convert our apostrophic mush to HTML!
|
2010-01-27 02:41:22 +00:00
|
|
|
|
$output = '';
|
|
|
|
|
|
$buffer = '';
|
|
|
|
|
|
$state = '';
|
2004-08-06 20:47:21 +00:00
|
|
|
|
$i = 0;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
foreach ( $arr as $r ) {
|
|
|
|
|
|
if ( ( $i % 2 ) == 0 ) {
|
|
|
|
|
|
if ( $state === 'both' ) {
|
2004-08-06 20:47:21 +00:00
|
|
|
|
$buffer .= $r;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else {
|
2004-08-06 20:47:21 +00:00
|
|
|
|
$output .= $r;
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
if ( strlen( $r ) == 2 ) {
|
|
|
|
|
|
if ( $state === 'i' ) {
|
|
|
|
|
|
$output .= '</i>'; $state = '';
|
|
|
|
|
|
} elseif ( $state === 'bi' ) {
|
|
|
|
|
|
$output .= '</i>'; $state = 'b';
|
|
|
|
|
|
} elseif ( $state === 'ib' ) {
|
|
|
|
|
|
$output .= '</b></i><b>'; $state = 'b';
|
|
|
|
|
|
} elseif ( $state === 'both' ) {
|
|
|
|
|
|
$output .= '<b><i>'.$buffer.'</i>'; $state = 'b';
|
|
|
|
|
|
} else { # $state can be 'b' or ''
|
|
|
|
|
|
$output .= '<i>'; $state .= 'i';
|
|
|
|
|
|
}
|
|
|
|
|
|
} elseif ( strlen( $r ) == 3 ) {
|
|
|
|
|
|
if ( $state === 'b' ) {
|
|
|
|
|
|
$output .= '</b>'; $state = '';
|
|
|
|
|
|
} elseif ( $state === 'bi' ) {
|
|
|
|
|
|
$output .= '</i></b><i>'; $state = 'i';
|
|
|
|
|
|
} elseif ( $state === 'ib' ) {
|
|
|
|
|
|
$output .= '</b>'; $state = 'i';
|
|
|
|
|
|
} elseif ( $state === 'both' ) {
|
|
|
|
|
|
$output .= '<i><b>'.$buffer.'</b>'; $state = 'i';
|
|
|
|
|
|
} else { # $state can be 'i' or ''
|
|
|
|
|
|
$output .= '<b>'; $state .= 'b';
|
|
|
|
|
|
}
|
|
|
|
|
|
} elseif ( strlen( $r ) == 5 ) {
|
|
|
|
|
|
if ( $state === 'b' ) {
|
|
|
|
|
|
$output .= '</b><i>'; $state = 'i';
|
|
|
|
|
|
} elseif ( $state === 'i' ) {
|
|
|
|
|
|
$output .= '</i><b>'; $state = 'b';
|
|
|
|
|
|
} elseif ( $state === 'bi' ) {
|
|
|
|
|
|
$output .= '</i></b>'; $state = '';
|
|
|
|
|
|
} elseif ( $state === 'ib' ) {
|
|
|
|
|
|
$output .= '</b></i>'; $state = '';
|
|
|
|
|
|
} elseif ( $state === 'both' ) {
|
|
|
|
|
|
$output .= '<i><b>'.$buffer.'</b></i>'; $state = '';
|
|
|
|
|
|
} else { # ($state == '')
|
|
|
|
|
|
$buffer = ''; $state = 'both';
|
|
|
|
|
|
}
|
2004-08-06 20:47:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$i++;
|
2004-05-26 16:29:04 +00:00
|
|
|
|
}
|
2004-08-07 12:37:20 +00:00
|
|
|
|
# Now close all remaining tags. Notice that the order is important.
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $state === 'b' || $state === 'ib' ) {
|
2004-09-11 08:40:26 +00:00
|
|
|
|
$output .= '</b>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( $state === 'i' || $state === 'bi' || $state === 'ib' ) {
|
2004-09-11 08:40:26 +00:00
|
|
|
|
$output .= '</i>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( $state === 'bi' ) {
|
2004-09-11 08:40:26 +00:00
|
|
|
|
$output .= '</b>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2007-03-13 18:09:20 +00:00
|
|
|
|
# There might be lonely ''''', so make sure we have a buffer
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $state === 'both' && $buffer ) {
|
2004-09-11 08:40:26 +00:00
|
|
|
|
$output .= '<b><i>'.$buffer.'</i></b>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2004-08-06 20:47:21 +00:00
|
|
|
|
return $output;
|
2004-05-26 16:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2008-08-26 14:37:15 +00:00
|
|
|
|
* Replace external links (REL)
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2010-12-11 03:52:35 +00:00
|
|
|
|
* Note: this is all very hackish and the order of execution matters a lot.
|
2004-10-25 05:24:23 +00:00
|
|
|
|
* Make sure to run maintenance/parserTests.php if you change this code.
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function replaceExternalLinks( $text ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-08-07 08:54:52 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$s = array_shift( $bits );
|
2004-08-07 18:24:12 +00:00
|
|
|
|
|
|
|
|
|
|
$i = 0;
|
|
|
|
|
|
while ( $i<count( $bits ) ) {
|
|
|
|
|
|
$url = $bits[$i++];
|
|
|
|
|
|
$protocol = $bits[$i++];
|
|
|
|
|
|
$text = $bits[$i++];
|
|
|
|
|
|
$trail = $bits[$i++];
|
2004-08-14 22:38:46 +00:00
|
|
|
|
|
2004-10-11 16:57:49 +00:00
|
|
|
|
# The characters '<' and '>' (which were escaped by
|
|
|
|
|
|
# removeHTMLtags()) should not be included in
|
|
|
|
|
|
# URLs, per RFC 2396.
|
2006-10-17 08:49:27 +00:00
|
|
|
|
$m2 = array();
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( preg_match( '/&(lt|gt);/', $url, $m2, PREG_OFFSET_CAPTURE ) ) {
|
|
|
|
|
|
$text = substr( $url, $m2[0][1] ) . ' ' . $text;
|
|
|
|
|
|
$url = substr( $url, 0, $m2[0][1] );
|
2004-10-11 16:57:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-08-07 18:24:12 +00:00
|
|
|
|
# If the link text is an image URL, replace it with an <img> tag
|
|
|
|
|
|
# This happened by accident in the original parser, but some people used it extensively
|
2005-04-27 07:48:14 +00:00
|
|
|
|
$img = $this->maybeMakeExternalImage( $text );
|
2004-08-07 18:24:12 +00:00
|
|
|
|
if ( $img !== false ) {
|
|
|
|
|
|
$text = $img;
|
|
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2004-08-07 18:24:12 +00:00
|
|
|
|
$dtrail = '';
|
2004-08-07 08:54:52 +00:00
|
|
|
|
|
2005-01-15 23:56:26 +00:00
|
|
|
|
# Set linktype for CSS - if URL==text, link is essentially free
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$linktype = ( $text === $url ) ? 'free' : 'text';
|
2005-01-15 23:56:26 +00:00
|
|
|
|
|
2004-08-07 18:24:12 +00:00
|
|
|
|
# No link text, e.g. [http://domain.tld/some.link]
|
|
|
|
|
|
if ( $text == '' ) {
|
2011-07-12 20:55:05 +00:00
|
|
|
|
# Autonumber
|
2012-03-05 05:53:12 +00:00
|
|
|
|
$langObj = $this->getTargetLanguage();
|
2011-07-12 20:55:05 +00:00
|
|
|
|
$text = '[' . $langObj->formatNum( ++$this->mAutonumber ) . ']';
|
|
|
|
|
|
$linktype = 'autonumber';
|
2004-08-07 18:24:12 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
# Have link text, e.g. [http://domain.tld/some.link text]s
|
|
|
|
|
|
# Check for trail
|
2005-04-27 07:48:14 +00:00
|
|
|
|
list( $dtrail, $trail ) = Linker::splitTrail( $trail );
|
2004-08-07 18:24:12 +00:00
|
|
|
|
}
|
2004-08-14 22:38:46 +00:00
|
|
|
|
|
2012-03-05 12:14:53 +00:00
|
|
|
|
$text = $this->getConverterLanguage()->markNoConversion( $text );
|
2006-10-17 08:49:27 +00:00
|
|
|
|
|
2006-07-11 19:54:20 +00:00
|
|
|
|
$url = Sanitizer::cleanUrl( $url );
|
2005-01-30 04:11:22 +00:00
|
|
|
|
|
2004-08-07 18:24:12 +00:00
|
|
|
|
# Use the encoded URL
|
|
|
|
|
|
# This means that users can paste URLs directly into the text
|
2010-05-30 17:33:59 +00:00
|
|
|
|
# Funny characters like ö aren't valid in URLs anyway
|
2004-08-07 18:24:12 +00:00
|
|
|
|
# This was changed in August 2004
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$s .= Linker::makeExternalLink( $url, $text, false, $linktype,
|
2009-01-23 18:03:12 +00:00
|
|
|
|
$this->getExternalLinkAttribs( $url ) ) . $dtrail . $trail;
|
2006-01-26 13:29:14 +00:00
|
|
|
|
|
2006-03-17 01:02:14 +00:00
|
|
|
|
# Register link in the output object.
|
|
|
|
|
|
# Replace unnecessary URL escape codes with the referenced character
|
|
|
|
|
|
# This prevents spammers from hiding links from the filters
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$pasteurized = self::replaceUnusualEscapes( $url );
|
2006-03-17 01:02:14 +00:00
|
|
|
|
$this->mOutput->addExternalLink( $pasteurized );
|
2004-08-07 18:24:12 +00:00
|
|
|
|
}
|
2004-08-07 08:54:52 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
return $s;
|
|
|
|
|
|
}
|
2004-08-14 22:38:46 +00:00
|
|
|
|
|
2009-01-23 18:03:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get an associative array of additional HTML attributes appropriate for a
|
|
|
|
|
|
* particular external link. This currently may include rel => nofollow
|
|
|
|
|
|
* (depending on configuration, namespace, and the URL's domain) and/or a
|
|
|
|
|
|
* target attribute (depending on configuration).
|
|
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $url String|bool optional URL, to extract the domain from for rel =>
|
2009-01-23 18:03:12 +00:00
|
|
|
|
* nofollow if appropriate
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @return Array associative array of HTML attributes
|
2009-01-23 18:03:12 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getExternalLinkAttribs( $url = false ) {
|
2008-09-30 01:00:40 +00:00
|
|
|
|
$attribs = array();
|
2011-08-20 10:18:09 +00:00
|
|
|
|
global $wgNoFollowLinks, $wgNoFollowNsExceptions, $wgNoFollowDomainExceptions;
|
2008-09-30 01:00:40 +00:00
|
|
|
|
$ns = $this->mTitle->getNamespace();
|
2011-08-20 10:18:09 +00:00
|
|
|
|
if ( $wgNoFollowLinks && !in_array( $ns, $wgNoFollowNsExceptions ) &&
|
|
|
|
|
|
!wfMatchesDomainList( $url, $wgNoFollowDomainExceptions ) )
|
|
|
|
|
|
{
|
2008-09-30 01:00:40 +00:00
|
|
|
|
$attribs['rel'] = 'nofollow';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $this->mOptions->getExternalLinkTarget() ) {
|
|
|
|
|
|
$attribs['target'] = $this->mOptions->getExternalLinkTarget();
|
|
|
|
|
|
}
|
|
|
|
|
|
return $attribs;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-01-26 13:29:14 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Replace unusual URL escape codes with their equivalent characters
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $url String
|
|
|
|
|
|
* @return String
|
|
|
|
|
|
*
|
2007-04-04 05:22:37 +00:00
|
|
|
|
* @todo This can merge genuinely required bits in the path or query string,
|
2006-03-17 01:02:14 +00:00
|
|
|
|
* breaking legit URLs. A proper fix would treat the various parts of
|
|
|
|
|
|
* the URL differently; as a workaround, just use the output for
|
|
|
|
|
|
* statistical records, not for actual linking/output.
|
2006-01-26 13:29:14 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function replaceUnusualEscapes( $url ) {
|
2006-03-11 17:13:49 +00:00
|
|
|
|
return preg_replace_callback( '/%[0-9A-Fa-f]{2}/',
|
2008-08-26 14:37:15 +00:00
|
|
|
|
array( __CLASS__, 'replaceUnusualEscapesCallback' ), $url );
|
2006-01-26 13:29:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Callback function used in replaceUnusualEscapes().
|
|
|
|
|
|
* Replaces unusual URL escape codes with their equivalent character
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $matches array
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2006-01-26 13:29:14 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
private static function replaceUnusualEscapesCallback( $matches ) {
|
2006-01-26 13:29:14 +00:00
|
|
|
|
$char = urldecode( $matches[0] );
|
|
|
|
|
|
$ord = ord( $char );
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Is it an unsafe or HTTP reserved character according to RFC 1738?
|
2006-01-26 13:29:14 +00:00
|
|
|
|
if ( $ord > 32 && $ord < 127 && strpos( '<>"#{}|\^~[]`;/?', $char ) === false ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# No, shouldn't be escaped
|
2006-01-26 13:29:14 +00:00
|
|
|
|
return $char;
|
|
|
|
|
|
} else {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Yes, leave it escaped
|
2006-01-26 13:29:14 +00:00
|
|
|
|
return $matches[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2005-10-26 22:13:02 +00:00
|
|
|
|
* make an image if it's allowed, either through the global
|
2008-09-01 18:49:14 +00:00
|
|
|
|
* option, through the exception, or through the on-wiki whitelist
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* $param $url string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2005-04-27 07:48:14 +00:00
|
|
|
|
function maybeMakeExternalImage( $url ) {
|
2005-10-26 22:13:02 +00:00
|
|
|
|
$imagesfrom = $this->mOptions->getAllowExternalImagesFrom();
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$imagesexception = !empty( $imagesfrom );
|
2004-08-07 18:24:12 +00:00
|
|
|
|
$text = false;
|
2008-09-01 18:49:14 +00:00
|
|
|
|
# $imagesfrom could be either a single string or an array of strings, parse out the latter
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $imagesexception && is_array( $imagesfrom ) ) {
|
2008-09-01 18:49:14 +00:00
|
|
|
|
$imagematch = false;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
foreach ( $imagesfrom as $match ) {
|
|
|
|
|
|
if ( strpos( $url, $match ) === 0 ) {
|
2008-09-01 18:49:14 +00:00
|
|
|
|
$imagematch = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $imagesexception ) {
|
|
|
|
|
|
$imagematch = ( strpos( $url, $imagesfrom ) === 0 );
|
2008-09-01 18:49:14 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$imagematch = false;
|
|
|
|
|
|
}
|
2006-01-07 13:09:30 +00:00
|
|
|
|
if ( $this->mOptions->getAllowExternalImages()
|
2010-12-11 03:52:35 +00:00
|
|
|
|
|| ( $imagesexception && $imagematch ) ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
if ( preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
|
2004-08-07 18:24:12 +00:00
|
|
|
|
# Image found
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$text = Linker::makeExternalImage( $url );
|
2004-08-07 18:24:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !$text && $this->mOptions->getEnableImageWhitelist()
|
2008-09-01 18:49:14 +00:00
|
|
|
|
&& preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
|
|
|
|
|
|
$whitelist = explode( "\n", wfMsgForContent( 'external_image_whitelist' ) );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
foreach ( $whitelist as $entry ) {
|
2008-09-01 18:49:14 +00:00
|
|
|
|
# Sanitize the regex fragment, make it case-insensitive, ignore blank entries/comments
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( strpos( $entry, '#' ) === 0 || $entry === '' ) {
|
2008-09-01 18:49:14 +00:00
|
|
|
|
continue;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( preg_match( '/' . str_replace( '/', '\\/', $entry ) . '/i', $url ) ) {
|
2008-09-01 18:49:14 +00:00
|
|
|
|
# Image matches a whitelist entry
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$text = Linker::makeExternalImage( $url );
|
2008-09-01 18:49:14 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-08-07 18:24:12 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Process [[ ]] wikilinks
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $s string
|
|
|
|
|
|
*
|
2010-11-13 00:47:51 +00:00
|
|
|
|
* @return String: processed text
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function replaceInternalLinks( $s ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$this->mLinkHolders->merge( $this->replaceInternalLinks2( $s ) );
|
|
|
|
|
|
return $s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Process [[ ]] wikilinks (RIL)
|
|
|
|
|
|
* @return LinkHolderArray
|
|
|
|
|
|
*
|
|
|
|
|
|
* @private
|
|
|
|
|
|
*/
|
|
|
|
|
|
function replaceInternalLinks2( &$s ) {
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__.'-setup' );
|
|
|
|
|
|
static $tc = FALSE, $e1, $e1_img;
|
2004-05-25 14:26:14 +00:00
|
|
|
|
# the % is needed to support urlencoded titles as well
|
2010-01-07 04:13:14 +00:00
|
|
|
|
if ( !$tc ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$tc = Title::legalChars() . '#%';
|
|
|
|
|
|
# Match a link having the form [[namespace:link|alternate]]trail
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
$e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD";
|
2008-08-26 14:37:15 +00:00
|
|
|
|
# Match cases where there is no "]]", which might still be images
|
|
|
|
|
|
$e1_img = "/^([{$tc}]+)\\|(.*)\$/sD";
|
|
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$holders = new LinkHolderArray( $this );
|
2006-11-08 07:12:03 +00:00
|
|
|
|
|
2012-03-19 21:40:39 +00:00
|
|
|
|
# split the entire text string on occurrences of [[
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$a = StringUtils::explode( '[[', ' ' . $s );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
# get the first element (all text up to first [[), and remove the space we added
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$s = $a->current();
|
|
|
|
|
|
$a->next();
|
|
|
|
|
|
$line = $a->current(); # Workaround for broken ArrayIterator::next() that returns "void"
|
2004-05-26 16:29:04 +00:00
|
|
|
|
$s = substr( $s, 1 );
|
|
|
|
|
|
|
2012-03-05 05:53:12 +00:00
|
|
|
|
$useLinkPrefixExtension = $this->getTargetLanguage()->linkPrefixExtension();
|
2007-11-13 09:55:45 +00:00
|
|
|
|
$e2 = null;
|
|
|
|
|
|
if ( $useLinkPrefixExtension ) {
|
|
|
|
|
|
# Match the end of a line for a word that's not followed by whitespace,
|
|
|
|
|
|
# e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched
|
|
|
|
|
|
$e2 = wfMsgForContent( 'linkprefix' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( is_null( $this->mTitle ) ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__.'-setup' );
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
throw new MWException( __METHOD__.": \$this->mTitle is null\n" );
|
2005-02-21 11:28:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
$nottalk = !$this->mTitle->isTalkPage();
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2004-06-02 22:54:01 +00:00
|
|
|
|
if ( $useLinkPrefixExtension ) {
|
2006-10-17 08:49:27 +00:00
|
|
|
|
$m = array();
|
2004-06-02 22:54:01 +00:00
|
|
|
|
if ( preg_match( $e2, $s, $m ) ) {
|
|
|
|
|
|
$first_prefix = $m[2];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$first_prefix = false;
|
|
|
|
|
|
}
|
2004-05-26 16:29:04 +00:00
|
|
|
|
} else {
|
2004-06-02 22:54:01 +00:00
|
|
|
|
$prefix = '';
|
2004-05-26 16:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-03-05 12:14:53 +00:00
|
|
|
|
if ( $this->getConverterLanguage()->hasVariants() ) {
|
2012-05-03 20:02:27 +00:00
|
|
|
|
$selflink = $this->getConverterLanguage()->autoConvertToAllVariants(
|
2012-03-05 05:53:12 +00:00
|
|
|
|
$this->mTitle->getPrefixedText() );
|
2007-01-09 20:57:10 +00:00
|
|
|
|
} else {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$selflink = array( $this->mTitle->getPrefixedText() );
|
2007-01-09 20:57:10 +00:00
|
|
|
|
}
|
2004-11-28 03:29:50 +00:00
|
|
|
|
$useSubpages = $this->areSubpagesAllowed();
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__.'-setup' );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-10-05 03:55:41 +00:00
|
|
|
|
# Loop for each link
|
2008-08-26 14:37:15 +00:00
|
|
|
|
for ( ; $line !== false && $line !== null ; $a->next(), $line = $a->current() ) {
|
|
|
|
|
|
# Check for excessive memory usage
|
|
|
|
|
|
if ( $holders->isBig() ) {
|
|
|
|
|
|
# Too big
|
|
|
|
|
|
# Do the existence check, replace the link holders and clear the array
|
|
|
|
|
|
$holders->replace( $s );
|
|
|
|
|
|
$holders->clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-06-02 22:54:01 +00:00
|
|
|
|
if ( $useLinkPrefixExtension ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__.'-prefixhandling' );
|
2004-06-02 22:54:01 +00:00
|
|
|
|
if ( preg_match( $e2, $s, $m ) ) {
|
|
|
|
|
|
$prefix = $m[2];
|
|
|
|
|
|
$s = $m[1];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$prefix='';
|
|
|
|
|
|
}
|
|
|
|
|
|
# first link
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $first_prefix ) {
|
2004-06-02 22:54:01 +00:00
|
|
|
|
$prefix = $first_prefix;
|
|
|
|
|
|
$first_prefix = false;
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__.'-prefixhandling' );
|
2004-06-02 22:39:06 +00:00
|
|
|
|
}
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2004-10-05 03:55:41 +00:00
|
|
|
|
$might_be_img = false;
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-e1" );
|
2004-05-26 16:29:04 +00:00
|
|
|
|
if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
$text = $m[2];
|
2005-04-12 06:07:23 +00:00
|
|
|
|
# If we get a ] at the beginning of $m[3] that means we have a link that's something like:
|
2008-05-05 20:50:40 +00:00
|
|
|
|
# [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row fucks up,
|
2005-04-12 06:07:23 +00:00
|
|
|
|
# the real problem is with the $e1 regex
|
|
|
|
|
|
# See bug 1300.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2005-05-18 09:21:47 +00:00
|
|
|
|
# Still some problems for cases where the ] is meant to be outside punctuation,
|
|
|
|
|
|
# and no image is in sight. See bug 2095.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $text !== '' &&
|
2006-10-17 08:49:27 +00:00
|
|
|
|
substr( $m[3], 0, 1 ) === ']' &&
|
2010-03-30 21:20:05 +00:00
|
|
|
|
strpos( $text, '[' ) !== false
|
2006-10-17 08:49:27 +00:00
|
|
|
|
)
|
2006-03-24 16:40:31 +00:00
|
|
|
|
{
|
2005-04-12 06:07:23 +00:00
|
|
|
|
$text .= ']'; # so that replaceExternalLinks($text) works later
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$m[3] = substr( $m[3], 1 );
|
2005-04-12 06:07:23 +00:00
|
|
|
|
}
|
2004-05-26 16:29:04 +00:00
|
|
|
|
# fix up urlencoded title texts
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( strpos( $m[1], '%' ) !== false ) {
|
2006-03-24 16:43:57 +00:00
|
|
|
|
# Should anchors '#' also be rejected?
|
2010-12-24 09:53:08 +00:00
|
|
|
|
$m[1] = str_replace( array('<', '>'), array('<', '>'), rawurldecode( $m[1] ) );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
}
|
2004-05-26 16:29:04 +00:00
|
|
|
|
$trail = $m[3];
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( preg_match( $e1_img, $line, $m ) ) { # Invalid, but might be an image with a link in its caption
|
2004-10-05 03:55:41 +00:00
|
|
|
|
$might_be_img = true;
|
|
|
|
|
|
$text = $m[2];
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
if ( strpos( $m[1], '%' ) !== false ) {
|
2010-12-24 09:53:08 +00:00
|
|
|
|
$m[1] = rawurldecode( $m[1] );
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
}
|
2004-10-05 03:55:41 +00:00
|
|
|
|
$trail = "";
|
2004-10-05 00:21:52 +00:00
|
|
|
|
} else { # Invalid form; output directly
|
|
|
|
|
|
$s .= $prefix . '[[' . $line ;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-e1" );
|
2004-10-05 00:21:52 +00:00
|
|
|
|
continue;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-e1" );
|
|
|
|
|
|
wfProfileIn( __METHOD__."-misc" );
|
2004-05-26 16:29:04 +00:00
|
|
|
|
|
2004-09-24 18:29:01 +00:00
|
|
|
|
# Don't allow internal links to pages containing
|
|
|
|
|
|
# PROTO: where PROTO is a valid URL protocol; these
|
|
|
|
|
|
# should be external links.
|
2012-04-14 17:07:51 +00:00
|
|
|
|
if ( preg_match( '/^(?:' . $this->mUrlProtocols . ')/', $m[1] ) ) {
|
2004-09-24 18:29:01 +00:00
|
|
|
|
$s .= $prefix . '[[' . $line ;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-misc" );
|
2004-09-24 18:29:01 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-25 20:35:38 +00:00
|
|
|
|
# Make subpage if necessary
|
2009-07-03 05:13:58 +00:00
|
|
|
|
if ( $useSubpages ) {
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
$link = $this->maybeDoSubpageLink( $m[1], $text );
|
2004-11-28 03:29:50 +00:00
|
|
|
|
} else {
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
$link = $m[1];
|
2004-11-28 03:29:50 +00:00
|
|
|
|
}
|
2004-09-25 20:35:38 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$noforce = ( substr( $m[1], 0, 1 ) !== ':' );
|
|
|
|
|
|
if ( !$noforce ) {
|
2004-09-25 20:35:38 +00:00
|
|
|
|
# Strip off leading ':'
|
2009-07-03 05:13:58 +00:00
|
|
|
|
$link = substr( $link, 1 );
|
2004-09-25 20:35:38 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-misc" );
|
|
|
|
|
|
wfProfileIn( __METHOD__."-title" );
|
2009-07-03 05:13:58 +00:00
|
|
|
|
$nt = Title::newFromText( $this->mStripState->unstripNoWiki( $link ) );
|
2009-12-11 21:07:27 +00:00
|
|
|
|
if ( $nt === null ) {
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$s .= $prefix . '[[' . $line;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-title" );
|
2004-05-26 16:29:04 +00:00
|
|
|
|
continue;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-10-04 03:47:39 +00:00
|
|
|
|
|
2004-05-26 16:29:04 +00:00
|
|
|
|
$ns = $nt->getNamespace();
|
|
|
|
|
|
$iw = $nt->getInterWiki();
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-title" );
|
2006-10-17 08:49:27 +00:00
|
|
|
|
|
2009-07-03 05:13:58 +00:00
|
|
|
|
if ( $might_be_img ) { # if this is actually an invalid link
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-might_be_img" );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $ns == NS_FILE && $noforce ) { # but might be an image
|
2004-10-05 03:55:41 +00:00
|
|
|
|
$found = false;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
while ( true ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
# look at the next 'line' to see if we can close it there
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$a->next();
|
|
|
|
|
|
$next_line = $a->current();
|
|
|
|
|
|
if ( $next_line === false || $next_line === null ) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$m = explode( ']]', $next_line, 3 );
|
|
|
|
|
|
if ( count( $m ) == 3 ) {
|
|
|
|
|
|
# the first ]] closes the inner link, the second the image
|
2004-10-05 03:55:41 +00:00
|
|
|
|
$found = true;
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$text .= "[[{$m[0]}]]{$m[1]}";
|
2004-10-05 03:55:41 +00:00
|
|
|
|
$trail = $m[2];
|
|
|
|
|
|
break;
|
2006-08-06 14:01:47 +00:00
|
|
|
|
} elseif ( count( $m ) == 2 ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
# if there's exactly one ]] that's fine, we'll keep looking
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$text .= "[[{$m[0]}]]{$m[1]}";
|
2004-10-05 03:55:41 +00:00
|
|
|
|
} else {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
# if $next_line is invalid too, we need look no further
|
2004-10-05 03:55:41 +00:00
|
|
|
|
$text .= '[[' . $next_line;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( !$found ) {
|
|
|
|
|
|
# we couldn't find the end of this imageLink, so output it raw
|
2010-03-30 21:20:05 +00:00
|
|
|
|
# but don't ignore what might be perfectly normal links in the text we've examined
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$holders->merge( $this->replaceInternalLinks2( $text ) );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$s .= "{$prefix}[[$link|$text";
|
2004-10-05 03:55:41 +00:00
|
|
|
|
# note: no $trail, because without an end, there *is* no trail
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-might_be_img" );
|
2004-10-05 03:55:41 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else { # it's not an image, so output it raw
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$s .= "{$prefix}[[$link|$text";
|
2004-10-05 03:55:41 +00:00
|
|
|
|
# note: no $trail, because without an end, there *is* no trail
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-might_be_img" );
|
2004-10-05 03:55:41 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-might_be_img" );
|
2004-10-05 03:55:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-06 19:59:42 +00:00
|
|
|
|
$wasblank = ( $text == '' );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $wasblank ) {
|
|
|
|
|
|
$text = $link;
|
2010-06-23 23:29:54 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
# Bug 4598 madness. Handle the quotes only if they come from the alternate part
|
2010-12-14 09:01:48 +00:00
|
|
|
|
# [[Lista d''e paise d''o munno]] -> <a href="...">Lista d''e paise d''o munno</a>
|
2010-12-19 04:31:15 +00:00
|
|
|
|
# [[Criticism of Harry Potter|Criticism of ''Harry Potter'']]
|
2010-12-14 09:01:48 +00:00
|
|
|
|
# -> <a href="Criticism of Harry Potter">Criticism of <i>Harry Potter</i></a>
|
|
|
|
|
|
$text = $this->doQuotes( $text );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2004-10-05 03:55:41 +00:00
|
|
|
|
|
2004-08-16 20:01:21 +00:00
|
|
|
|
# Link not escaped by : , create the various objects
|
2009-07-03 05:13:58 +00:00
|
|
|
|
if ( $noforce ) {
|
2004-08-16 20:01:21 +00:00
|
|
|
|
# Interwikis
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-interwiki" );
|
2012-03-08 19:30:30 +00:00
|
|
|
|
if ( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && Language::fetchLanguageName( $iw, null, 'mw' ) ) {
|
2012-08-06 17:28:57 +00:00
|
|
|
|
// FIXME: the above check prevents links to sites with identifiers that are not language codes
|
2005-12-30 09:33:11 +00:00
|
|
|
|
$this->mOutput->addLanguageLink( $nt->getFullText() );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$s = rtrim( $s . $prefix );
|
|
|
|
|
|
$s .= trim( $trail, "\n" ) == '' ? '': $prefix . $trail;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-interwiki" );
|
2004-05-26 16:29:04 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-interwiki" );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2008-12-01 17:14:30 +00:00
|
|
|
|
if ( $ns == NS_FILE ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-image" );
|
2006-09-25 01:35:41 +00:00
|
|
|
|
if ( !wfIsBadImage( $nt->getDBkey(), $this->mTitle ) ) {
|
2009-07-03 05:13:58 +00:00
|
|
|
|
if ( $wasblank ) {
|
|
|
|
|
|
# if no parameters were passed, $text
|
|
|
|
|
|
# becomes something like "File:Foo.png",
|
|
|
|
|
|
# which we don't want to pass on to the
|
|
|
|
|
|
# image generator
|
|
|
|
|
|
$text = '';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# recursively parse links inside the image caption
|
|
|
|
|
|
# actually, this will parse them in any other parameters, too,
|
|
|
|
|
|
# but it might be hard to fix that, and it doesn't matter ATM
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$text = $this->replaceExternalLinks( $text );
|
2009-07-03 05:13:58 +00:00
|
|
|
|
$holders->merge( $this->replaceInternalLinks2( $text ) );
|
|
|
|
|
|
}
|
2005-04-12 04:03:21 +00:00
|
|
|
|
# cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them
|
2011-03-23 03:13:37 +00:00
|
|
|
|
$s .= $prefix . $this->armorLinks(
|
|
|
|
|
|
$this->makeImage( $nt, $text, $holders ) ) . $trail;
|
2010-01-31 18:26:37 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$s .= $prefix . $trail;
|
2005-04-12 04:03:21 +00:00
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-image" );
|
|
|
|
|
|
continue;
|
2004-05-27 01:10:01 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-08-07 03:50:46 +00:00
|
|
|
|
if ( $ns == NS_CATEGORY ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-category" );
|
2010-12-10 18:23:33 +00:00
|
|
|
|
$s = rtrim( $s . "\n" ); # bug 87
|
2004-05-26 16:29:04 +00:00
|
|
|
|
|
2004-09-07 22:08:01 +00:00
|
|
|
|
if ( $wasblank ) {
|
2006-12-29 10:39:35 +00:00
|
|
|
|
$sortkey = $this->getDefaultSort();
|
2004-09-07 22:08:01 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$sortkey = $text;
|
|
|
|
|
|
}
|
2005-12-05 08:19:52 +00:00
|
|
|
|
$sortkey = Sanitizer::decodeCharReferences( $sortkey );
|
2006-06-23 09:20:44 +00:00
|
|
|
|
$sortkey = str_replace( "\n", '', $sortkey );
|
2012-03-05 12:14:53 +00:00
|
|
|
|
$sortkey = $this->getConverterLanguage()->convertCategoryKey( $sortkey );
|
2005-12-30 09:33:11 +00:00
|
|
|
|
$this->mOutput->addCategory( $nt->getDBkey(), $sortkey );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2005-04-09 00:31:40 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Strip the whitespace Category links produce, see bug 87
|
|
|
|
|
|
* @todo We might want to use trim($tmp, "\n") here.
|
|
|
|
|
|
*/
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$s .= trim( $prefix . $trail, "\n" ) == '' ? '' : $prefix . $trail;
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-category" );
|
2004-05-26 16:29:04 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-10-08 04:27:07 +00:00
|
|
|
|
|
2007-01-17 19:29:11 +00:00
|
|
|
|
# Self-link checking
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $nt->getFragment() === '' && $ns != NS_SPECIAL ) {
|
|
|
|
|
|
if ( in_array( $nt->getPrefixedText(), $selflink, true ) ) {
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$s .= $prefix . Linker::makeSelfLinkObj( $nt, $text, '', $trail );
|
2007-01-17 19:29:11 +00:00
|
|
|
|
continue;
|
2007-01-17 19:48:48 +00:00
|
|
|
|
}
|
2004-04-20 21:08:24 +00:00
|
|
|
|
}
|
2004-03-20 12:10:25 +00:00
|
|
|
|
|
2008-12-13 04:14:40 +00:00
|
|
|
|
# NS_MEDIA is a pseudo-namespace for linking directly to a file
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: Should do batch file existence checks, see comment below
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $ns == NS_MEDIA ) {
|
2009-02-27 23:44:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-media" );
|
2008-04-19 21:29:19 +00:00
|
|
|
|
# Give extensions a chance to select the file revision for us
|
2011-09-06 18:11:53 +00:00
|
|
|
|
$options = array();
|
|
|
|
|
|
$descQuery = false;
|
2011-03-24 01:44:48 +00:00
|
|
|
|
wfRunHooks( 'BeforeParserFetchFileAndTitle',
|
2011-09-06 18:11:53 +00:00
|
|
|
|
array( $this, $nt, &$options, &$descQuery ) );
|
2011-03-24 01:44:48 +00:00
|
|
|
|
# Fetch and register the file (file title may be different via hooks)
|
2011-09-06 18:11:53 +00:00
|
|
|
|
list( $file, $nt ) = $this->fetchFileAndTitle( $nt, $options );
|
2005-12-21 14:02:20 +00:00
|
|
|
|
# Cloak with NOPARSE to avoid replacement in replaceExternalLinks
|
2011-03-24 01:44:48 +00:00
|
|
|
|
$s .= $prefix . $this->armorLinks(
|
2011-04-03 11:44:11 +00:00
|
|
|
|
Linker::makeMediaLinkFile( $nt, $file, $text ) ) . $trail;
|
2009-02-27 23:44:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-media" );
|
2004-06-05 02:22:16 +00:00
|
|
|
|
continue;
|
2004-05-26 16:29:04 +00:00
|
|
|
|
}
|
2008-12-13 04:14:40 +00:00
|
|
|
|
|
2009-02-27 23:44:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-always_known" );
|
2008-12-13 04:14:40 +00:00
|
|
|
|
# Some titles, such as valid special pages or files in foreign repos, should
|
|
|
|
|
|
# be shown as bluelinks even though they're not included in the page table
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: isAlwaysKnown() can be expensive for file links; we should really do
|
2008-12-13 04:14:40 +00:00
|
|
|
|
# batch file existence checks for NS_FILE and NS_MEDIA
|
2010-04-18 00:39:12 +00:00
|
|
|
|
if ( $iw == '' && $nt->isAlwaysKnown() ) {
|
2009-01-01 00:05:08 +00:00
|
|
|
|
$this->mOutput->addLink( $nt );
|
2011-03-13 14:00:38 +00:00
|
|
|
|
$s .= $this->makeKnownLinkHolder( $nt, $text, array(), $trail, $prefix );
|
2008-12-13 04:14:40 +00:00
|
|
|
|
} else {
|
2009-01-01 00:05:08 +00:00
|
|
|
|
# Links will be added to the output link list after checking
|
2011-03-15 16:47:55 +00:00
|
|
|
|
$s .= $holders->makeHolder( $nt, $text, array(), $trail, $prefix );
|
2008-12-13 04:14:40 +00:00
|
|
|
|
}
|
2009-02-27 23:44:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-always_known" );
|
2004-02-28 23:38:08 +00:00
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
return $holders;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2005-12-29 00:31:18 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Render a forced-blue link inline; protect against double expansion of
|
|
|
|
|
|
* URLs if we're in a mode that prepends full URL prefixes to internal links.
|
|
|
|
|
|
* Since this little disaster has to split off the trail text to avoid
|
|
|
|
|
|
* breaking URLs in the following text without breaking trails on the
|
|
|
|
|
|
* wiki links, it's been made into a horrible function.
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $nt Title
|
|
|
|
|
|
* @param $text String
|
2011-03-13 14:00:38 +00:00
|
|
|
|
* @param $query Array or String
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $trail String
|
|
|
|
|
|
* @param $prefix String
|
|
|
|
|
|
* @return String: HTML-wikitext mix oh yuck
|
2005-12-29 00:31:18 +00:00
|
|
|
|
*/
|
2011-03-13 14:00:38 +00:00
|
|
|
|
function makeKnownLinkHolder( $nt, $text = '', $query = array(), $trail = '', $prefix = '' ) {
|
2005-12-29 00:31:18 +00:00
|
|
|
|
list( $inside, $trail ) = Linker::splitTrail( $trail );
|
2011-03-13 14:00:38 +00:00
|
|
|
|
|
|
|
|
|
|
if ( is_string( $query ) ) {
|
|
|
|
|
|
$query = wfCgiToArray( $query );
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $text == '' ) {
|
2011-03-19 13:00:11 +00:00
|
|
|
|
$text = htmlspecialchars( $nt->getPrefixedText() );
|
2011-03-13 14:00:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$link = Linker::linkKnown( $nt, "$prefix$text$inside", array(), $query );
|
2011-03-13 14:00:38 +00:00
|
|
|
|
|
2005-12-29 00:31:18 +00:00
|
|
|
|
return $this->armorLinks( $link ) . $trail;
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-12-28 22:58:54 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Insert a NOPARSE hacky thing into any inline links in a chunk that's
|
|
|
|
|
|
* going to go through further parsing steps before inline URL expansion.
|
|
|
|
|
|
*
|
2008-08-26 14:37:15 +00:00
|
|
|
|
* Not needed quite as much as it used to be since free links are a bit
|
|
|
|
|
|
* more sensible these days. But bracketed links are still an issue.
|
2005-12-28 22:58:54 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String: more-or-less HTML
|
|
|
|
|
|
* @return String: less-or-more HTML with NOPARSE bits
|
2005-12-28 22:58:54 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function armorLinks( $text ) {
|
2012-04-14 17:07:51 +00:00
|
|
|
|
return preg_replace( '/\b(' . $this->mUrlProtocols . ')/',
|
2005-12-28 22:58:54 +00:00
|
|
|
|
"{$this->mUniqPrefix}NOPARSE$1", $text );
|
|
|
|
|
|
}
|
2005-04-27 07:48:14 +00:00
|
|
|
|
|
2004-11-28 03:29:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return true if subpage links should be expanded on this page.
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return Boolean
|
2004-11-28 03:29:50 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function areSubpagesAllowed() {
|
|
|
|
|
|
# Some namespaces don't allow subpages
|
2008-05-23 22:00:14 +00:00
|
|
|
|
return MWNamespace::hasSubpages( $this->mTitle->getNamespace() );
|
2004-11-28 03:29:50 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2004-09-25 20:13:14 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Handle link to subpage if necessary
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $target String: the source of the link
|
|
|
|
|
|
* @param &$text String: the link text, modified as necessary
|
2004-09-25 20:13:14 +00:00
|
|
|
|
* @return string the full name of the link
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2004-09-25 20:13:14 +00:00
|
|
|
|
*/
|
2010-03-30 21:20:05 +00:00
|
|
|
|
function maybeDoSubpageLink( $target, &$text ) {
|
2009-07-20 02:07:56 +00:00
|
|
|
|
return Linker::normalizeSubpageLink( $this->mTitle, $target, $text );
|
2004-09-25 20:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**#@+
|
|
|
|
|
|
* Used by doBlockLevels()
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2010-03-30 21:53:56 +00:00
|
|
|
|
function closeParagraph() {
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$result = '';
|
2010-01-27 02:41:22 +00:00
|
|
|
|
if ( $this->mLastSection != '' ) {
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$result = '</' . $this->mLastSection . ">\n";
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-04-15 14:25:34 +00:00
|
|
|
|
$this->mInPre = false;
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$this->mLastSection = '';
|
2004-04-09 13:40:50 +00:00
|
|
|
|
return $result;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-06-10 21:05:58 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* getCommon() returns the length of the longest common substring
|
|
|
|
|
|
* of both arguments, starting at the beginning of both.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $st1 string
|
|
|
|
|
|
* @param $st2 string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return int
|
2010-05-15 10:35:54 +00:00
|
|
|
|
*/
|
2010-03-30 21:20:05 +00:00
|
|
|
|
function getCommon( $st1, $st2 ) {
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$fl = strlen( $st1 );
|
|
|
|
|
|
$shorter = strlen( $st2 );
|
2010-05-15 10:35:54 +00:00
|
|
|
|
if ( $fl < $shorter ) {
|
|
|
|
|
|
$shorter = $fl;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
|
|
|
|
|
for ( $i = 0; $i < $shorter; ++$i ) {
|
2011-04-17 07:59:58 +00:00
|
|
|
|
if ( $st1[$i] != $st2[$i] ) {
|
2010-05-15 10:35:54 +00:00
|
|
|
|
break;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $i;
|
|
|
|
|
|
}
|
2010-06-10 21:05:58 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* These next three functions open, continue, and close the list
|
|
|
|
|
|
* element appropriate to the prefix character passed into them.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @param $char string
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return string
|
2010-03-30 21:20:05 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function openList( $char ) {
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$result = $this->closeParagraph();
|
|
|
|
|
|
|
2010-05-15 10:35:54 +00:00
|
|
|
|
if ( '*' === $char ) {
|
|
|
|
|
|
$result .= '<ul><li>';
|
|
|
|
|
|
} elseif ( '#' === $char ) {
|
|
|
|
|
|
$result .= '<ol><li>';
|
|
|
|
|
|
} elseif ( ':' === $char ) {
|
|
|
|
|
|
$result .= '<dl><dd>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( ';' === $char ) {
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$result .= '<dl><dt>';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$this->mDTopen = true;
|
2010-05-15 10:35:54 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$result = '<!-- ERR 1 -->';
|
2009-08-27 17:16:15 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* TODO: document
|
|
|
|
|
|
* @param $char String
|
|
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2010-03-30 21:53:56 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function nextItem( $char ) {
|
2010-05-15 10:35:54 +00:00
|
|
|
|
if ( '*' === $char || '#' === $char ) {
|
|
|
|
|
|
return '</li><li>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( ':' === $char || ';' === $char ) {
|
2004-08-16 15:29:17 +00:00
|
|
|
|
$close = '</dd>';
|
2010-05-15 10:35:54 +00:00
|
|
|
|
if ( $this->mDTopen ) {
|
|
|
|
|
|
$close = '</dt>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( ';' === $char ) {
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$this->mDTopen = true;
|
2004-06-08 18:11:28 +00:00
|
|
|
|
return $close . '<dt>';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$this->mDTopen = false;
|
2004-06-08 18:11:28 +00:00
|
|
|
|
return $close . '<dd>';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-06-08 18:11:28 +00:00
|
|
|
|
return '<!-- ERR 2 -->';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* TODO: document
|
|
|
|
|
|
* @param $char String
|
|
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2010-03-30 21:53:56 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function closeList( $char ) {
|
2010-05-15 10:35:54 +00:00
|
|
|
|
if ( '*' === $char ) {
|
|
|
|
|
|
$text = '</li></ul>';
|
|
|
|
|
|
} elseif ( '#' === $char ) {
|
|
|
|
|
|
$text = '</li></ol>';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( ':' === $char ) {
|
2004-02-26 13:37:26 +00:00
|
|
|
|
if ( $this->mDTopen ) {
|
|
|
|
|
|
$this->mDTopen = false;
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$text = '</dt></dl>';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
} else {
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$text = '</dd></dl>';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-05-15 10:35:54 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
return '<!-- ERR 3 -->';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $text."\n";
|
|
|
|
|
|
}
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**#@-*/
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2008-08-26 14:37:15 +00:00
|
|
|
|
* Make lists from lines starting with ':', '*', '#', etc. (DBL)
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @param $linestart Boolean: whether or not this is at the start of a line.
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2004-09-21 05:49:12 +00:00
|
|
|
|
* @return string the lists rendered as HTML
|
|
|
|
|
|
*/
|
|
|
|
|
|
function doBlockLevels( $text, $linestart ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2004-02-26 13:37:26 +00:00
|
|
|
|
# Parsing through the text line by line. The main thing
|
|
|
|
|
|
# happening here is handling of block-level elements p, pre,
|
|
|
|
|
|
# and making lists from lines starting with * # : etc.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$textLines = StringUtils::explode( "\n", $text );
|
2004-04-11 16:46:06 +00:00
|
|
|
|
|
2005-04-21 06:30:48 +00:00
|
|
|
|
$lastPrefix = $output = '';
|
2004-04-11 16:46:06 +00:00
|
|
|
|
$this->mDTopen = $inBlockElem = false;
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$prefixLength = 0;
|
|
|
|
|
|
$paragraphStack = false;
|
|
|
|
|
|
|
|
|
|
|
|
foreach ( $textLines as $oLine ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
# Fix up $linestart
|
|
|
|
|
|
if ( !$linestart ) {
|
|
|
|
|
|
$output .= $oLine;
|
|
|
|
|
|
$linestart = true;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# * = ul
|
|
|
|
|
|
# # = ol
|
|
|
|
|
|
# ; = dt
|
|
|
|
|
|
# : = dd
|
2008-08-26 14:37:15 +00:00
|
|
|
|
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$lastPrefixLength = strlen( $lastPrefix );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$preCloseMatch = preg_match( '/<\\/pre/i', $oLine );
|
|
|
|
|
|
$preOpenMatch = preg_match( '/<pre/i', $oLine );
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# If not in a <pre> element, scan for and figure out what prefixes are there.
|
2004-07-14 18:46:02 +00:00
|
|
|
|
if ( !$this->mInPre ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# Multiple prefixes may abut each other for nested lists.
|
2009-08-27 17:16:15 +00:00
|
|
|
|
$prefixLength = strspn( $oLine, '*#:;' );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$prefix = substr( $oLine, 0, $prefixLength );
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# eh?
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# ; and : are both from definition-lists, so they're equivalent
|
|
|
|
|
|
# for the purposes of determining whether or not we need to open/close
|
|
|
|
|
|
# elements.
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$prefix2 = str_replace( ';', ':', $prefix );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$t = substr( $oLine, $prefixLength );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$this->mInPre = (bool)$preOpenMatch;
|
2004-04-16 11:21:51 +00:00
|
|
|
|
} else {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# Don't interpret any other prefixes in preformatted text
|
|
|
|
|
|
$prefixLength = 0;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$prefix = $prefix2 = '';
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$t = $oLine;
|
2004-04-16 11:21:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# List generation
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $prefixLength && $lastPrefix === $prefix2 ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# Same as the last item, so no need to deal with nesting or opening stuff
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$output .= $this->nextItem( substr( $prefix, -1 ) );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$paragraphStack = false;
|
2004-04-16 11:21:51 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( substr( $prefix, -1 ) === ';') {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# The one nasty exception: definition lists work like this:
|
|
|
|
|
|
# ; title : definition text
|
|
|
|
|
|
# So we check for : in the remainder text to split up the
|
|
|
|
|
|
# title and definition, without b0rking links.
|
2005-04-21 06:30:48 +00:00
|
|
|
|
$term = $t2 = '';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
|
2004-09-27 21:01:39 +00:00
|
|
|
|
$t = $t2;
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$output .= $term . $this->nextItem( ':' );
|
2004-04-16 11:21:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $prefixLength || $lastPrefixLength ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# We need to open or close prefixes, or both.
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# Either open or close a level...
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$commonPrefixLength = $this->getCommon( $prefix, $lastPrefix );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$paragraphStack = false;
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Close all the prefixes which aren't shared.
|
2010-03-30 21:20:05 +00:00
|
|
|
|
while ( $commonPrefixLength < $lastPrefixLength ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$output .= $this->closeList( $lastPrefix[$lastPrefixLength-1] );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
--$lastPrefixLength;
|
2004-04-16 11:21:51 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Continue the current prefix if appropriate.
|
2004-04-29 06:16:21 +00:00
|
|
|
|
if ( $prefixLength <= $commonPrefixLength && $commonPrefixLength > 0 ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$output .= $this->nextItem( $prefix[$commonPrefixLength-1] );
|
2004-04-16 11:21:51 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Open prefixes where appropriate.
|
2004-04-29 06:16:21 +00:00
|
|
|
|
while ( $prefixLength > $commonPrefixLength ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$char = substr( $prefix, $commonPrefixLength, 1 );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$output .= $this->openList( $char );
|
2004-04-16 11:21:51 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( ';' === $char ) {
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: This is dupe of code above
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
|
2004-09-27 21:01:39 +00:00
|
|
|
|
$t = $t2;
|
2004-08-22 17:24:50 +00:00
|
|
|
|
$output .= $term . $this->nextItem( ':' );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-04-29 06:16:21 +00:00
|
|
|
|
++$commonPrefixLength;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$lastPrefix = $prefix2;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# If we have no prefixes, go to paragraph mode.
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( 0 == $prefixLength ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__."-paragraph" );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
# No prefix (not in list)--go to paragraph mode
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# XXX: use a stack for nestable elements like span, table and div
|
2007-04-13 00:23:49 +00:00
|
|
|
|
$openmatch = preg_match('/(?:<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<li|<\\/tr|<\\/td|<\\/th)/iS', $t );
|
2004-04-12 23:59:37 +00:00
|
|
|
|
$closematch = preg_match(
|
2007-04-13 00:23:49 +00:00
|
|
|
|
'/(?:<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'.
|
2006-12-17 16:51:01 +00:00
|
|
|
|
'<td|<th|<\\/?div|<hr|<\\/pre|<\\/p|'.$this->mUniqPrefix.'-pre|<\\/li|<\\/ul|<\\/ol|<\\/?center)/iS', $t );
|
2004-04-09 13:40:50 +00:00
|
|
|
|
if ( $openmatch or $closematch ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$paragraphStack = false;
|
2011-04-12 21:27:24 +00:00
|
|
|
|
# TODO bug 5718: paragraph closed
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$output .= $this->closeParagraph();
|
2005-07-22 22:14:05 +00:00
|
|
|
|
if ( $preOpenMatch and !$preCloseMatch ) {
|
|
|
|
|
|
$this->mInPre = true;
|
|
|
|
|
|
}
|
2010-09-02 23:12:47 +00:00
|
|
|
|
$inBlockElem = !$closematch;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( !$inBlockElem && !$this->mInPre ) {
|
|
|
|
|
|
if ( ' ' == substr( $t, 0, 1 ) and ( $this->mLastSection === 'pre' || trim( $t ) != '' ) ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# pre
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->mLastSection !== 'pre' ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$paragraphStack = false;
|
|
|
|
|
|
$output .= $this->closeParagraph().'<pre>';
|
2004-04-10 15:11:14 +00:00
|
|
|
|
$this->mLastSection = 'pre';
|
2004-04-10 03:09:52 +00:00
|
|
|
|
}
|
2004-09-12 13:07:52 +00:00
|
|
|
|
$t = substr( $t, 1 );
|
2004-04-12 23:59:37 +00:00
|
|
|
|
} else {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# paragraph
|
2010-05-28 14:16:46 +00:00
|
|
|
|
if ( trim( $t ) === '' ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
if ( $paragraphStack ) {
|
2004-05-31 00:58:57 +00:00
|
|
|
|
$output .= $paragraphStack.'<br />';
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$paragraphStack = false;
|
2004-04-10 15:11:14 +00:00
|
|
|
|
$this->mLastSection = 'p';
|
|
|
|
|
|
} else {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->mLastSection !== 'p' ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$output .= $this->closeParagraph();
|
2004-04-10 15:11:14 +00:00
|
|
|
|
$this->mLastSection = '';
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$paragraphStack = '<p>';
|
2004-04-10 15:11:14 +00:00
|
|
|
|
} else {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$paragraphStack = '</p><p>';
|
2004-04-10 15:11:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
if ( $paragraphStack ) {
|
|
|
|
|
|
$output .= $paragraphStack;
|
|
|
|
|
|
$paragraphStack = false;
|
2004-04-10 15:11:14 +00:00
|
|
|
|
$this->mLastSection = 'p';
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $this->mLastSection !== 'p' ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$output .= $this->closeParagraph().'<p>';
|
2004-04-10 15:11:14 +00:00
|
|
|
|
$this->mLastSection = 'p';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-04-09 13:40:50 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__."-paragraph" );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# somewhere above we forget to get out of pre block (bug 785)
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $preCloseMatch && $this->mInPre ) {
|
2005-07-13 15:17:28 +00:00
|
|
|
|
$this->mInPre = false;
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $paragraphStack === false ) {
|
2004-04-29 06:16:21 +00:00
|
|
|
|
$output .= $t."\n";
|
2004-04-10 15:11:14 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-04-29 06:16:21 +00:00
|
|
|
|
while ( $prefixLength ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$output .= $this->closeList( $prefix2[$prefixLength-1] );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
--$prefixLength;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-01-27 02:41:22 +00:00
|
|
|
|
if ( $this->mLastSection != '' ) {
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$output .= '</' . $this->mLastSection . '>';
|
|
|
|
|
|
$this->mLastSection = '';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-04-29 06:16:21 +00:00
|
|
|
|
return $output;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-27 21:01:39 +00:00
|
|
|
|
/**
|
2012-03-19 21:40:39 +00:00
|
|
|
|
* Split up a string on ':', ignoring any occurrences inside tags
|
2006-06-02 20:54:34 +00:00
|
|
|
|
* to prevent illegal overlapping.
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $str String the string to split
|
|
|
|
|
|
* @param &$before String set to everything before the ':'
|
|
|
|
|
|
* @param &$after String set to everything after the ':'
|
|
|
|
|
|
* @return String the position of the ':', or false if none found
|
2004-09-27 21:01:39 +00:00
|
|
|
|
*/
|
2010-03-30 21:20:05 +00:00
|
|
|
|
function findColonNoLinks( $str, &$before, &$after ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2006-06-02 20:54:34 +00:00
|
|
|
|
$pos = strpos( $str, ':' );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $pos === false ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Nothing to find!
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 20:54:34 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2006-06-02 23:56:19 +00:00
|
|
|
|
$lt = strpos( $str, '<' );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $lt === false || $lt > $pos ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Easy; no tag nesting to worry about
|
2006-06-02 20:54:34 +00:00
|
|
|
|
$before = substr( $str, 0, $pos );
|
|
|
|
|
|
$after = substr( $str, $pos+1 );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 20:54:34 +00:00
|
|
|
|
return $pos;
|
|
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Ugly state machine to walk through avoiding tags.
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TEXT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
$stack = 0;
|
|
|
|
|
|
$len = strlen( $str );
|
|
|
|
|
|
for( $i = 0; $i < $len; $i++ ) {
|
2011-04-17 07:59:58 +00:00
|
|
|
|
$c = $str[$i];
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2006-06-02 20:54:34 +00:00
|
|
|
|
switch( $state ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# (Using the number is a performance hack for common cases)
|
|
|
|
|
|
case 0: # self::COLON_STATE_TEXT:
|
2006-06-02 20:54:34 +00:00
|
|
|
|
switch( $c ) {
|
|
|
|
|
|
case "<":
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Could be either a <start> tag or an </end> tag
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TAGSTART;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case ":":
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $stack == 0 ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# We found it!
|
2006-06-02 20:54:34 +00:00
|
|
|
|
$before = substr( $str, 0, $i );
|
|
|
|
|
|
$after = substr( $str, $i + 1 );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 20:54:34 +00:00
|
|
|
|
return $i;
|
|
|
|
|
|
}
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Embedded in a tag; don't break it.
|
2006-06-02 20:54:34 +00:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Skip ahead looking for something interesting
|
2006-06-02 23:56:19 +00:00
|
|
|
|
$colon = strpos( $str, ':', $i );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $colon === false ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Nothing else interesting
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 23:56:19 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
$lt = strpos( $str, '<', $i );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $stack === 0 ) {
|
|
|
|
|
|
if ( $lt === false || $colon < $lt ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# We found it!
|
2006-06-02 23:56:19 +00:00
|
|
|
|
$before = substr( $str, 0, $colon );
|
|
|
|
|
|
$after = substr( $str, $colon + 1 );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 23:56:19 +00:00
|
|
|
|
return $i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $lt === false ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Nothing else interesting to find; abort!
|
|
|
|
|
|
# We're nested, but there's no close tags left. Abort!
|
2006-06-02 23:56:19 +00:00
|
|
|
|
break 2;
|
|
|
|
|
|
}
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Skip ahead to next tag start
|
2006-06-02 23:56:19 +00:00
|
|
|
|
$i = $lt;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TAGSTART;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
case 1: # self::COLON_STATE_TAG:
|
|
|
|
|
|
# In a <tag>
|
2006-06-02 20:54:34 +00:00
|
|
|
|
switch( $c ) {
|
|
|
|
|
|
case ">":
|
|
|
|
|
|
$stack++;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TEXT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case "/":
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Slash may be followed by >?
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TAGSLASH;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# ignore
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
case 2: # self::COLON_STATE_TAGSTART:
|
2006-06-02 20:54:34 +00:00
|
|
|
|
switch( $c ) {
|
|
|
|
|
|
case "/":
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_CLOSETAG;
|
2004-09-27 21:01:39 +00:00
|
|
|
|
break;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
case "!":
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_COMMENT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case ">":
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Illegal early close? This shouldn't happen D:
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TEXT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TAG;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
case 3: # self::COLON_STATE_CLOSETAG:
|
|
|
|
|
|
# In a </tag>
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $c === ">" ) {
|
2006-06-02 20:54:34 +00:00
|
|
|
|
$stack--;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $stack < 0 ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfDebug( __METHOD__.": Invalid input; too many close tags\n" );
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 20:54:34 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TEXT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
case self::COLON_STATE_TAGSLASH:
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $c === ">" ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Yes, a self-closed tag <blah/>
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TEXT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
} else {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Probably we're jumping the gun, and this is an attribute
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TAG;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
case 5: # self::COLON_STATE_COMMENT:
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $c === "-" ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_COMMENTDASH;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
case self::COLON_STATE_COMMENTDASH:
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $c === "-" ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_COMMENTDASHDASH;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
} else {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_COMMENT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
case self::COLON_STATE_COMMENTDASHDASH:
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $c === ">" ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_TEXT;
|
2006-06-02 20:54:34 +00:00
|
|
|
|
} else {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$state = self::COLON_STATE_COMMENT;
|
2004-09-27 21:01:39 +00:00
|
|
|
|
}
|
2006-06-02 20:54:34 +00:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2008-08-26 14:37:15 +00:00
|
|
|
|
throw new MWException( "State machine error in " . __METHOD__ );
|
2004-09-27 21:01:39 +00:00
|
|
|
|
}
|
2006-06-02 20:54:34 +00:00
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $stack > 0 ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfDebug( __METHOD__.": Invalid input; not enough close tags (stack $stack, state $state)\n" );
|
2011-02-10 16:11:34 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 20:54:34 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-06-02 20:54:34 +00:00
|
|
|
|
return false;
|
2004-09-27 21:01:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return value of a magic variable (like PAGENAME)
|
|
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $index integer
|
|
|
|
|
|
* @param $frame PPFrame
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2011-08-05 00:33:03 +00:00
|
|
|
|
function getVariableValue( $index, $frame = false ) {
|
2010-09-29 15:47:56 +00:00
|
|
|
|
global $wgContLang, $wgSitename, $wgServer;
|
2010-08-05 15:21:15 +00:00
|
|
|
|
global $wgArticlePath, $wgScriptPath, $wgStylePath;
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2011-08-17 00:46:58 +00:00
|
|
|
|
if ( is_null( $this->mTitle ) ) {
|
|
|
|
|
|
// If no title set, bad things are going to happen
|
|
|
|
|
|
// later. Title should always be set since this
|
|
|
|
|
|
// should only be called in the middle of a parse
|
|
|
|
|
|
// operation (but the unit-tests do funky stuff)
|
|
|
|
|
|
throw new MWException( __METHOD__ . ' Should only be '
|
|
|
|
|
|
. ' called while parsing (no title set)' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-11-21 14:07:24 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Some of these require message or data lookups and can be
|
|
|
|
|
|
* expensive to check many times.
|
|
|
|
|
|
*/
|
2008-01-24 04:29:56 +00:00
|
|
|
|
if ( wfRunHooks( 'ParserGetVariableValueVarCache', array( &$this, &$this->mVarCache ) ) ) {
|
|
|
|
|
|
if ( isset( $this->mVarCache[$index] ) ) {
|
|
|
|
|
|
return $this->mVarCache[$index];
|
2006-10-17 08:49:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2005-11-26 23:04:05 +00:00
|
|
|
|
|
2008-01-24 04:29:56 +00:00
|
|
|
|
$ts = wfTimestamp( TS_UNIX, $this->mOptions->getTimestamp() );
|
2005-11-26 23:04:05 +00:00
|
|
|
|
wfRunHooks( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2006-08-23 16:45:49 +00:00
|
|
|
|
# Use the time zone
|
|
|
|
|
|
global $wgLocaltimezone;
|
|
|
|
|
|
if ( isset( $wgLocaltimezone ) ) {
|
2010-01-08 01:48:53 +00:00
|
|
|
|
$oldtz = date_default_timezone_get();
|
|
|
|
|
|
date_default_timezone_set( $wgLocaltimezone );
|
2006-08-23 16:45:49 +00:00
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2006-08-23 16:45:49 +00:00
|
|
|
|
$localTimestamp = date( 'YmdHis', $ts );
|
|
|
|
|
|
$localMonth = date( 'm', $ts );
|
2009-05-20 07:14:03 +00:00
|
|
|
|
$localMonth1 = date( 'n', $ts );
|
2006-08-23 16:45:49 +00:00
|
|
|
|
$localMonthName = date( 'n', $ts );
|
|
|
|
|
|
$localDay = date( 'j', $ts );
|
|
|
|
|
|
$localDay2 = date( 'd', $ts );
|
|
|
|
|
|
$localDayOfWeek = date( 'w', $ts );
|
|
|
|
|
|
$localWeek = date( 'W', $ts );
|
|
|
|
|
|
$localYear = date( 'Y', $ts );
|
|
|
|
|
|
$localHour = date( 'H', $ts );
|
|
|
|
|
|
if ( isset( $wgLocaltimezone ) ) {
|
2010-01-08 01:48:53 +00:00
|
|
|
|
date_default_timezone_set( $oldtz );
|
2006-08-23 16:45:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$pageLang = $this->getFunctionLang();
|
|
|
|
|
|
|
2004-03-20 15:03:26 +00:00
|
|
|
|
switch ( $index ) {
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentmonth':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( gmdate( 'm', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2009-05-20 07:14:03 +00:00
|
|
|
|
case 'currentmonth1':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( gmdate( 'n', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentmonthname':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getMonthName( gmdate( 'n', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentmonthnamegen':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getMonthNameGen( gmdate( 'n', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentmonthabbrev':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getMonthAbbreviation( gmdate( 'n', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentday':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( gmdate( 'j', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentday2':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( gmdate( 'd', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localmonth':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( $localMonth );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2009-05-20 07:14:03 +00:00
|
|
|
|
case 'localmonth1':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( $localMonth1 );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localmonthname':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getMonthName( $localMonthName );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localmonthnamegen':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getMonthNameGen( $localMonthName );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localmonthabbrev':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getMonthAbbreviation( $localMonthName );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localday':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( $localDay );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localday2':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( $localDay2 );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'pagename':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfEscapeWikiText( $this->mTitle->getText() );
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'pagenamee':
|
2011-01-18 20:15:50 +00:00
|
|
|
|
$value = wfEscapeWikiText( $this->mTitle->getPartialURL() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'fullpagename':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfEscapeWikiText( $this->mTitle->getPrefixedText() );
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'fullpagenamee':
|
2011-01-18 20:15:50 +00:00
|
|
|
|
$value = wfEscapeWikiText( $this->mTitle->getPrefixedURL() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'subpagename':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfEscapeWikiText( $this->mTitle->getSubpageText() );
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'subpagenamee':
|
2011-01-18 20:15:50 +00:00
|
|
|
|
$value = wfEscapeWikiText( $this->mTitle->getSubpageUrlForm() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'basepagename':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfEscapeWikiText( $this->mTitle->getBaseText() );
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'basepagenamee':
|
2011-01-18 20:15:50 +00:00
|
|
|
|
$value = wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getBaseText() ) ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'talkpagename':
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->mTitle->canTalk() ) {
|
2006-04-12 15:38:17 +00:00
|
|
|
|
$talkPage = $this->mTitle->getTalkPage();
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfEscapeWikiText( $talkPage->getPrefixedText() );
|
2006-04-12 15:38:17 +00:00
|
|
|
|
} else {
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = '';
|
2006-04-12 15:38:17 +00:00
|
|
|
|
}
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'talkpagenamee':
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->mTitle->canTalk() ) {
|
2006-04-12 15:38:17 +00:00
|
|
|
|
$talkPage = $this->mTitle->getTalkPage();
|
2011-01-18 20:15:50 +00:00
|
|
|
|
$value = wfEscapeWikiText( $talkPage->getPrefixedUrl() );
|
2006-04-12 15:38:17 +00:00
|
|
|
|
} else {
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = '';
|
2006-04-12 15:38:17 +00:00
|
|
|
|
}
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'subjectpagename':
|
2006-04-12 15:38:17 +00:00
|
|
|
|
$subjPage = $this->mTitle->getSubjectPage();
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfEscapeWikiText( $subjPage->getPrefixedText() );
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'subjectpagenamee':
|
2006-04-12 15:38:17 +00:00
|
|
|
|
$subjPage = $this->mTitle->getSubjectPage();
|
2011-01-18 20:15:50 +00:00
|
|
|
|
$value = wfEscapeWikiText( $subjPage->getPrefixedUrl() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2012-06-25 11:39:29 +00:00
|
|
|
|
case 'pageid': // requested in bug 23427
|
|
|
|
|
|
$pageid = $this->getTitle()->getArticleId();
|
|
|
|
|
|
if( $pageid == 0 ) {
|
|
|
|
|
|
# 0 means the page doesn't exist in the database,
|
|
|
|
|
|
# which means the user is previewing a new page.
|
|
|
|
|
|
# The vary-revision flag must be set, because the magic word
|
|
|
|
|
|
# will have a different value once the page is saved.
|
|
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{PAGEID}} used in a new page, setting vary-revision...\n" );
|
|
|
|
|
|
}
|
|
|
|
|
|
$value = $pageid ? $pageid : null;
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'revisionid':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned.
|
2007-11-15 02:54:28 +00:00
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONID}} used, setting vary-revision...\n" );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = $this->mRevisionId;
|
|
|
|
|
|
break;
|
2006-09-26 17:20:36 +00:00
|
|
|
|
case 'revisionday':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned. This is for null edits.
|
2008-01-06 03:17:09 +00:00
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONDAY}} used, setting vary-revision...\n" );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = intval( substr( $this->getRevisionTimestamp(), 6, 2 ) );
|
|
|
|
|
|
break;
|
2006-09-26 17:20:36 +00:00
|
|
|
|
case 'revisionday2':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned. This is for null edits.
|
2008-01-06 03:17:09 +00:00
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONDAY2}} used, setting vary-revision...\n" );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = substr( $this->getRevisionTimestamp(), 6, 2 );
|
|
|
|
|
|
break;
|
2006-09-26 17:20:36 +00:00
|
|
|
|
case 'revisionmonth':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned. This is for null edits.
|
2008-01-06 03:17:09 +00:00
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONMONTH}} used, setting vary-revision...\n" );
|
2010-05-11 16:24:14 +00:00
|
|
|
|
$value = substr( $this->getRevisionTimestamp(), 4, 2 );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'revisionmonth1':
|
|
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned. This is for null edits.
|
|
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONMONTH1}} used, setting vary-revision...\n" );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = intval( substr( $this->getRevisionTimestamp(), 4, 2 ) );
|
|
|
|
|
|
break;
|
2006-09-26 17:20:36 +00:00
|
|
|
|
case 'revisionyear':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned. This is for null edits.
|
2008-01-06 03:17:09 +00:00
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONYEAR}} used, setting vary-revision...\n" );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = substr( $this->getRevisionTimestamp(), 0, 4 );
|
|
|
|
|
|
break;
|
2006-09-26 17:20:36 +00:00
|
|
|
|
case 'revisiontimestamp':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned. This is for null edits.
|
2008-01-06 03:17:09 +00:00
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONTIMESTAMP}} used, setting vary-revision...\n" );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = $this->getRevisionTimestamp();
|
|
|
|
|
|
break;
|
2009-03-07 23:01:59 +00:00
|
|
|
|
case 'revisionuser':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Let the edit saving system know we should parse the page
|
|
|
|
|
|
# *after* a revision ID has been assigned. This is for null edits.
|
2009-03-07 23:01:59 +00:00
|
|
|
|
$this->mOutput->setFlag( 'vary-revision' );
|
|
|
|
|
|
wfDebug( __METHOD__ . ": {{REVISIONUSER}} used, setting vary-revision...\n" );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = $this->getRevisionUser();
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'namespace':
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$value = str_replace( '_',' ',$wgContLang->getNsText( $this->mTitle->getNamespace() ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'namespacee':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfUrlencode( $wgContLang->getNsText( $this->mTitle->getNamespace() ) );
|
|
|
|
|
|
break;
|
2012-04-01 10:27:59 +00:00
|
|
|
|
case 'namespacenumber':
|
|
|
|
|
|
$value = $this->mTitle->getNamespace();
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'talkspace':
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$value = $this->mTitle->canTalk() ? str_replace( '_',' ',$this->mTitle->getTalkNsText() ) : '';
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'talkspacee':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = $this->mTitle->canTalk() ? wfUrlencode( $this->mTitle->getTalkNsText() ) : '';
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'subjectspace':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = $this->mTitle->getSubjectNsText();
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'subjectspacee':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = ( wfUrlencode( $this->mTitle->getSubjectNsText() ) );
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentdayname':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getWeekdayName( gmdate( 'w', $ts ) + 1 );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentyear':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( gmdate( 'Y', $ts ), true );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currenttime':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->time( wfTimestamp( TS_MW, $ts ), false, false );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-14 22:43:50 +00:00
|
|
|
|
case 'currenthour':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( gmdate( 'H', $ts ), true );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentweek':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
|
|
|
|
|
|
# int to remove the padding
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( (int)gmdate( 'W', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentdow':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( gmdate( 'w', $ts ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localdayname':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->getWeekdayName( $localDayOfWeek + 1 );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localyear':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( $localYear, true );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localtime':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->time( $localTimestamp, false, false );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localhour':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( $localHour, true );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localweek':
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
|
|
|
|
|
|
# int to remove the padding
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( (int)$localWeek );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localdow':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( $localDayOfWeek );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'numberofarticles':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( SiteStats::articles() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'numberoffiles':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( SiteStats::images() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'numberofusers':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( SiteStats::users() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2009-02-17 23:05:04 +00:00
|
|
|
|
case 'numberofactiveusers':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( SiteStats::activeUsers() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'numberofpages':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( SiteStats::pages() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'numberofadmins':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( SiteStats::numberingroup( 'sysop' ) );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2007-04-17 09:23:31 +00:00
|
|
|
|
case 'numberofedits':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
$value = $pageLang->formatNum( SiteStats::edits() );
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2008-10-19 04:11:02 +00:00
|
|
|
|
case 'numberofviews':
|
2012-06-06 17:29:16 +00:00
|
|
|
|
global $wgDisableCounters;
|
|
|
|
|
|
$value = !$wgDisableCounters ? $pageLang->formatNum( SiteStats::views() ) : '';
|
2009-10-02 09:46:17 +00:00
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currenttimestamp':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = wfTimestamp( TS_MW, $ts );
|
|
|
|
|
|
break;
|
2006-08-23 16:45:49 +00:00
|
|
|
|
case 'localtimestamp':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = $localTimestamp;
|
|
|
|
|
|
break;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'currentversion':
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$value = SpecialVersion::getVersion();
|
|
|
|
|
|
break;
|
2010-08-05 15:21:15 +00:00
|
|
|
|
case 'articlepath':
|
|
|
|
|
|
return $wgArticlePath;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'sitename':
|
2004-04-05 10:38:40 +00:00
|
|
|
|
return $wgSitename;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'server':
|
2004-04-05 10:38:40 +00:00
|
|
|
|
return $wgServer;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'servername':
|
2011-09-26 23:16:32 +00:00
|
|
|
|
$serverParts = wfParseUrl( $wgServer );
|
2011-09-26 23:14:20 +00:00
|
|
|
|
return $serverParts && isset( $serverParts['host'] ) ? $serverParts['host'] : $wgServer;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'scriptpath':
|
2005-06-19 16:09:00 +00:00
|
|
|
|
return $wgScriptPath;
|
2009-12-16 12:02:41 +00:00
|
|
|
|
case 'stylepath':
|
|
|
|
|
|
return $wgStylePath;
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'directionmark':
|
2011-08-16 19:29:52 +00:00
|
|
|
|
return $pageLang->getDirMark();
|
2006-07-14 15:39:23 +00:00
|
|
|
|
case 'contentlanguage':
|
2010-09-07 22:37:55 +00:00
|
|
|
|
global $wgLanguageCode;
|
|
|
|
|
|
return $wgLanguageCode;
|
2004-03-20 15:03:26 +00:00
|
|
|
|
default:
|
2005-11-25 06:53:20 +00:00
|
|
|
|
$ret = null;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( wfRunHooks( 'ParserGetVariableValueSwitch', array( &$this, &$this->mVarCache, &$index, &$ret, &$frame ) ) ) {
|
2005-11-25 06:53:20 +00:00
|
|
|
|
return $ret;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else {
|
2005-11-25 06:53:20 +00:00
|
|
|
|
return null;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2004-03-20 15:03:26 +00:00
|
|
|
|
}
|
2009-10-02 09:46:17 +00:00
|
|
|
|
|
2011-08-05 00:33:03 +00:00
|
|
|
|
if ( $index ) {
|
2009-10-02 09:46:17 +00:00
|
|
|
|
$this->mVarCache[$index] = $value;
|
2011-08-05 00:33:03 +00:00
|
|
|
|
}
|
2009-10-02 09:46:17 +00:00
|
|
|
|
|
|
|
|
|
|
return $value;
|
2004-03-20 15:03:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2010-05-15 10:35:54 +00:00
|
|
|
|
* initialise the magic variables (like CURRENTMONTHNAME) and substitution modifiers
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2004-06-12 06:15:09 +00:00
|
|
|
|
function initialiseVariables() {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2006-07-14 16:36:35 +00:00
|
|
|
|
$variableIDs = MagicWord::getVariableIDs();
|
2010-01-30 11:58:19 +00:00
|
|
|
|
$substIDs = MagicWord::getSubstIDs();
|
2006-07-03 11:07:00 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$this->mVariables = new MagicWordArray( $variableIDs );
|
2010-02-15 09:34:51 +00:00
|
|
|
|
$this->mSubstWords = new MagicWordArray( $substIDs );
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-03-20 15:03:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2005-10-19 06:24:30 +00:00
|
|
|
|
/**
|
2008-01-05 12:39:12 +00:00
|
|
|
|
* Preprocess some wikitext and return the document tree.
|
2008-09-15 06:37:57 +00:00
|
|
|
|
* This is the ghost of replace_variables().
|
2005-10-19 06:24:30 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String: The text to parse
|
|
|
|
|
|
* @param $flags Integer: bitwise combination of:
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* self::PTD_FOR_INCLUSION Handle "<noinclude>" and "<includeonly>" as if the text is being
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* included. Default is to assume a direct page view.
|
2008-01-05 12:39:12 +00:00
|
|
|
|
*
|
2008-01-19 09:03:45 +00:00
|
|
|
|
* The generated DOM tree must depend only on the input text and the flags.
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of bug 4899.
|
2008-01-05 12:39:12 +00:00
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* Any flag added to the $flags parameter here, or any other parameter liable to cause a
|
|
|
|
|
|
* change in the DOM tree for a given text, must be passed through the section identifier
|
|
|
|
|
|
* in the section edit link and thus back to extractSections().
|
2008-01-05 12:39:12 +00:00
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* The output of this function is currently only cached in process memory, but a persistent
|
|
|
|
|
|
* cache may be implemented at a later date which takes further advantage of these strict
|
2008-01-05 12:39:12 +00:00
|
|
|
|
* dependency requirements.
|
|
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return PPNode
|
2005-10-19 06:24:30 +00:00
|
|
|
|
*/
|
2010-03-30 21:20:05 +00:00
|
|
|
|
function preprocessToDom( $text, $flags = 0 ) {
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$dom = $this->getPreprocessor()->preprocessToObj( $text, $flags );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
return $dom;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
/**
|
2007-11-20 10:55:08 +00:00
|
|
|
|
* Return a three-element array: leading whitespace, string contents, trailing whitespace
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $s string
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return array
|
2007-11-20 10:55:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public static function splitWhitespace( $s ) {
|
|
|
|
|
|
$ltrimmed = ltrim( $s );
|
|
|
|
|
|
$w1 = substr( $s, 0, strlen( $s ) - strlen( $ltrimmed ) );
|
|
|
|
|
|
$trimmed = rtrim( $ltrimmed );
|
|
|
|
|
|
$diff = strlen( $ltrimmed ) - strlen( $trimmed );
|
|
|
|
|
|
if ( $diff > 0 ) {
|
|
|
|
|
|
$w2 = substr( $ltrimmed, -$diff );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$w2 = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
return array( $w1, $trimmed, $w2 );
|
2005-10-19 06:24:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Replace magic variables, templates, and template arguments
|
|
|
|
|
|
* with the appropriate text. Templates are substituted recursively,
|
|
|
|
|
|
* taking care to avoid infinite loops.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Note that the substitution depends on value of $mOutputType:
|
2008-01-22 10:47:44 +00:00
|
|
|
|
* self::OT_WIKI: only {{subst:}} templates
|
|
|
|
|
|
* self::OT_PREPROCESS: templates but not extension tags
|
|
|
|
|
|
* self::OT_HTML: all templates and extension tags
|
2005-07-03 07:15:53 +00:00
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $text String the text to transform
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $frame PPFrame Object describing the arguments passed to the template.
|
2008-06-26 13:05:40 +00:00
|
|
|
|
* 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.
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $argsOnly Boolean only do argument (triple-brace) expansion, not double-brace expansion
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function replaceVariables( $text, $frame = false, $argsOnly = false ) {
|
2009-03-02 02:06:01 +00:00
|
|
|
|
# Is there any text? Also, Prevent too big inclusions!
|
|
|
|
|
|
if ( strlen( $text ) < 1 || strlen( $text ) > $this->mOptions->getMaxIncludeSize() ) {
|
2004-11-21 14:07:24 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
if ( $frame === false ) {
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$frame = $this->getPreprocessor()->newFrame();
|
2007-11-20 10:55:08 +00:00
|
|
|
|
} elseif ( !( $frame instanceof PPFrame ) ) {
|
2008-06-26 13:05:40 +00:00
|
|
|
|
wfDebug( __METHOD__." called using plain parameters instead of a PPFrame instance. Creating custom frame.\n" );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$frame = $this->getPreprocessor()->newCustomFrame( $frame );
|
2004-05-23 03:39:24 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$dom = $this->preprocessToDom( $text );
|
|
|
|
|
|
$flags = $argsOnly ? PPFrame::NO_TEMPLATES : 0;
|
2007-12-01 07:13:31 +00:00
|
|
|
|
$text = $frame->expand( $dom, $flags );
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-09-21 23:30:46 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-01 23:54:41 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Clean up argument array - refactored in 1.9 so parserfunctions can use it, too.
|
|
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $args array
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2006-12-11 23:50:41 +00:00
|
|
|
|
static function createAssocArgs( $args ) {
|
|
|
|
|
|
$assocArgs = array();
|
|
|
|
|
|
$index = 1;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
foreach ( $args as $arg ) {
|
2006-12-11 23:50:41 +00:00
|
|
|
|
$eqpos = strpos( $arg, '=' );
|
|
|
|
|
|
if ( $eqpos === false ) {
|
|
|
|
|
|
$assocArgs[$index++] = $arg;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$name = trim( substr( $arg, 0, $eqpos ) );
|
|
|
|
|
|
$value = trim( substr( $arg, $eqpos+1 ) );
|
|
|
|
|
|
if ( $value === false ) {
|
|
|
|
|
|
$value = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $name !== false ) {
|
|
|
|
|
|
$assocArgs[$name] = $value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-12-11 23:50:41 +00:00
|
|
|
|
return $assocArgs;
|
|
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2008-05-19 21:33:47 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Warn the user when a parser limitation is reached
|
|
|
|
|
|
* Will warn at most once the user per limitation type
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $limitationType String: should be one of:
|
2010-05-15 10:35:54 +00:00
|
|
|
|
* 'expensive-parserfunction' (corresponding messages:
|
|
|
|
|
|
* 'expensive-parserfunction-warning',
|
2010-03-30 21:20:05 +00:00
|
|
|
|
* 'expensive-parserfunction-category')
|
2010-05-15 10:35:54 +00:00
|
|
|
|
* 'post-expand-template-argument' (corresponding messages:
|
|
|
|
|
|
* 'post-expand-template-argument-warning',
|
2010-03-30 21:20:05 +00:00
|
|
|
|
* 'post-expand-template-argument-category')
|
2010-05-15 10:35:54 +00:00
|
|
|
|
* 'post-expand-template-inclusion' (corresponding messages:
|
|
|
|
|
|
* 'post-expand-template-inclusion-warning',
|
2010-03-30 21:20:05 +00:00
|
|
|
|
* 'post-expand-template-inclusion-category')
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @param $current int|null Current value
|
|
|
|
|
|
* @param $max int|null Maximum allowed, when an explicit limit has been
|
2008-05-19 21:33:47 +00:00
|
|
|
|
* exceeded, provide the values (optional)
|
|
|
|
|
|
*/
|
2012-02-09 19:29:36 +00:00
|
|
|
|
function limitationWarn( $limitationType, $current = null, $max = null) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# does no harm if $current and $max are present but are unnecessary for the message
|
2010-01-07 04:13:14 +00:00
|
|
|
|
$warning = wfMsgExt( "$limitationType-warning", array( 'parsemag', 'escape' ), $current, $max );
|
2008-05-19 21:33:47 +00:00
|
|
|
|
$this->mOutput->addWarning( $warning );
|
2009-10-11 12:52:08 +00:00
|
|
|
|
$this->addTrackingCategory( "$limitationType-category" );
|
2008-05-19 21:33:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return the text of a template, after recursively
|
|
|
|
|
|
* replacing any variables or templates within the template.
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $piece Array: the parts of the template
|
2005-10-19 06:24:30 +00:00
|
|
|
|
* $piece['title']: the title, i.e. the part before the |
|
|
|
|
|
|
* $piece['parts']: the parameter array
|
2008-01-21 16:36:08 +00:00
|
|
|
|
* $piece['lineStart']: whether the brace was at the start of a line
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $frame PPFrame The current frame, contains template arguments
|
|
|
|
|
|
* @return String: the text of the template
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function braceSubstitution( $piece, $frame ) {
|
2012-05-05 08:22:28 +00:00
|
|
|
|
global $wgContLang;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileIn( __METHOD__.'-setup' );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2006-03-11 17:13:49 +00:00
|
|
|
|
# Flags
|
2006-02-01 04:41:53 +00:00
|
|
|
|
$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
|
2011-09-29 22:08:00 +00:00
|
|
|
|
$forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$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
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2006-02-01 04:41:53 +00:00
|
|
|
|
# Title object, where $text came from
|
2011-11-08 20:58:57 +00:00
|
|
|
|
$title = false;
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
|
# $part1 is the bit before the first |, and must contain only title characters.
|
|
|
|
|
|
# Various prefixes will be stripped from it later.
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$titleWithSpaces = $frame->expand( $piece['title'] );
|
|
|
|
|
|
$part1 = trim( $titleWithSpaces );
|
|
|
|
|
|
$titleText = false;
|
2004-09-25 05:16:38 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# Original title text preserved for various purposes
|
|
|
|
|
|
$originalTitle = $part1;
|
2006-10-17 08:49:27 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# $args is a list of argument nodes, starting from index 0, not including $part1
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: If piece['parts'] is null then the call to getLength() below won't work b/c this $args isn't an object
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$args = ( null == $piece['parts'] ) ? array() : $piece['parts'];
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileOut( __METHOD__.'-setup' );
|
2011-10-27 01:19:34 +00:00
|
|
|
|
|
|
|
|
|
|
$titleProfileIn = null; // profile templates
|
2011-06-17 16:05:05 +00:00
|
|
|
|
|
2004-03-20 15:03:26 +00:00
|
|
|
|
# SUBST
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileIn( __METHOD__.'-modifiers' );
|
2004-05-23 03:39:24 +00:00
|
|
|
|
if ( !$found ) {
|
2010-01-30 11:58:19 +00:00
|
|
|
|
|
2010-02-15 09:34:51 +00:00
|
|
|
|
$substMatch = $this->mSubstWords->matchStartAndRemove( $part1 );
|
2010-01-30 11:58:19 +00:00
|
|
|
|
|
2010-01-30 12:46:16 +00:00
|
|
|
|
# Possibilities for substMatch: "subst", "safesubst" or FALSE
|
2010-02-15 09:34:51 +00:00
|
|
|
|
# Decide whether to expand template or keep wikitext as-is.
|
2010-02-22 07:02:12 +00:00
|
|
|
|
if ( $this->ot['wiki'] ) {
|
2010-02-15 09:34:51 +00:00
|
|
|
|
if ( $substMatch === false ) {
|
|
|
|
|
|
$literal = true; # literal when in PST with no prefix
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$literal = false; # expand when in PST with subst: or safesubst:
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if ( $substMatch == 'subst' ) {
|
|
|
|
|
|
$literal = true; # literal when not in PST with plain subst:
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$literal = false; # expand when not in PST with safesubst: or no prefix
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $literal ) {
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$text = $frame->virtualBracketedImplode( '{{', '|', '}}', $titleWithSpaces, $args );
|
|
|
|
|
|
$isLocalObj = true;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$found = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Variables
|
2008-01-21 16:36:08 +00:00
|
|
|
|
if ( !$found && $args->getLength() == 0 ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$id = $this->mVariables->matchStartToEnd( $part1 );
|
|
|
|
|
|
if ( $id !== false ) {
|
2009-08-30 06:37:10 +00:00
|
|
|
|
$text = $this->getVariableValue( $id, $frame );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( MagicWord::getCacheTTL( $id ) > -1 ) {
|
2010-07-19 23:08:52 +00:00
|
|
|
|
$this->mOutput->updateCacheExpiry( MagicWord::getCacheTTL( $id ) );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2004-03-20 15:03:26 +00:00
|
|
|
|
$found = true;
|
|
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2006-09-30 04:53:36 +00:00
|
|
|
|
# MSG, MSGNW and RAW
|
2004-03-20 15:03:26 +00:00
|
|
|
|
if ( !$found ) {
|
|
|
|
|
|
# Check for MSGNW:
|
2008-04-09 18:23:34 +00:00
|
|
|
|
$mwMsgnw = MagicWord::get( 'msgnw' );
|
2004-04-11 16:46:06 +00:00
|
|
|
|
if ( $mwMsgnw->matchStartAndRemove( $part1 ) ) {
|
2004-03-20 15:03:26 +00:00
|
|
|
|
$nowiki = true;
|
2005-06-12 13:39:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
# Remove obsolete MSG:
|
2008-04-09 18:23:34 +00:00
|
|
|
|
$mwMsg = MagicWord::get( 'msg' );
|
2005-06-12 13:39:28 +00:00
|
|
|
|
$mwMsg->matchStartAndRemove( $part1 );
|
2004-03-20 15:03:26 +00:00
|
|
|
|
}
|
2011-07-30 15:56:54 +00:00
|
|
|
|
|
|
|
|
|
|
# Check for RAW:
|
|
|
|
|
|
$mwRaw = MagicWord::get( 'raw' );
|
|
|
|
|
|
if ( $mwRaw->matchStartAndRemove( $part1 ) ) {
|
|
|
|
|
|
$forceRawInterwiki = true;
|
|
|
|
|
|
}
|
2004-03-20 15:03:26 +00:00
|
|
|
|
}
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileOut( __METHOD__.'-modifiers' );
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2006-07-03 11:07:00 +00:00
|
|
|
|
# Parser functions
|
2004-04-05 10:38:40 +00:00
|
|
|
|
if ( !$found ) {
|
2006-07-03 11:07:00 +00:00
|
|
|
|
wfProfileIn( __METHOD__ . '-pfunc' );
|
2006-10-17 08:49:27 +00:00
|
|
|
|
|
2006-07-03 11:07:00 +00:00
|
|
|
|
$colonPos = strpos( $part1, ':' );
|
|
|
|
|
|
if ( $colonPos !== false ) {
|
|
|
|
|
|
# Case sensitive functions
|
|
|
|
|
|
$function = substr( $part1, 0, $colonPos );
|
|
|
|
|
|
if ( isset( $this->mFunctionSynonyms[1][$function] ) ) {
|
|
|
|
|
|
$function = $this->mFunctionSynonyms[1][$function];
|
2004-04-05 10:38:40 +00:00
|
|
|
|
} else {
|
2006-07-03 11:07:00 +00:00
|
|
|
|
# Case insensitive functions
|
2012-03-05 05:53:12 +00:00
|
|
|
|
$function = $wgContLang->lc( $function );
|
2006-07-03 11:07:00 +00:00
|
|
|
|
if ( isset( $this->mFunctionSynonyms[0][$function] ) ) {
|
|
|
|
|
|
$function = $this->mFunctionSynonyms[0][$function];
|
2006-04-30 18:02:03 +00:00
|
|
|
|
} else {
|
2006-07-03 11:07:00 +00:00
|
|
|
|
$function = false;
|
2006-04-30 18:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-07-03 11:07:00 +00:00
|
|
|
|
if ( $function ) {
|
2011-10-27 21:53:37 +00:00
|
|
|
|
wfProfileIn( __METHOD__ . '-pfunc-' . $function );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
list( $callback, $flags ) = $this->mFunctionHooks[$function];
|
|
|
|
|
|
$initialArgs = array( &$this );
|
|
|
|
|
|
$funcArgs = array( trim( substr( $part1, $colonPos + 1 ) ) );
|
|
|
|
|
|
if ( $flags & SFH_OBJECT_ARGS ) {
|
|
|
|
|
|
# Add a frame parameter, and pass the arguments as an array
|
|
|
|
|
|
$allArgs = $initialArgs;
|
|
|
|
|
|
$allArgs[] = $frame;
|
2008-01-21 16:36:08 +00:00
|
|
|
|
for ( $i = 0; $i < $args->getLength(); $i++ ) {
|
|
|
|
|
|
$funcArgs[] = $args->item( $i );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
$allArgs[] = $funcArgs;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# Convert arguments to plain text
|
2008-01-21 16:36:08 +00:00
|
|
|
|
for ( $i = 0; $i < $args->getLength(); $i++ ) {
|
|
|
|
|
|
$funcArgs[] = trim( $frame->expand( $args->item( $i ) ) );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
$allArgs = array_merge( $initialArgs, $funcArgs );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-01-25 07:43:23 +00:00
|
|
|
|
# Workaround for PHP bug 35229 and similar
|
|
|
|
|
|
if ( !is_callable( $callback ) ) {
|
2011-10-27 21:53:37 +00:00
|
|
|
|
wfProfileOut( __METHOD__ . '-pfunc-' . $function );
|
2009-04-05 01:10:52 +00:00
|
|
|
|
wfProfileOut( __METHOD__ . '-pfunc' );
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2008-09-21 07:18:24 +00:00
|
|
|
|
throw new MWException( "Tag hook for $function is not callable\n" );
|
2008-01-25 07:43:23 +00:00
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$result = call_user_func_array( $callback, $allArgs );
|
2006-04-05 09:40:25 +00:00
|
|
|
|
$found = true;
|
2008-05-10 18:31:05 +00:00
|
|
|
|
$noparse = true;
|
|
|
|
|
|
$preprocessFlags = 0;
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2006-04-05 09:40:25 +00:00
|
|
|
|
if ( is_array( $result ) ) {
|
2006-07-03 11:07:00 +00:00
|
|
|
|
if ( isset( $result[0] ) ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = $result[0];
|
2006-07-03 11:07:00 +00:00
|
|
|
|
unset( $result[0] );
|
|
|
|
|
|
}
|
2006-04-05 09:40:25 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Extract flags into the local scope
|
|
|
|
|
|
# This allows callers to set flags such as nowiki, found, etc.
|
2006-04-05 09:40:25 +00:00
|
|
|
|
extract( $result );
|
|
|
|
|
|
} else {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = $result;
|
2006-04-05 09:40:25 +00:00
|
|
|
|
}
|
2008-05-10 18:31:05 +00:00
|
|
|
|
if ( !$noparse ) {
|
|
|
|
|
|
$text = $this->preprocessToDom( $text, $preprocessFlags );
|
|
|
|
|
|
$isChildObj = true;
|
|
|
|
|
|
}
|
2011-10-27 21:53:37 +00:00
|
|
|
|
wfProfileOut( __METHOD__ . '-pfunc-' . $function );
|
2006-04-05 09:40:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
wfProfileOut( __METHOD__ . '-pfunc' );
|
2006-04-05 09:40:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# Finish mangling title and then check for loops.
|
|
|
|
|
|
# Set $title to a Title object and $titleText to the PDBK
|
2004-03-20 15:03:26 +00:00
|
|
|
|
if ( !$found ) {
|
2004-09-25 20:13:14 +00:00
|
|
|
|
$ns = NS_TEMPLATE;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# Split the title into page and subpage
|
2006-03-24 16:44:52 +00:00
|
|
|
|
$subpage = '';
|
|
|
|
|
|
$part1 = $this->maybeDoSubpageLink( $part1, $subpage );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $subpage !== '' ) {
|
2004-09-25 20:13:14 +00:00
|
|
|
|
$ns = $this->mTitle->getNamespace();
|
|
|
|
|
|
}
|
|
|
|
|
|
$title = Title::newFromText( $part1, $ns );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
if ( $title ) {
|
2006-08-17 22:20:06 +00:00
|
|
|
|
$titleText = $title->getPrefixedText();
|
2006-06-17 08:55:44 +00:00
|
|
|
|
# Check for language variants if the template is not found
|
2012-03-05 12:14:53 +00:00
|
|
|
|
if ( $this->getConverterLanguage()->hasVariants() && $title->getArticleID() == 0 ) {
|
|
|
|
|
|
$this->getConverterLanguage()->findVariantLink( $part1, $title, true );
|
2006-06-17 08:55:44 +00:00
|
|
|
|
}
|
2008-01-11 03:25:41 +00:00
|
|
|
|
# Do recursion depth check
|
|
|
|
|
|
$limit = $this->mOptions->getMaxTemplateDepth();
|
|
|
|
|
|
if ( $frame->depth >= $limit ) {
|
|
|
|
|
|
$found = true;
|
2010-05-15 10:35:54 +00:00
|
|
|
|
$text = '<span class="error">'
|
|
|
|
|
|
. wfMsgForContent( 'parser-template-recursion-depth-warning', $limit )
|
2010-03-30 21:20:05 +00:00
|
|
|
|
. '</span>';
|
2008-01-11 03:25:41 +00:00
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-06-17 08:55:44 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# Load from database
|
|
|
|
|
|
if ( !$found && $title ) {
|
2012-05-03 20:02:27 +00:00
|
|
|
|
if ( !Profiler::instance()->isPersistent() ) {
|
|
|
|
|
|
# Too many unique items can kill profiling DBs/collectors
|
|
|
|
|
|
$titleProfileIn = __METHOD__ . "-title-" . $title->getDBKey();
|
|
|
|
|
|
wfProfileIn( $titleProfileIn ); // template in
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
wfProfileIn( __METHOD__ . '-loadtpl' );
|
|
|
|
|
|
if ( !$title->isExternal() ) {
|
2011-11-02 20:55:08 +00:00
|
|
|
|
if ( $title->isSpecialPage()
|
2010-05-15 10:35:54 +00:00
|
|
|
|
&& $this->mOptions->getAllowSpecialInclusion()
|
|
|
|
|
|
&& $this->ot['html'] )
|
2010-03-30 21:20:05 +00:00
|
|
|
|
{
|
2011-09-29 15:14:34 +00:00
|
|
|
|
// Pass the template arguments as URL parameters.
|
|
|
|
|
|
// "uselang" will have no effect since the Language object
|
|
|
|
|
|
// is forced to the one defined in ParserOptions.
|
2011-08-02 15:40:03 +00:00
|
|
|
|
$pageArgs = array();
|
|
|
|
|
|
for ( $i = 0; $i < $args->getLength(); $i++ ) {
|
|
|
|
|
|
$bits = $args->item( $i )->splitArg();
|
|
|
|
|
|
if ( strval( $bits['index'] ) === '' ) {
|
|
|
|
|
|
$name = trim( $frame->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
|
|
|
|
|
|
$value = trim( $frame->expand( $bits['value'] ) );
|
|
|
|
|
|
$pageArgs[$name] = $value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-09-29 15:14:34 +00:00
|
|
|
|
|
|
|
|
|
|
// Create a new context to execute the special page
|
2011-08-02 15:40:03 +00:00
|
|
|
|
$context = new RequestContext;
|
|
|
|
|
|
$context->setTitle( $title );
|
|
|
|
|
|
$context->setRequest( new FauxRequest( $pageArgs ) );
|
|
|
|
|
|
$context->setUser( $this->getUser() );
|
2011-11-23 10:28:21 +00:00
|
|
|
|
$context->setLanguage( $this->mOptions->getUserLangObj() );
|
2011-08-02 15:40:03 +00:00
|
|
|
|
$ret = SpecialPageFactory::capturePath( $title, $context );
|
|
|
|
|
|
if ( $ret ) {
|
|
|
|
|
|
$text = $context->getOutput()->getHTML();
|
2011-08-02 16:31:22 +00:00
|
|
|
|
$this->mOutput->addOutputPageMetadata( $context->getOutput() );
|
2006-01-31 03:44:08 +00:00
|
|
|
|
$found = true;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$isHTML = true;
|
|
|
|
|
|
$this->disableCache();
|
|
|
|
|
|
}
|
2012-05-11 17:52:34 +00:00
|
|
|
|
} elseif ( MWNamespace::isNonincludable( $title->getNamespace() ) ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
$found = false; # access denied
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfDebug( __METHOD__.": template inclusion denied for " . $title->getPrefixedDBkey() );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
list( $text, $title ) = $this->getTemplateDom( $title );
|
|
|
|
|
|
if ( $text !== false ) {
|
|
|
|
|
|
$found = true;
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$isChildObj = true;
|
2006-01-31 03:44:08 +00:00
|
|
|
|
}
|
2005-02-05 07:14:25 +00:00
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
# If the title is valid but undisplayable, make a link to it
|
|
|
|
|
|
if ( !$found && ( $this->ot['html'] || $this->ot['pre'] ) ) {
|
|
|
|
|
|
$text = "[[:$titleText]]";
|
|
|
|
|
|
$found = true;
|
2006-02-01 04:41:53 +00:00
|
|
|
|
}
|
2011-09-29 22:08:00 +00:00
|
|
|
|
} elseif ( $title->isTrans() ) {
|
|
|
|
|
|
# Interwiki transclusion
|
|
|
|
|
|
if ( $this->ot['html'] && !$forceRawInterwiki ) {
|
|
|
|
|
|
$text = $this->interwikiTransclude( $title, 'render' );
|
|
|
|
|
|
$isHTML = true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$text = $this->interwikiTransclude( $title, 'raw' );
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Preprocess it like a template
|
2008-01-05 12:39:12 +00:00
|
|
|
|
$text = $this->preprocessToDom( $text, self::PTD_FOR_INCLUSION );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$isChildObj = true;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
2011-09-29 22:08:00 +00:00
|
|
|
|
$found = true;
|
2004-03-20 15:03:26 +00:00
|
|
|
|
}
|
2009-04-05 15:01:25 +00:00
|
|
|
|
|
|
|
|
|
|
# Do infinite loop check
|
|
|
|
|
|
# This has to be done after redirect resolution to avoid infinite loops via redirects
|
|
|
|
|
|
if ( !$frame->loopCheck( $title ) ) {
|
|
|
|
|
|
$found = true;
|
|
|
|
|
|
$text = '<span class="error">' . wfMsgForContent( 'parser-template-loop-warning', $titleText ) . '</span>';
|
|
|
|
|
|
wfDebug( __METHOD__.": template loop broken at '$titleText'\n" );
|
|
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
wfProfileOut( __METHOD__ . '-loadtpl' );
|
2004-03-20 15:03:26 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2008-01-03 05:37:32 +00:00
|
|
|
|
# If we haven't found text to substitute by now, we're done
|
|
|
|
|
|
# Recover the source wikitext and return it
|
|
|
|
|
|
if ( !$found ) {
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$text = $frame->virtualBracketedImplode( '{{', '|', '}}', $titleWithSpaces, $args );
|
2011-10-27 01:19:34 +00:00
|
|
|
|
if ( $titleProfileIn ) {
|
|
|
|
|
|
wfProfileOut( $titleProfileIn ); // template out
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
return array( 'object' => $text );
|
2008-01-03 05:37:32 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2008-01-03 05:37:32 +00:00
|
|
|
|
# Expand DOM-style return values in a child frame
|
2008-01-21 16:36:08 +00:00
|
|
|
|
if ( $isChildObj ) {
|
2008-01-03 05:37:32 +00:00
|
|
|
|
# Clean up argument array
|
|
|
|
|
|
$newFrame = $frame->newChild( $args, $title );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2008-01-24 04:29:56 +00:00
|
|
|
|
if ( $nowiki ) {
|
|
|
|
|
|
$text = $newFrame->expand( $text, PPFrame::RECOVER_ORIG );
|
|
|
|
|
|
} elseif ( $titleText !== false && $newFrame->isEmpty() ) {
|
2008-01-03 05:37:32 +00:00
|
|
|
|
# Expansion is eligible for the empty-frame cache
|
|
|
|
|
|
if ( isset( $this->mTplExpandCache[$titleText] ) ) {
|
|
|
|
|
|
$text = $this->mTplExpandCache[$titleText];
|
2007-11-20 10:55:08 +00:00
|
|
|
|
} else {
|
2008-01-03 05:37:32 +00:00
|
|
|
|
$text = $newFrame->expand( $text );
|
|
|
|
|
|
$this->mTplExpandCache[$titleText] = $text;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
2008-01-03 05:37:32 +00:00
|
|
|
|
} else {
|
2008-01-11 03:25:41 +00:00
|
|
|
|
# Uncached expansion
|
2008-01-03 05:37:32 +00:00
|
|
|
|
$text = $newFrame->expand( $text );
|
2004-09-25 16:06:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2008-01-24 04:29:56 +00:00
|
|
|
|
if ( $isLocalObj && $nowiki ) {
|
|
|
|
|
|
$text = $frame->expand( $text, PPFrame::RECOVER_ORIG );
|
|
|
|
|
|
$isLocalObj = false;
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2011-10-27 01:19:34 +00:00
|
|
|
|
if ( $titleProfileIn ) {
|
|
|
|
|
|
wfProfileOut( $titleProfileIn ); // template out
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-01-03 05:37:32 +00:00
|
|
|
|
# Replace raw HTML by a placeholder
|
|
|
|
|
|
if ( $isHTML ) {
|
2012-05-12 21:25:35 +00:00
|
|
|
|
$text = $this->insertStripItem( $text );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $nowiki && ( $this->ot['html'] || $this->ot['pre'] ) ) {
|
|
|
|
|
|
# Escape nowiki-style return values
|
2008-01-03 05:37:32 +00:00
|
|
|
|
$text = wfEscapeWikiText( $text );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( is_string( $text )
|
2010-05-15 10:35:54 +00:00
|
|
|
|
&& !$piece['lineStart']
|
2011-01-26 01:16:18 +00:00
|
|
|
|
&& preg_match( '/^(?:{\\||:|;|#|\*)/', $text ) )
|
2010-03-30 21:20:05 +00:00
|
|
|
|
{
|
2011-01-26 01:16:18 +00:00
|
|
|
|
# Bug 529: if the template begins with a table or block-level
|
|
|
|
|
|
# element, it should be treated as beginning a new line.
|
|
|
|
|
|
# This behaviour is somewhat controversial.
|
2008-01-03 05:37:32 +00:00
|
|
|
|
$text = "\n" . $text;
|
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2008-01-21 16:36:08 +00:00
|
|
|
|
if ( is_string( $text ) && !$this->incrementIncludeSize( 'post-expand', strlen( $text ) ) ) {
|
2006-08-10 21:28:49 +00:00
|
|
|
|
# Error, oversize inclusion
|
2010-05-19 00:03:54 +00:00
|
|
|
|
if ( $titleText !== false ) {
|
|
|
|
|
|
# Make a working, properly escaped link if possible (bug 23588)
|
|
|
|
|
|
$text = "[[:$titleText]]";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# This will probably not be a working link, but at least it may
|
|
|
|
|
|
# provide some hint of where the problem is
|
|
|
|
|
|
preg_replace( '/^:/', '', $originalTitle );
|
|
|
|
|
|
$text = "[[:$originalTitle]]";
|
|
|
|
|
|
}
|
|
|
|
|
|
$text .= $this->insertStripItem( '<!-- WARNING: template omitted, post-expand include size too large -->' );
|
2008-05-19 21:33:47 +00:00
|
|
|
|
$this->limitationWarn( 'post-expand-template-inclusion' );
|
2006-08-10 21:28:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2008-01-21 16:36:08 +00:00
|
|
|
|
if ( $isLocalObj ) {
|
|
|
|
|
|
$ret = array( 'object' => $text );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$ret = array( 'text' => $text );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
return $ret;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the semi-parsed DOM representation of a template with a given title,
|
|
|
|
|
|
* and its redirect destination title. Cached.
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $title Title
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return array
|
2007-11-20 10:55:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getTemplateDom( $title ) {
|
2007-11-21 23:07:36 +00:00
|
|
|
|
$cacheTitle = $title;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$titleText = $title->getPrefixedDBkey();
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
if ( isset( $this->mTplRedirCache[$titleText] ) ) {
|
|
|
|
|
|
list( $ns, $dbk ) = $this->mTplRedirCache[$titleText];
|
|
|
|
|
|
$title = Title::makeTitle( $ns, $dbk );
|
|
|
|
|
|
$titleText = $title->getPrefixedDBkey();
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( isset( $this->mTplDomCache[$titleText] ) ) {
|
|
|
|
|
|
return array( $this->mTplDomCache[$titleText], $title );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Cache miss, go to the database
|
2007-11-20 10:55:08 +00:00
|
|
|
|
list( $text, $title ) = $this->fetchTemplateAndTitle( $title );
|
|
|
|
|
|
|
|
|
|
|
|
if ( $text === false ) {
|
|
|
|
|
|
$this->mTplDomCache[$titleText] = false;
|
|
|
|
|
|
return array( false, $title );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-01-05 12:39:12 +00:00
|
|
|
|
$dom = $this->preprocessToDom( $text, self::PTD_FOR_INCLUSION );
|
2007-11-21 23:07:36 +00:00
|
|
|
|
$this->mTplDomCache[ $titleText ] = $dom;
|
|
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !$title->equals( $cacheTitle ) ) {
|
2008-04-14 07:45:50 +00:00
|
|
|
|
$this->mTplRedirCache[$cacheTitle->getPrefixedDBkey()] =
|
2011-01-26 01:16:18 +00:00
|
|
|
|
array( $title->getNamespace(), $cdb = $title->getDBkey() );
|
2007-11-21 23:07:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
return array( $dom, $title );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-01-11 02:19:41 +00:00
|
|
|
|
/**
|
2006-03-11 17:13:49 +00:00
|
|
|
|
* Fetch the unparsed text of a template and register a reference to it.
|
2011-03-23 17:35:40 +00:00
|
|
|
|
* @param Title $title
|
|
|
|
|
|
* @return Array ( string or false, Title )
|
2006-01-11 02:19:41 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function fetchTemplateAndTitle( $title ) {
|
2010-07-20 09:23:37 +00:00
|
|
|
|
$templateCb = $this->mOptions->getTemplateCallback(); # Defaults to Parser::statelessFetchTemplate()
|
2008-06-06 20:28:34 +00:00
|
|
|
|
$stuff = call_user_func( $templateCb, $title, $this );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = $stuff['text'];
|
|
|
|
|
|
$finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
|
|
|
|
|
|
if ( isset( $stuff['deps'] ) ) {
|
|
|
|
|
|
foreach ( $stuff['deps'] as $dep ) {
|
|
|
|
|
|
$this->mOutput->addTemplate( $dep['title'], $dep['page_id'], $dep['rev_id'] );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
return array( $text, $finalTitle );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-03-23 17:35:40 +00:00
|
|
|
|
/**
|
2011-09-29 22:08:00 +00:00
|
|
|
|
* Fetch the unparsed text of a template and register a reference to it.
|
|
|
|
|
|
* @param Title $title
|
|
|
|
|
|
* @return mixed string or false
|
2011-03-23 17:35:40 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function fetchTemplate( $title ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$rv = $this->fetchTemplateAndTitle( $title );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
return $rv[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Static function to get a template
|
|
|
|
|
|
* Can be overridden via ParserOptions::setTemplateCallback().
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2012-07-10 14:58:52 +00:00
|
|
|
|
* @param $title Title
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $parser Parser
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return array
|
2007-11-20 10:55:08 +00:00
|
|
|
|
*/
|
2011-05-01 23:54:41 +00:00
|
|
|
|
static function statelessFetchTemplate( $title, $parser = false ) {
|
2007-05-31 16:01:26 +00:00
|
|
|
|
$text = $skip = false;
|
2007-05-01 22:42:41 +00:00
|
|
|
|
$finalTitle = $title;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$deps = array();
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Loop to fetch the article, with up to 1 redirect
|
2006-01-11 02:19:41 +00:00
|
|
|
|
for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) {
|
2007-05-31 16:01:26 +00:00
|
|
|
|
# Give extensions a chance to select the revision instead
|
2010-03-30 21:53:56 +00:00
|
|
|
|
$id = false; # Assume current
|
2011-03-23 03:13:37 +00:00
|
|
|
|
wfRunHooks( 'BeforeParserFetchTemplateAndtitle',
|
2011-04-04 01:22:08 +00:00
|
|
|
|
array( $parser, $title, &$skip, &$id ) );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $skip ) {
|
2007-05-31 16:01:26 +00:00
|
|
|
|
$text = false;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$deps[] = array(
|
2011-03-23 03:13:37 +00:00
|
|
|
|
'title' => $title,
|
|
|
|
|
|
'page_id' => $title->getArticleID(),
|
|
|
|
|
|
'rev_id' => null
|
|
|
|
|
|
);
|
2007-05-31 16:01:26 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2011-03-23 18:23:55 +00:00
|
|
|
|
# Get the revision
|
|
|
|
|
|
$rev = $id
|
|
|
|
|
|
? Revision::newFromId( $id )
|
|
|
|
|
|
: Revision::newFromTitle( $title );
|
2007-05-31 16:01:26 +00:00
|
|
|
|
$rev_id = $rev ? $rev->getId() : 0;
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# If there is no current revision, there is no page
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $id === false && !$rev ) {
|
2008-05-13 16:06:31 +00:00
|
|
|
|
$linkCache = LinkCache::singleton();
|
|
|
|
|
|
$linkCache->addBadLinkObj( $title );
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
|
$deps[] = array(
|
2011-03-23 03:13:37 +00:00
|
|
|
|
'title' => $title,
|
|
|
|
|
|
'page_id' => $title->getArticleID(),
|
|
|
|
|
|
'rev_id' => $rev_id );
|
2011-03-23 18:23:55 +00:00
|
|
|
|
if ( $rev && !$title->equals( $rev->getTitle() ) ) {
|
|
|
|
|
|
# We fetched a rev from a different title; register it too...
|
|
|
|
|
|
$deps[] = array(
|
|
|
|
|
|
'title' => $rev->getTitle(),
|
|
|
|
|
|
'page_id' => $rev->getPage(),
|
|
|
|
|
|
'rev_id' => $rev_id );
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $rev ) {
|
2012-06-08 07:03:18 +00:00
|
|
|
|
$content = $rev->getContent();
|
|
|
|
|
|
$text = $content->getWikitextForTransclusion();
|
|
|
|
|
|
|
|
|
|
|
|
if ( $text === false || $text === null ) {
|
|
|
|
|
|
$text = false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $title->getNamespace() == NS_MEDIAWIKI ) {
|
2008-09-28 10:51:58 +00:00
|
|
|
|
global $wgContLang;
|
2011-01-14 10:51:05 +00:00
|
|
|
|
$message = wfMessage( $wgContLang->lcfirst( $title->getText() ) )->inContentLanguage();
|
|
|
|
|
|
if ( !$message->exists() ) {
|
2007-01-07 12:30:46 +00:00
|
|
|
|
$text = false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2012-06-12 09:12:49 +00:00
|
|
|
|
$content = $message->content();
|
2011-01-14 10:51:05 +00:00
|
|
|
|
$text = $message->plain();
|
2007-01-07 12:30:46 +00:00
|
|
|
|
} else {
|
2006-01-11 02:19:41 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2012-06-11 10:35:46 +00:00
|
|
|
|
if ( !$content ) {
|
2006-01-11 02:19:41 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Redirect?
|
2007-05-01 22:42:41 +00:00
|
|
|
|
$finalTitle = $title;
|
2012-06-11 10:35:46 +00:00
|
|
|
|
$title = $content->getRedirectTarget();
|
2006-01-11 02:19:41 +00:00
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
return array(
|
|
|
|
|
|
'text' => $text,
|
|
|
|
|
|
'finalTitle' => $finalTitle,
|
|
|
|
|
|
'deps' => $deps );
|
2006-01-11 02:19:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-03-23 03:13:37 +00:00
|
|
|
|
/**
|
2011-03-23 17:35:40 +00:00
|
|
|
|
* Fetch a file and its title and register a reference to it.
|
2011-09-06 18:11:53 +00:00
|
|
|
|
* If 'broken' is a key in $options then the file will appear as a broken thumbnail.
|
2011-03-23 17:35:40 +00:00
|
|
|
|
* @param Title $title
|
2011-09-06 18:11:53 +00:00
|
|
|
|
* @param Array $options Array of options to RepoGroup::findFile
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @return File|bool
|
2011-03-23 03:13:37 +00:00
|
|
|
|
*/
|
2011-09-06 18:11:53 +00:00
|
|
|
|
function fetchFile( $title, $options = array() ) {
|
|
|
|
|
|
$res = $this->fetchFileAndTitle( $title, $options );
|
2011-03-23 17:35:40 +00:00
|
|
|
|
return $res[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Fetch a file and its title and register a reference to it.
|
2011-09-06 18:11:53 +00:00
|
|
|
|
* If 'broken' is a key in $options then the file will appear as a broken thumbnail.
|
2011-03-23 17:35:40 +00:00
|
|
|
|
* @param Title $title
|
2011-09-06 18:11:53 +00:00
|
|
|
|
* @param Array $options Array of options to RepoGroup::findFile
|
2011-03-23 18:23:55 +00:00
|
|
|
|
* @return Array ( File or false, Title of file )
|
2011-03-23 17:35:40 +00:00
|
|
|
|
*/
|
2011-09-06 18:11:53 +00:00
|
|
|
|
function fetchFileAndTitle( $title, $options = array() ) {
|
|
|
|
|
|
if ( isset( $options['broken'] ) ) {
|
2011-03-23 17:35:40 +00:00
|
|
|
|
$file = false; // broken thumbnail forced by hook
|
2011-09-06 18:11:53 +00:00
|
|
|
|
} elseif ( isset( $options['sha1'] ) ) { // get by (sha1,timestamp)
|
|
|
|
|
|
$file = RepoGroup::singleton()->findFileFromKey( $options['sha1'], $options );
|
2011-03-23 03:13:37 +00:00
|
|
|
|
} else { // get by (name,timestamp)
|
2011-09-06 18:11:53 +00:00
|
|
|
|
$file = wfFindFile( $title, $options );
|
2011-03-23 03:13:37 +00:00
|
|
|
|
}
|
2011-04-04 01:22:08 +00:00
|
|
|
|
$time = $file ? $file->getTimestamp() : false;
|
|
|
|
|
|
$sha1 = $file ? $file->getSha1() : false;
|
2011-03-23 18:23:55 +00:00
|
|
|
|
# Register the file as a dependency...
|
2011-03-23 17:35:40 +00:00
|
|
|
|
$this->mOutput->addImage( $title->getDBkey(), $time, $sha1 );
|
2011-03-23 18:23:55 +00:00
|
|
|
|
if ( $file && !$title->equals( $file->getTitle() ) ) {
|
2011-05-25 15:39:47 +00:00
|
|
|
|
# Update fetched file title
|
2011-03-23 18:23:55 +00:00
|
|
|
|
$title = $file->getTitle();
|
2011-07-09 10:31:09 +00:00
|
|
|
|
if ( is_null( $file->getRedirectedTitle() ) ) {
|
|
|
|
|
|
# This file was not a redirect, but the title does not match.
|
|
|
|
|
|
# Register under the new name because otherwise the link will
|
|
|
|
|
|
# get lost.
|
|
|
|
|
|
$this->mOutput->addImage( $title->getDBkey(), $time, $sha1 );
|
|
|
|
|
|
}
|
2011-03-23 18:23:55 +00:00
|
|
|
|
}
|
2011-04-13 11:24:38 +00:00
|
|
|
|
return array( $file, $title );
|
2011-03-23 03:13:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-29 22:08:00 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Transclude an interwiki link.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $title Title
|
|
|
|
|
|
* @param $action
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
function interwikiTransclude( $title, $action ) {
|
|
|
|
|
|
global $wgEnableScaryTranscluding;
|
|
|
|
|
|
|
|
|
|
|
|
if ( !$wgEnableScaryTranscluding ) {
|
|
|
|
|
|
return wfMsgForContent('scarytranscludedisabled');
|
|
|
|
|
|
}
|
2011-07-30 15:56:54 +00:00
|
|
|
|
|
2011-09-29 22:08:00 +00:00
|
|
|
|
$url = $title->getFullUrl( "action=$action" );
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2011-09-29 22:08:00 +00:00
|
|
|
|
if ( strlen( $url ) > 255 ) {
|
|
|
|
|
|
return wfMsgForContent( 'scarytranscludetoolong' );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $this->fetchScaryTemplateMaybeFromCache( $url );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @param $url string
|
|
|
|
|
|
* @return Mixed|String
|
|
|
|
|
|
*/
|
|
|
|
|
|
function fetchScaryTemplateMaybeFromCache( $url ) {
|
|
|
|
|
|
global $wgTranscludeCacheExpiry;
|
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
|
$tsCond = $dbr->timestamp( time() - $wgTranscludeCacheExpiry );
|
|
|
|
|
|
$obj = $dbr->selectRow( 'transcache', array('tc_time', 'tc_contents' ),
|
|
|
|
|
|
array( 'tc_url' => $url, "tc_time >= " . $dbr->addQuotes( $tsCond ) ) );
|
|
|
|
|
|
if ( $obj ) {
|
|
|
|
|
|
return $obj->tc_contents;
|
2011-07-30 15:56:54 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2011-09-29 22:08:00 +00:00
|
|
|
|
$text = Http::get( $url );
|
|
|
|
|
|
if ( !$text ) {
|
|
|
|
|
|
return wfMsgForContent( 'scarytranscludefailed', $url );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
|
$dbw->replace( 'transcache', array('tc_url'), array(
|
|
|
|
|
|
'tc_url' => $url,
|
|
|
|
|
|
'tc_time' => $dbw->timestamp( time() ),
|
|
|
|
|
|
'tc_contents' => $text)
|
|
|
|
|
|
);
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Triple brace replacement -- used for template arguments
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2012-07-10 14:58:52 +00:00
|
|
|
|
* @param $piece array
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @param $frame PPFrame
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return array
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function argSubstitution( $piece, $frame ) {
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-05-23 03:39:24 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$error = false;
|
|
|
|
|
|
$parts = $piece['parts'];
|
2008-01-13 09:23:58 +00:00
|
|
|
|
$nameWithSpaces = $frame->expand( $piece['title'] );
|
|
|
|
|
|
$argName = trim( $nameWithSpaces );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$object = false;
|
2008-01-13 12:47:38 +00:00
|
|
|
|
$text = $frame->getArgument( $argName );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
if ( $text === false && $parts->getLength() > 0
|
|
|
|
|
|
&& (
|
2010-12-11 03:52:35 +00:00
|
|
|
|
$this->ot['html']
|
|
|
|
|
|
|| $this->ot['pre']
|
|
|
|
|
|
|| ( $this->ot['wiki'] && $frame->isTemplate() )
|
2008-01-30 02:52:14 +00:00
|
|
|
|
)
|
|
|
|
|
|
) {
|
2008-01-13 06:40:14 +00:00
|
|
|
|
# No match in frame, use the supplied default
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$object = $parts->item( 0 )->getChildren();
|
2004-05-23 03:39:24 +00:00
|
|
|
|
}
|
2006-08-10 21:28:49 +00:00
|
|
|
|
if ( !$this->incrementIncludeSize( 'arg', strlen( $text ) ) ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$error = '<!-- WARNING: argument omitted, expansion size too large -->';
|
2008-05-19 21:33:47 +00:00
|
|
|
|
$this->limitationWarn( 'post-expand-template-argument' );
|
2006-08-10 21:28:49 +00:00
|
|
|
|
}
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2008-01-21 16:36:08 +00:00
|
|
|
|
if ( $text === false && $object === false ) {
|
2008-01-13 06:40:14 +00:00
|
|
|
|
# No match anywhere
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$object = $frame->virtualBracketedImplode( '{{{', '|', '}}}', $nameWithSpaces, $parts );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( $error !== false ) {
|
|
|
|
|
|
$text .= $error;
|
|
|
|
|
|
}
|
2008-01-21 16:36:08 +00:00
|
|
|
|
if ( $object !== false ) {
|
|
|
|
|
|
$ret = array( 'object' => $object );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$ret = array( 'text' => $text );
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
return $ret;
|
2004-05-23 03:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return the text to be used for a given extension tag.
|
|
|
|
|
|
* This is the ghost of strip().
|
|
|
|
|
|
*
|
2012-02-09 18:01:10 +00:00
|
|
|
|
* @param $params array Associative array of parameters:
|
2008-01-21 16:36:08 +00:00
|
|
|
|
* name PPNode for the tag name
|
|
|
|
|
|
* attr PPNode for unparsed text where tag attributes are thought to be
|
2008-01-09 07:13:54 +00:00
|
|
|
|
* attributes Optional associative array of parsed attributes
|
2007-11-20 10:55:08 +00:00
|
|
|
|
* inner Contents of extension element
|
|
|
|
|
|
* noClose Original text did not have a close tag
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $frame PPFrame
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2007-11-20 10:55:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function extensionSubstitution( $params, $frame ) {
|
|
|
|
|
|
$name = $frame->expand( $params['name'] );
|
2008-01-09 07:13:54 +00:00
|
|
|
|
$attrText = !isset( $params['attr'] ) ? null : $frame->expand( $params['attr'] );
|
|
|
|
|
|
$content = !isset( $params['inner'] ) ? null : $frame->expand( $params['inner'] );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$marker = "{$this->mUniqPrefix}-$name-" . sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2009-07-11 13:03:35 +00:00
|
|
|
|
$isFunctionTag = isset( $this->mFunctionTagHooks[strtolower($name)] ) &&
|
|
|
|
|
|
( $this->ot['html'] || $this->ot['pre'] );
|
2010-02-03 07:10:58 +00:00
|
|
|
|
if ( $isFunctionTag ) {
|
|
|
|
|
|
$markerType = 'none';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$markerType = 'general';
|
|
|
|
|
|
}
|
2009-07-11 13:03:35 +00:00
|
|
|
|
if ( $this->ot['html'] || $isFunctionTag ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$name = strtolower( $name );
|
2008-01-09 07:13:54 +00:00
|
|
|
|
$attributes = Sanitizer::decodeTagAttributes( $attrText );
|
|
|
|
|
|
if ( isset( $params['attributes'] ) ) {
|
|
|
|
|
|
$attributes = $attributes + $params['attributes'];
|
|
|
|
|
|
}
|
2010-02-03 07:10:58 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $this->mTagHooks[$name] ) ) {
|
2010-02-03 07:10:58 +00:00
|
|
|
|
# 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 ) );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( isset( $this->mFunctionTagHooks[$name] ) ) {
|
2010-02-03 07:10:58 +00:00
|
|
|
|
list( $callback, $flags ) = $this->mFunctionTagHooks[$name];
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !is_callable( $callback ) ) {
|
2010-02-03 07:10:58 +00:00
|
|
|
|
throw new MWException( "Tag hook for $name is not callable\n" );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2010-02-03 07:10:58 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$output = call_user_func_array( $callback, array( &$this, $frame, $content, $attributes ) );
|
2010-02-03 07:10:58 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$output = '<span class="error">Invalid tag extension name: ' .
|
|
|
|
|
|
htmlspecialchars( $name ) . '</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( is_array( $output ) ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Extract flags to local scope (to override $markerType)
|
2010-02-03 07:10:58 +00:00
|
|
|
|
$flags = $output;
|
|
|
|
|
|
$output = $flags[0];
|
|
|
|
|
|
unset( $flags[0] );
|
|
|
|
|
|
extract( $flags );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2008-01-19 09:03:45 +00:00
|
|
|
|
if ( is_null( $attrText ) ) {
|
|
|
|
|
|
$attrText = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( isset( $params['attributes'] ) ) {
|
|
|
|
|
|
foreach ( $params['attributes'] as $attrName => $attrValue ) {
|
|
|
|
|
|
$attrText .= ' ' . htmlspecialchars( $attrName ) . '="' .
|
|
|
|
|
|
htmlspecialchars( $attrValue ) . '"';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2007-12-17 15:07:25 +00:00
|
|
|
|
if ( $content === null ) {
|
|
|
|
|
|
$output = "<$name$attrText/>";
|
2007-11-20 10:55:08 +00:00
|
|
|
|
} else {
|
2007-12-17 15:07:25 +00:00
|
|
|
|
$close = is_null( $params['close'] ) ? '' : $frame->expand( $params['close'] );
|
|
|
|
|
|
$output = "<$name$attrText>$content$close";
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $markerType === 'none' ) {
|
2009-07-11 13:03:35 +00:00
|
|
|
|
return $output;
|
2010-02-03 07:10:58 +00:00
|
|
|
|
} elseif ( $markerType === 'nowiki' ) {
|
2011-02-23 06:58:15 +00:00
|
|
|
|
$this->mStripState->addNoWiki( $marker, $output );
|
2010-02-03 07:10:58 +00:00
|
|
|
|
} elseif ( $markerType === 'general' ) {
|
2011-02-23 06:58:15 +00:00
|
|
|
|
$this->mStripState->addGeneral( $marker, $output );
|
2010-02-03 07:10:58 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
throw new MWException( __METHOD__.': invalid marker type' );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $marker;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2006-08-10 21:28:49 +00:00
|
|
|
|
* Increment an include size counter
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $type String: the type of expansion
|
|
|
|
|
|
* @param $size Integer: the size of the text
|
|
|
|
|
|
* @return Boolean: false if this inclusion would take it over the maximum, true otherwise
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2006-08-10 21:28:49 +00:00
|
|
|
|
function incrementIncludeSize( $type, $size ) {
|
2010-12-11 03:53:22 +00:00
|
|
|
|
if ( $this->mIncludeSizes[$type] + $size > $this->mOptions->getMaxIncludeSize() ) {
|
2004-04-11 16:46:06 +00:00
|
|
|
|
return false;
|
2006-08-10 21:28:49 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$this->mIncludeSizes[$type] += $size;
|
|
|
|
|
|
return true;
|
2004-04-11 16:46:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-04-18 14:34:38 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Increment the expensive function count
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return Boolean: false if the limit has been exceeded
|
2008-04-18 14:34:38 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function incrementExpensiveFunctionCount() {
|
|
|
|
|
|
$this->mExpensiveFunctionCount++;
|
2012-05-04 18:56:28 +00:00
|
|
|
|
return $this->mExpensiveFunctionCount <= $this->mOptions->getExpensiveParserFunctionLimit();
|
2008-04-18 14:34:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-06-13 11:37:09 +00:00
|
|
|
|
/**
|
2008-02-20 08:53:12 +00:00
|
|
|
|
* Strip double-underscore items like __NOGALLERY__ and __NOTOC__
|
|
|
|
|
|
* Fills $this->mDoubleUnderscores, returns the modified text
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2006-06-13 11:37:09 +00:00
|
|
|
|
*/
|
2008-02-20 08:53:12 +00:00
|
|
|
|
function doDoubleUnderscore( $text ) {
|
2009-03-06 02:25:28 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# The position of __TOC__ needs to be recorded
|
2006-07-14 15:39:23 +00:00
|
|
|
|
$mw = MagicWord::get( 'toc' );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $mw->match( $text ) ) {
|
2006-05-23 07:19:01 +00:00
|
|
|
|
$this->mShowToc = true;
|
|
|
|
|
|
$this->mForceTocPosition = true;
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Set a placeholder. At the end we'll fill it in with the TOC.
|
2006-05-23 07:19:01 +00:00
|
|
|
|
$text = $mw->replace( '<!--MWTOC-->', $text, 1 );
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Only keep the first one.
|
2006-05-23 07:19:01 +00:00
|
|
|
|
$text = $mw->replace( '', $text );
|
|
|
|
|
|
}
|
2008-02-20 08:53:12 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Now match and remove the rest of them
|
2008-02-20 08:53:12 +00:00
|
|
|
|
$mwa = MagicWord::getDoubleUnderscoreArray();
|
|
|
|
|
|
$this->mDoubleUnderscores = $mwa->matchAndRemove( $text );
|
|
|
|
|
|
|
|
|
|
|
|
if ( isset( $this->mDoubleUnderscores['nogallery'] ) ) {
|
|
|
|
|
|
$this->mOutput->mNoGallery = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( isset( $this->mDoubleUnderscores['notoc'] ) && !$this->mForceTocPosition ) {
|
|
|
|
|
|
$this->mShowToc = false;
|
|
|
|
|
|
}
|
2008-02-29 00:55:45 +00:00
|
|
|
|
if ( isset( $this->mDoubleUnderscores['hiddencat'] ) && $this->mTitle->getNamespace() == NS_CATEGORY ) {
|
2009-09-28 17:55:00 +00:00
|
|
|
|
$this->addTrackingCategory( 'hidden-category-category' );
|
2008-02-20 08:53:12 +00:00
|
|
|
|
}
|
2008-07-24 18:10:35 +00:00
|
|
|
|
# (bug 8068) Allow control over whether robots index a page.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: Bug 14899: __INDEX__ always overrides __NOINDEX__ here! This
|
2008-07-24 18:10:35 +00:00
|
|
|
|
# is not desirable, the last one on the page should win.
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $this->mDoubleUnderscores['noindex'] ) && $this->mTitle->canUseNoindex() ) {
|
2008-07-23 19:49:46 +00:00
|
|
|
|
$this->mOutput->setIndexPolicy( 'noindex' );
|
2009-09-28 17:55:00 +00:00
|
|
|
|
$this->addTrackingCategory( 'noindex-category' );
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $this->mDoubleUnderscores['index'] ) && $this->mTitle->canUseNoindex() ) {
|
2008-07-23 19:49:46 +00:00
|
|
|
|
$this->mOutput->setIndexPolicy( 'index' );
|
2009-09-28 17:55:00 +00:00
|
|
|
|
$this->addTrackingCategory( 'index-category' );
|
2008-07-23 19:49:46 +00:00
|
|
|
|
}
|
2010-12-11 03:52:35 +00:00
|
|
|
|
|
2010-07-10 11:30:11 +00:00
|
|
|
|
# Cache all double underscores in the database
|
|
|
|
|
|
foreach ( $this->mDoubleUnderscores as $key => $val ) {
|
|
|
|
|
|
$this->mOutput->setProperty( $key, '' );
|
|
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2009-03-06 02:25:28 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2006-05-23 07:19:01 +00:00
|
|
|
|
return $text;
|
2010-01-07 04:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-09-28 17:55:00 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Add a tracking category, getting the title from a system message,
|
|
|
|
|
|
* or print a debug message if the title is invalid.
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $msg String: message key
|
|
|
|
|
|
* @return Boolean: whether the addition was successful
|
2009-09-28 17:55:00 +00:00
|
|
|
|
*/
|
2012-01-11 15:42:29 +00:00
|
|
|
|
public function addTrackingCategory( $msg ) {
|
2011-08-21 18:46:01 +00:00
|
|
|
|
if ( $this->mTitle->getNamespace() === NS_SPECIAL ) {
|
|
|
|
|
|
wfDebug( __METHOD__.": Not adding tracking category $msg to special page!\n" );
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2011-12-30 06:44:38 +00:00
|
|
|
|
// Important to parse with correct title (bug 31469)
|
|
|
|
|
|
$cat = wfMessage( $msg )
|
|
|
|
|
|
->title( $this->getTitle() )
|
|
|
|
|
|
->inContentLanguage()
|
|
|
|
|
|
->text();
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2009-10-11 12:52:08 +00:00
|
|
|
|
# Allow tracking categories to be disabled by setting them to "-"
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $cat === '-' ) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2009-10-11 12:52:08 +00:00
|
|
|
|
$containerCategory = Title::makeTitleSafe( NS_CATEGORY, $cat );
|
2009-09-28 17:55:00 +00:00
|
|
|
|
if ( $containerCategory ) {
|
|
|
|
|
|
$this->mOutput->addCategory( $containerCategory->getDBkey(), $this->getDefaultSort() );
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
wfDebug( __METHOD__.": [[MediaWiki:$msg]] is not a valid title!\n" );
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2006-05-23 07:19:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* This function accomplishes several tasks:
|
|
|
|
|
|
* 1) Auto-number headings if that option is enabled
|
2007-10-12 07:11:09 +00:00
|
|
|
|
* 2) Add an [edit] link to sections for users who have enabled the option and can edit the page
|
2004-09-21 05:49:12 +00:00
|
|
|
|
* 3) Add a Table of contents on the top for users who have enabled the option
|
|
|
|
|
|
* 4) Auto-anchor headings
|
2005-07-03 07:15:53 +00:00
|
|
|
|
*
|
2004-09-21 05:49:12 +00:00
|
|
|
|
* It loops through all headlines, collects the necessary data, then splits up the
|
|
|
|
|
|
* string and re-inserts the newly formatted headlines.
|
2005-07-03 07:15:53 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @param $origText String: original, untouched wikitext
|
|
|
|
|
|
* @param $isMain Boolean
|
2012-02-09 21:35:05 +00:00
|
|
|
|
* @return mixed|string
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2009-06-20 18:25:30 +00:00
|
|
|
|
function formatHeadings( $text, $origText, $isMain=true ) {
|
2011-06-29 13:23:51 +00:00
|
|
|
|
global $wgMaxTocLevel, $wgHtml5, $wgExperimentalHtmlIds;
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2004-02-26 13:37:26 +00:00
|
|
|
|
# Inhibit editsection links if requested in the page
|
2010-08-05 14:37:50 +00:00
|
|
|
|
if ( isset( $this->mDoubleUnderscores['noeditsection'] ) ) {
|
2011-10-25 22:18:33 +00:00
|
|
|
|
$maybeShowEditLink = $showEditLink = false;
|
2010-08-05 14:37:50 +00:00
|
|
|
|
} else {
|
2011-10-25 22:18:33 +00:00
|
|
|
|
$maybeShowEditLink = true; /* Actual presence will depend on ParserOptions option */
|
2010-08-05 14:37:50 +00:00
|
|
|
|
$showEditLink = $this->mOptions->getEditSection();
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2011-01-03 20:17:20 +00:00
|
|
|
|
if ( $showEditLink ) {
|
2011-01-04 11:31:06 +00:00
|
|
|
|
$this->mOutput->setEditSectionTokens( true );
|
2011-01-03 20:17:20 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2004-04-03 04:38:09 +00:00
|
|
|
|
# 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
|
2006-10-17 08:49:27 +00:00
|
|
|
|
$matches = array();
|
2007-01-08 02:11:45 +00:00
|
|
|
|
$numMatches = preg_match_all( '/<H(?P<level>[1-6])(?P<attrib>.*?'.'>)(?P<header>.*?)<\/H[1-6] *>/i', $text, $matches );
|
2004-04-03 04:38:09 +00:00
|
|
|
|
|
|
|
|
|
|
# if there are fewer than 4 headlines in the article, do not show TOC
|
2006-05-23 10:01:45 +00:00
|
|
|
|
# unless it's been explicitly enabled.
|
|
|
|
|
|
$enoughToc = $this->mShowToc &&
|
2010-03-30 21:20:05 +00:00
|
|
|
|
( ( $numMatches >= 4 ) || $this->mForceTocPosition );
|
2004-04-03 04:38:09 +00:00
|
|
|
|
|
2006-05-01 20:35:08 +00:00
|
|
|
|
# Allow user to stipulate that a page should have a "new section"
|
|
|
|
|
|
# link added via __NEWSECTIONLINK__
|
2008-02-20 08:53:12 +00:00
|
|
|
|
if ( isset( $this->mDoubleUnderscores['newsectionlink'] ) ) {
|
2006-05-01 20:35:08 +00:00
|
|
|
|
$this->mOutput->setNewSection( true );
|
2008-02-20 08:53:12 +00:00
|
|
|
|
}
|
2006-05-01 20:35:08 +00:00
|
|
|
|
|
2009-02-19 22:14:59 +00:00
|
|
|
|
# Allow user to remove the "new section"
|
|
|
|
|
|
# link via __NONEWSECTIONLINK__
|
|
|
|
|
|
if ( isset( $this->mDoubleUnderscores['nonewsectionlink'] ) ) {
|
|
|
|
|
|
$this->mOutput->hideNewSection( true );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-05-23 10:01:45 +00:00
|
|
|
|
# if the string __FORCETOC__ (not case-sensitive) occurs in the HTML,
|
|
|
|
|
|
# override above conditions and always show TOC above first header
|
2008-02-20 08:53:12 +00:00
|
|
|
|
if ( isset( $this->mDoubleUnderscores['forcetoc'] ) ) {
|
2006-05-23 07:19:01 +00:00
|
|
|
|
$this->mShowToc = true;
|
2006-05-23 10:01:45 +00:00
|
|
|
|
$enoughToc = true;
|
2004-04-03 04:38:09 +00:00
|
|
|
|
}
|
2004-07-12 19:49:20 +00:00
|
|
|
|
|
2004-02-26 13:37:26 +00:00
|
|
|
|
# headline counter
|
2004-03-21 11:28:44 +00:00
|
|
|
|
$headlineCount = 0;
|
2007-04-30 19:51:56 +00:00
|
|
|
|
$numVisible = 0;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
|
|
|
|
|
# Ugh .. the TOC should have neat indentation levels which can be
|
|
|
|
|
|
# passed to the skin functions. These are determined here
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$toc = '';
|
|
|
|
|
|
$full = '';
|
2004-03-08 02:50:04 +00:00
|
|
|
|
$head = array();
|
2004-03-21 11:28:44 +00:00
|
|
|
|
$sublevelCount = array();
|
2005-01-15 23:21:52 +00:00
|
|
|
|
$levelCount = array();
|
2004-03-29 14:48:07 +00:00
|
|
|
|
$level = 0;
|
|
|
|
|
|
$prevlevel = 0;
|
2005-01-15 23:21:52 +00:00
|
|
|
|
$toclevel = 0;
|
|
|
|
|
|
$prevtoclevel = 0;
|
2008-03-27 00:00:25 +00:00
|
|
|
|
$markerRegex = "{$this->mUniqPrefix}-h-(\d+)-" . self::MARKER_SUFFIX;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$baseTitleText = $this->mTitle->getPrefixedDBkey();
|
2009-06-20 18:25:30 +00:00
|
|
|
|
$oldType = $this->mOutputType;
|
|
|
|
|
|
$this->setOutputType( self::OT_WIKI );
|
|
|
|
|
|
$frame = $this->getPreprocessor()->newFrame();
|
|
|
|
|
|
$root = $this->preprocessToDom( $origText );
|
|
|
|
|
|
$node = $root->getFirstChild();
|
|
|
|
|
|
$byteOffset = 0;
|
2007-12-27 20:14:07 +00:00
|
|
|
|
$tocraw = array();
|
2010-10-18 23:50:33 +00:00
|
|
|
|
$refers = array();
|
2005-01-15 23:21:52 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
foreach ( $matches[3] as $headline ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$isTemplate = false;
|
|
|
|
|
|
$titleText = false;
|
|
|
|
|
|
$sectionIndex = false;
|
2005-01-15 23:21:52 +00:00
|
|
|
|
$numbering = '';
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$markerMatches = array();
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( preg_match("/^$markerRegex/", $headline, $markerMatches ) ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$serial = $markerMatches[1];
|
|
|
|
|
|
list( $titleText, $sectionIndex ) = $this->mHeadings[$serial];
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$isTemplate = ( $titleText != $baseTitleText );
|
|
|
|
|
|
$headline = preg_replace( "/^$markerRegex/", "", $headline );
|
2004-09-21 04:33:51 +00:00
|
|
|
|
}
|
2004-09-21 08:31:25 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $toclevel ) {
|
2004-03-21 11:28:44 +00:00
|
|
|
|
$prevlevel = $level;
|
|
|
|
|
|
}
|
|
|
|
|
|
$level = $matches[1][$headlineCount];
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2009-06-25 11:05:22 +00:00
|
|
|
|
if ( $level > $prevlevel ) {
|
|
|
|
|
|
# Increase TOC level
|
|
|
|
|
|
$toclevel++;
|
|
|
|
|
|
$sublevelCount[$toclevel] = 0;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $toclevel<$wgMaxTocLevel ) {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
$prevtoclevel = $toclevel;
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$toc .= Linker::tocIndent();
|
2009-06-25 11:05:22 +00:00
|
|
|
|
$numVisible++;
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $level < $prevlevel && $toclevel > 1 ) {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
# Decrease TOC level, find level to jump to
|
|
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
for ( $i = $toclevel; $i > 0; $i-- ) {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
if ( $levelCount[$i] == $level ) {
|
|
|
|
|
|
# Found last matching level
|
|
|
|
|
|
$toclevel = $i;
|
|
|
|
|
|
break;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $levelCount[$i] < $level ) {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
# Found first matching level below current level
|
|
|
|
|
|
$toclevel = $i + 1;
|
|
|
|
|
|
break;
|
2006-04-25 19:43:46 +00:00
|
|
|
|
}
|
2005-01-15 23:21:52 +00:00
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $i == 0 ) {
|
|
|
|
|
|
$toclevel = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $toclevel<$wgMaxTocLevel ) {
|
|
|
|
|
|
if ( $prevtoclevel < $wgMaxTocLevel ) {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
# Unindent only if the previous toc level was shown :p
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$toc .= Linker::tocUnindent( $prevtoclevel - $toclevel );
|
2009-06-25 11:05:22 +00:00
|
|
|
|
$prevtoclevel = $toclevel;
|
|
|
|
|
|
} else {
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$toc .= Linker::tocLineEnd();
|
2006-04-25 19:43:46 +00:00
|
|
|
|
}
|
2005-01-15 23:21:52 +00:00
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} else {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
# No change in level, end TOC line
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $toclevel<$wgMaxTocLevel ) {
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$toc .= Linker::tocLineEnd();
|
2009-06-25 11:05:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2009-06-25 11:05:22 +00:00
|
|
|
|
$levelCount[$toclevel] = $level;
|
2005-01-15 23:21:52 +00:00
|
|
|
|
|
2009-06-25 11:05:22 +00:00
|
|
|
|
# count number of headlines for each level
|
|
|
|
|
|
@$sublevelCount[$toclevel]++;
|
|
|
|
|
|
$dot = 0;
|
|
|
|
|
|
for( $i = 1; $i <= $toclevel; $i++ ) {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !empty( $sublevelCount[$i] ) ) {
|
|
|
|
|
|
if ( $dot ) {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
$numbering .= '.';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2012-03-05 05:53:12 +00:00
|
|
|
|
$numbering .= $this->getTargetLanguage()->formatNum( $sublevelCount[$i] );
|
2009-06-25 11:05:22 +00:00
|
|
|
|
$dot = 1;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-01-10 17:16:21 +00:00
|
|
|
|
# The safe header is a version of the header text safe to use for links
|
|
|
|
|
|
|
|
|
|
|
|
# Remove link placeholders by the link text.
|
|
|
|
|
|
# <!--LINK number-->
|
|
|
|
|
|
# turns into
|
|
|
|
|
|
# link text with suffix
|
2012-03-20 04:39:09 +00:00
|
|
|
|
# Do this before unstrip since link text can contain strip markers
|
|
|
|
|
|
$safeHeadline = $this->replaceLinkHoldersText( $headline );
|
|
|
|
|
|
|
|
|
|
|
|
# Avoid insertion of weird stuff like <math> by expanding the relevant sections
|
|
|
|
|
|
$safeHeadline = $this->mStripState->unstripBoth( $safeHeadline );
|
2009-01-10 17:16:21 +00:00
|
|
|
|
|
2012-01-21 16:27:27 +00:00
|
|
|
|
# Strip out HTML (first regex removes any tag not allowed)
|
|
|
|
|
|
# Allowed tags are <sup> and <sub> (bug 8393), <i> (bug 26375) and <b> (r105284)
|
|
|
|
|
|
# We strip any parameter from accepted tags (second regex)
|
2009-01-10 17:16:21 +00:00
|
|
|
|
$tocline = preg_replace(
|
2012-01-21 16:27:27 +00:00
|
|
|
|
array( '#<(?!/?(sup|sub|i|b)(?: [^>]*)?>).*?'.'>#', '#<(/?(sup|sub|i|b))(?: .*?)?'.'>#' ),
|
2010-03-30 21:20:05 +00:00
|
|
|
|
array( '', '<$1>' ),
|
2009-01-10 17:16:21 +00:00
|
|
|
|
$safeHeadline
|
|
|
|
|
|
);
|
|
|
|
|
|
$tocline = trim( $tocline );
|
|
|
|
|
|
|
|
|
|
|
|
# For the anchor, strip out HTML-y stuff period
|
|
|
|
|
|
$safeHeadline = preg_replace( '/<.*?'.'>/', '', $safeHeadline );
|
2010-06-21 01:17:36 +00:00
|
|
|
|
$safeHeadline = Sanitizer::normalizeSectionNameWhitespace( $safeHeadline );
|
2009-01-10 17:16:21 +00:00
|
|
|
|
|
|
|
|
|
|
# Save headline for section edit hint before it's escaped
|
|
|
|
|
|
$headlineHint = $safeHeadline;
|
|
|
|
|
|
|
2010-02-01 01:43:07 +00:00
|
|
|
|
if ( $wgHtml5 && $wgExperimentalHtmlIds ) {
|
2009-01-10 17:16:21 +00:00
|
|
|
|
# For reverse compatibility, provide an id that's
|
|
|
|
|
|
# HTML4-compatible, like we used to.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2009-01-10 17:16:21 +00:00
|
|
|
|
# It may be worth noting, academically, that it's possible for
|
|
|
|
|
|
# the legacy anchor to conflict with a non-legacy headline
|
|
|
|
|
|
# anchor on the page. In this case likely the "correct" thing
|
|
|
|
|
|
# would be to either drop the legacy anchors or make sure
|
|
|
|
|
|
# they're numbered first. However, this would require people
|
|
|
|
|
|
# to type in section names like "abc_.D7.93.D7.90.D7.A4"
|
|
|
|
|
|
# manually, so let's not bother worrying about it.
|
|
|
|
|
|
$legacyHeadline = Sanitizer::escapeId( $safeHeadline,
|
2010-01-29 21:44:01 +00:00
|
|
|
|
array( 'noninitial', 'legacy' ) );
|
|
|
|
|
|
$safeHeadline = Sanitizer::escapeId( $safeHeadline );
|
2009-01-10 17:16:21 +00:00
|
|
|
|
|
|
|
|
|
|
if ( $legacyHeadline == $safeHeadline ) {
|
|
|
|
|
|
# No reason to have both (in fact, we can't)
|
|
|
|
|
|
$legacyHeadline = false;
|
|
|
|
|
|
}
|
2010-01-29 21:44:01 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$legacyHeadline = false;
|
|
|
|
|
|
$safeHeadline = Sanitizer::escapeId( $safeHeadline,
|
|
|
|
|
|
'noninitial' );
|
2009-01-10 17:16:21 +00:00
|
|
|
|
}
|
2009-01-05 15:59:46 +00:00
|
|
|
|
|
2010-12-11 03:52:35 +00:00
|
|
|
|
# HTML names must be case-insensitively unique (bug 10721).
|
|
|
|
|
|
# This does not apply to Unicode characters per
|
2010-10-08 22:51:03 +00:00
|
|
|
|
# http://dev.w3.org/html5/spec/infrastructure.html#case-sensitivity-and-string-comparison
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: We may be changing them depending on the current locale.
|
2009-01-10 17:16:21 +00:00
|
|
|
|
$arrayKey = strtolower( $safeHeadline );
|
|
|
|
|
|
if ( $legacyHeadline === false ) {
|
2009-01-05 15:59:46 +00:00
|
|
|
|
$legacyArrayKey = false;
|
|
|
|
|
|
} else {
|
2009-01-10 17:16:21 +00:00
|
|
|
|
$legacyArrayKey = strtolower( $legacyHeadline );
|
2009-01-05 15:59:46 +00:00
|
|
|
|
}
|
2008-03-13 18:30:50 +00:00
|
|
|
|
|
2004-03-21 11:28:44 +00:00
|
|
|
|
# count how many in assoc. array so we can track dupes in anchors
|
2009-01-05 15:59:46 +00:00
|
|
|
|
if ( isset( $refers[$arrayKey] ) ) {
|
|
|
|
|
|
$refers[$arrayKey]++;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$refers[$arrayKey] = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( isset( $refers[$legacyArrayKey] ) ) {
|
|
|
|
|
|
$refers[$legacyArrayKey]++;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$refers[$legacyArrayKey] = 1;
|
|
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2005-01-15 23:21:52 +00:00
|
|
|
|
# Don't number the heading if it is the only one (looks silly)
|
2011-03-06 21:16:22 +00:00
|
|
|
|
if ( count( $matches[3] ) > 1 && $this->mOptions->getNumberHeadings() ) {
|
2005-01-15 23:21:52 +00:00
|
|
|
|
# the two are different if the line contains a link
|
2012-06-03 14:15:28 +00:00
|
|
|
|
$headline = Html::element( 'span', array( 'class' => 'mw-headline-number' ), $numbering ) . ' ' . $headline;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2004-03-21 11:28:44 +00:00
|
|
|
|
# Create the anchor for linking from the TOC to the section
|
2009-01-10 17:16:21 +00:00
|
|
|
|
$anchor = $safeHeadline;
|
|
|
|
|
|
$legacyAnchor = $legacyHeadline;
|
2009-01-05 15:59:46 +00:00
|
|
|
|
if ( $refers[$arrayKey] > 1 ) {
|
|
|
|
|
|
$anchor .= '_' . $refers[$arrayKey];
|
|
|
|
|
|
}
|
2009-01-10 17:16:21 +00:00
|
|
|
|
if ( $legacyHeadline !== false && $refers[$legacyArrayKey] > 1 ) {
|
2009-01-05 15:59:46 +00:00
|
|
|
|
$legacyAnchor .= '_' . $refers[$legacyArrayKey];
|
2004-03-21 11:28:44 +00:00
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $enoughToc && ( !isset( $wgMaxTocLevel ) || $toclevel < $wgMaxTocLevel ) ) {
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$toc .= Linker::tocLine( $anchor, $tocline,
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$numbering, $toclevel, ( $isTemplate ? false : $sectionIndex ) );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2009-06-25 11:05:22 +00:00
|
|
|
|
# Add the section to the section tree
|
|
|
|
|
|
# Find the DOM node for this header
|
|
|
|
|
|
while ( $node && !$isTemplate ) {
|
|
|
|
|
|
if ( $node->getName() === 'h' ) {
|
|
|
|
|
|
$bits = $node->splitHeading();
|
2010-10-18 23:50:33 +00:00
|
|
|
|
if ( $bits['i'] == $sectionIndex ) {
|
2009-06-25 11:05:22 +00:00
|
|
|
|
break;
|
2010-10-18 23:50:33 +00:00
|
|
|
|
}
|
2009-06-25 11:05:22 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
$byteOffset += mb_strlen( $this->mStripState->unstripBoth(
|
2009-06-25 11:05:22 +00:00
|
|
|
|
$frame->expand( $node, PPFrame::RECOVER_ORIG ) ) );
|
|
|
|
|
|
$node = $node->getNextSibling();
|
|
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
$tocraw[] = array(
|
2009-06-25 11:05:22 +00:00
|
|
|
|
'toclevel' => $toclevel,
|
|
|
|
|
|
'level' => $level,
|
|
|
|
|
|
'line' => $tocline,
|
|
|
|
|
|
'number' => $numbering,
|
2010-03-30 21:20:05 +00:00
|
|
|
|
'index' => ( $isTemplate ? 'T-' : '' ) . $sectionIndex,
|
2009-06-25 11:05:22 +00:00
|
|
|
|
'fromtitle' => $titleText,
|
|
|
|
|
|
'byteoffset' => ( $isTemplate ? null : $byteOffset ),
|
|
|
|
|
|
'anchor' => $anchor,
|
|
|
|
|
|
);
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2006-10-18 06:53:19 +00:00
|
|
|
|
# give headline the correct <h#> tag
|
2011-10-25 22:18:33 +00:00
|
|
|
|
if ( $maybeShowEditLink && $sectionIndex !== false ) {
|
2011-01-04 11:31:06 +00:00
|
|
|
|
// Output edit section links as markers with styles that can be customized by skins
|
|
|
|
|
|
if ( $isTemplate ) {
|
|
|
|
|
|
# Put a T flag in the section identifier, to indicate to extractSections()
|
|
|
|
|
|
# that sections inside <includeonly> should be counted.
|
|
|
|
|
|
$editlinkArgs = array( $titleText, "T-$sectionIndex"/*, null */ );
|
2008-01-05 12:39:12 +00:00
|
|
|
|
} else {
|
2011-01-04 11:31:06 +00:00
|
|
|
|
$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
|
|
|
|
|
|
// be able to convert that piece of data.
|
2011-02-06 01:38:33 +00:00
|
|
|
|
$editlink = '<mw:editsection page="' . htmlspecialchars($editlinkArgs[0]);
|
2011-01-04 11:31:06 +00:00
|
|
|
|
$editlink .= '" section="' . htmlspecialchars($editlinkArgs[1]) .'"';
|
|
|
|
|
|
if ( isset($editlinkArgs[2]) ) {
|
2011-02-06 01:38:33 +00:00
|
|
|
|
$editlink .= '>' . $editlinkArgs[2] . '</mw:editsection>';
|
2011-01-04 11:31:06 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$editlink .= '/>';
|
2008-01-05 12:39:12 +00:00
|
|
|
|
}
|
2007-01-08 02:11:45 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$editlink = '';
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$head[$headlineCount] = Linker::makeHeadline( $level,
|
2009-01-05 15:59:46 +00:00
|
|
|
|
$matches['attrib'][$headlineCount], $anchor, $headline,
|
|
|
|
|
|
$editlink, $legacyAnchor );
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2004-03-21 11:28:44 +00:00
|
|
|
|
$headlineCount++;
|
2004-04-12 23:59:37 +00:00
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2009-06-20 18:25:30 +00:00
|
|
|
|
$this->setOutputType( $oldType );
|
2007-12-27 20:14:07 +00:00
|
|
|
|
|
2007-04-30 19:51:56 +00:00
|
|
|
|
# Never ever show TOC if no headers
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $numVisible < 1 ) {
|
2007-04-30 19:51:56 +00:00
|
|
|
|
$enoughToc = false;
|
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $enoughToc ) {
|
|
|
|
|
|
if ( $prevtoclevel > 0 && $prevtoclevel < $wgMaxTocLevel ) {
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$toc .= Linker::tocUnindent( $prevtoclevel - 1 );
|
2006-04-25 19:43:46 +00:00
|
|
|
|
}
|
2011-10-19 15:30:02 +00:00
|
|
|
|
$toc = Linker::tocList( $toc, $this->mOptions->getUserLangObj() );
|
2009-07-14 13:35:07 +00:00
|
|
|
|
$this->mOutput->setTOCHTML( $toc );
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2009-06-21 12:52:24 +00:00
|
|
|
|
if ( $isMain ) {
|
|
|
|
|
|
$this->mOutput->setSections( $tocraw );
|
|
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
|
2004-03-21 11:28:44 +00:00
|
|
|
|
# split up and insert constructed headlines
|
2004-06-08 18:11:28 +00:00
|
|
|
|
$blocks = preg_split( '/<H[1-6].*?' . '>.*?<\/H[1-6]>/i', $text );
|
2004-03-21 11:28:44 +00:00
|
|
|
|
$i = 0;
|
2011-07-24 21:36:04 +00:00
|
|
|
|
|
2011-07-18 23:23:14 +00:00
|
|
|
|
// build an array of document sections
|
|
|
|
|
|
$sections = array();
|
2011-07-24 21:36:04 +00:00
|
|
|
|
foreach ( $blocks as $block ) {
|
2011-07-18 23:23:14 +00:00
|
|
|
|
// $head is zero-based, sections aren't.
|
|
|
|
|
|
if ( empty( $head[$i - 1] ) ) {
|
|
|
|
|
|
$sections[$i] = $block;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$sections[$i] = $head[$i - 1] . $block;
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-07-18 23:23:14 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Send a hook, one per section.
|
|
|
|
|
|
* The idea here is to be able to make section-level DIVs, but to do so in a
|
|
|
|
|
|
* lower-impact, more correct way than r50769
|
|
|
|
|
|
*
|
|
|
|
|
|
* $this : caller
|
|
|
|
|
|
* $section : the section number
|
|
|
|
|
|
* &$sectionContent : ref to the content of the section
|
|
|
|
|
|
* $showEditLinks : boolean describing whether this section has an edit link
|
|
|
|
|
|
*/
|
|
|
|
|
|
wfRunHooks( 'ParserSectionCreate', array( $this, $i, &$sections[$i], $showEditLink ) );
|
2011-07-24 21:36:04 +00:00
|
|
|
|
|
2004-02-26 13:37:26 +00:00
|
|
|
|
$i++;
|
|
|
|
|
|
}
|
2011-07-18 23:23:14 +00:00
|
|
|
|
|
|
|
|
|
|
if ( $enoughToc && $isMain && !$this->mForceTocPosition ) {
|
|
|
|
|
|
// append the TOC at the beginning
|
|
|
|
|
|
// Top anchor now in skin
|
|
|
|
|
|
$sections[0] = $sections[0] . $toc . "\n";
|
|
|
|
|
|
}
|
2011-07-24 21:36:04 +00:00
|
|
|
|
|
2011-07-18 23:23:14 +00:00
|
|
|
|
$full .= join( '', $sections );
|
2011-07-24 21:36:04 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->mForceTocPosition ) {
|
2006-05-23 07:19:01 +00:00
|
|
|
|
return str_replace( '<!--MWTOC-->', $toc, $full );
|
2004-06-29 23:59:30 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
return $full;
|
|
|
|
|
|
}
|
2004-02-26 13:37:26 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* Transform wiki markup when saving a page by doing "\r\n" -> "\n"
|
2004-09-21 05:49:12 +00:00
|
|
|
|
* conversion, substitting signatures, {{subst:}} templates, etc.
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String: the text to transform
|
2010-10-16 18:58:29 +00:00
|
|
|
|
* @param $title Title: the Title object for the current article
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $user User: the User object describing the current user
|
|
|
|
|
|
* @param $options ParserOptions: parsing options
|
|
|
|
|
|
* @param $clearState Boolean: whether to clear the parser state first
|
|
|
|
|
|
* @return String: the altered wiki markup
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2010-12-26 19:30:10 +00:00
|
|
|
|
public function preSaveTransform( $text, Title $title, User $user, ParserOptions $options, $clearState = true ) {
|
2011-02-22 15:05:08 +00:00
|
|
|
|
$this->startParse( $title, $options, self::OT_WIKI, $clearState );
|
2010-12-10 18:17:20 +00:00
|
|
|
|
$this->setUser( $user );
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2004-04-09 16:22:12 +00:00
|
|
|
|
$pairs = array(
|
|
|
|
|
|
"\r\n" => "\n",
|
2005-04-21 06:30:48 +00:00
|
|
|
|
);
|
2004-11-20 11:28:37 +00:00
|
|
|
|
$text = str_replace( array_keys( $pairs ), array_values( $pairs ), $text );
|
2011-01-16 21:12:26 +00:00
|
|
|
|
if( $options->getPreSaveTransform() ) {
|
|
|
|
|
|
$text = $this->pstPass2( $text, $user );
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = $this->mStripState->unstripBoth( $text );
|
2010-12-10 18:17:20 +00:00
|
|
|
|
|
|
|
|
|
|
$this->setUser( null ); #Reset
|
|
|
|
|
|
|
2004-03-06 01:49:16 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Pre-save transform helper function
|
2006-04-19 15:46:24 +00:00
|
|
|
|
* @private
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
* @param $user User
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function pstPass2( $text, $user ) {
|
2005-04-21 06:30:48 +00:00
|
|
|
|
global $wgContLang, $wgLocaltimezone;
|
2004-03-20 15:03:26 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
# Note: This is the timestamp saved as hardcoded wikitext to
|
|
|
|
|
|
# the database, we use $wgContLang here in order to give
|
|
|
|
|
|
# everyone the same signature and use the default one rather
|
|
|
|
|
|
# than the one selected in each user's preferences.
|
|
|
|
|
|
# (see also bug 12815)
|
2008-02-09 20:39:32 +00:00
|
|
|
|
$ts = $this->mOptions->getTimestamp();
|
2005-11-15 00:38:39 +00:00
|
|
|
|
if ( isset( $wgLocaltimezone ) ) {
|
2010-01-08 01:48:53 +00:00
|
|
|
|
$tz = $wgLocaltimezone;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$tz = date_default_timezone_get();
|
|
|
|
|
|
}
|
2009-01-31 17:34:47 +00:00
|
|
|
|
|
2010-01-08 01:48:53 +00:00
|
|
|
|
$unixts = wfTimestamp( TS_UNIX, $ts );
|
|
|
|
|
|
$oldtz = date_default_timezone_get();
|
|
|
|
|
|
date_default_timezone_set( $tz );
|
|
|
|
|
|
$ts = date( 'YmdHis', $unixts );
|
|
|
|
|
|
$tzMsg = date( 'T', $unixts ); # might vary on DST changeover!
|
2009-01-31 17:34:47 +00:00
|
|
|
|
|
2010-05-21 21:08:05 +00:00
|
|
|
|
# Allow translation of timezones through wiki. date() can return
|
2010-03-30 21:20:05 +00:00
|
|
|
|
# whatever crap the system uses, localised or not, so we cannot
|
|
|
|
|
|
# ship premade translations.
|
2010-01-08 01:48:53 +00:00
|
|
|
|
$key = 'timezone-' . strtolower( trim( $tzMsg ) );
|
2011-01-05 15:50:34 +00:00
|
|
|
|
$msg = wfMessage( $key )->inContentLanguage();
|
|
|
|
|
|
if ( $msg->exists() ) {
|
|
|
|
|
|
$tzMsg = $msg->text();
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2010-01-08 01:48:53 +00:00
|
|
|
|
|
|
|
|
|
|
date_default_timezone_set( $oldtz );
|
2008-06-25 12:09:32 +00:00
|
|
|
|
|
2010-01-08 01:48:53 +00:00
|
|
|
|
$d = $wgContLang->timeanddate( $ts, false, false ) . " ($tzMsg)";
|
2004-03-06 01:49:16 +00:00
|
|
|
|
|
2006-01-07 23:37:40 +00:00
|
|
|
|
# Variable replacement
|
|
|
|
|
|
# Because mOutputType is OT_WIKI, this will only process {{subst:xxx}} type tags
|
|
|
|
|
|
$text = $this->replaceVariables( $text );
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2011-02-19 19:18:02 +00:00
|
|
|
|
# This works almost by chance, as the replaceVariables are done before the getUserSig(),
|
2011-01-23 18:45:21 +00:00
|
|
|
|
# which may corrupt this parser instance via its wfMsgExt( parsemag ) call-
|
|
|
|
|
|
|
2006-01-12 15:42:38 +00:00
|
|
|
|
# Signatures
|
|
|
|
|
|
$sigText = $this->getUserSig( $user );
|
2006-03-11 17:13:49 +00:00
|
|
|
|
$text = strtr( $text, array(
|
2006-01-12 15:42:38 +00:00
|
|
|
|
'~~~~~' => $d,
|
|
|
|
|
|
'~~~~' => "$sigText $d",
|
|
|
|
|
|
'~~~' => $sigText
|
|
|
|
|
|
) );
|
2006-01-07 23:37:40 +00:00
|
|
|
|
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
# Context links: [[|name]] and [[name (context)|]]
|
2012-05-04 19:47:00 +00:00
|
|
|
|
$tc = '[' . Title::legalChars() . ']';
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
$nc = '[ _0-9A-Za-z\x80-\xff-]'; # Namespaces can use non-ascii!
|
|
|
|
|
|
|
2011-08-02 16:23:46 +00:00
|
|
|
|
$p1 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\))\\|]]/"; # [[ns:page (context)|]]
|
|
|
|
|
|
$p4 = "/\[\[(:?$nc+:|:|)($tc+?)( ?($tc+))\\|]]/"; # [[ns:page(context)|]]
|
2012-05-23 19:32:29 +00:00
|
|
|
|
$p3 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\)|)((?:, |,)$tc+|)\\|]]/"; # [[ns:page (context), context|]]
|
Moving Conrad's recent parser work out to a branch. Reverted r62434, r62416, r62150, r62111, r62085, r62081, r62080, r62077, r62076, r62069, r62049, r62035.
2010-02-19 05:19:32 +00:00
|
|
|
|
$p2 = "/\[\[\\|($tc+)]]/"; # [[|page]]
|
|
|
|
|
|
|
|
|
|
|
|
# try $p1 first, to turn "[[A, B (C)|]]" into "[[A, B (C)|A, B]]"
|
|
|
|
|
|
$text = preg_replace( $p1, '[[\\1\\2\\3|\\2]]', $text );
|
|
|
|
|
|
$text = preg_replace( $p4, '[[\\1\\2\\3|\\2]]', $text );
|
|
|
|
|
|
$text = preg_replace( $p3, '[[\\1\\2\\3\\4|\\2]]', $text );
|
|
|
|
|
|
|
|
|
|
|
|
$t = $this->mTitle->getText();
|
|
|
|
|
|
$m = array();
|
|
|
|
|
|
if ( preg_match( "/^($nc+:|)$tc+?( \\($tc+\\))$/", $t, $m ) ) {
|
|
|
|
|
|
$text = preg_replace( $p2, "[[$m[1]\\1$m[2]|\\1]]", $text );
|
|
|
|
|
|
} elseif ( preg_match( "/^($nc+:|)$tc+?(, $tc+|)$/", $t, $m ) && "$m[1]$m[2]" != '' ) {
|
|
|
|
|
|
$text = preg_replace( $p2, "[[$m[1]\\1$m[2]|\\1]]", $text );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# if there's no context, don't bother duplicating the title
|
|
|
|
|
|
$text = preg_replace( $p2, '[[\\1]]', $text );
|
|
|
|
|
|
}
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2004-03-06 01:49:16 +00:00
|
|
|
|
# Trim trailing whitespace
|
|
|
|
|
|
$text = rtrim( $text );
|
|
|
|
|
|
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-11-15 00:38:39 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Fetch the user's signature text, if any, and normalize to
|
|
|
|
|
|
* validated, ready-to-insert wikitext.
|
2009-09-30 10:35:34 +00:00
|
|
|
|
* If you have pre-fetched the nickname or the fancySig option, you can
|
|
|
|
|
|
* specify them here to save a database query.
|
2011-01-23 18:45:21 +00:00
|
|
|
|
* Do not reuse this parser instance after calling getUserSig(),
|
|
|
|
|
|
* as it may have changed if it's the $wgParser.
|
2005-11-15 00:38:39 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $user User
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $nickname String|bool nickname to use or false to use user's default nickname
|
|
|
|
|
|
* @param $fancySig Boolean|null whether the nicknname is the complete signature
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* or null to use default value
|
2005-11-15 00:38:39 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2009-09-30 10:35:34 +00:00
|
|
|
|
function getUserSig( &$user, $nickname = false, $fancySig = null ) {
|
2007-06-13 16:28:19 +00:00
|
|
|
|
global $wgMaxSigChars;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2006-01-07 23:09:21 +00:00
|
|
|
|
$username = $user->getName();
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# If not given, retrieve from the user object.
|
2009-09-30 10:35:34 +00:00
|
|
|
|
if ( $nickname === false )
|
|
|
|
|
|
$nickname = $user->getOption( 'nickname' );
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( is_null( $fancySig ) ) {
|
2009-09-30 10:35:34 +00:00
|
|
|
|
$fancySig = $user->getBoolOption( 'fancysig' );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2009-09-09 17:30:52 +00:00
|
|
|
|
$nickname = $nickname == null ? $username : $nickname;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( mb_strlen( $nickname ) > $wgMaxSigChars ) {
|
2007-06-13 16:28:19 +00:00
|
|
|
|
$nickname = $username;
|
|
|
|
|
|
wfDebug( __METHOD__ . ": $username has overlong signature.\n" );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
} elseif ( $fancySig !== false ) {
|
2006-01-07 23:09:21 +00:00
|
|
|
|
# Sig. might contain markup; validate this
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->validateSig( $nickname ) !== false ) {
|
2006-01-07 23:09:21 +00:00
|
|
|
|
# Validated; clean up (if needed) and return it
|
2006-04-30 20:09:44 +00:00
|
|
|
|
return $this->cleanSig( $nickname, true );
|
2005-11-15 00:38:39 +00:00
|
|
|
|
} else {
|
2006-01-07 23:09:21 +00:00
|
|
|
|
# Failed to validate; fall back to the default
|
|
|
|
|
|
$nickname = $username;
|
2008-08-26 14:37:15 +00:00
|
|
|
|
wfDebug( __METHOD__.": $username has bad XML tags in signature.\n" );
|
2005-11-15 00:38:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Make sure nickname doesnt get a sig in a sig
|
2011-12-06 23:07:13 +00:00
|
|
|
|
$nickname = self::cleanSigInSig( $nickname );
|
2006-06-23 19:50:55 +00:00
|
|
|
|
|
2006-01-07 23:09:21 +00:00
|
|
|
|
# If we're still here, make it a link to the user page
|
2007-11-15 03:30:03 +00:00
|
|
|
|
$userText = wfEscapeWikiText( $username );
|
|
|
|
|
|
$nickText = wfEscapeWikiText( $nickname );
|
2011-06-22 17:45:31 +00:00
|
|
|
|
$msgName = $user->isAnon() ? 'signature-anon' : 'signature';
|
|
|
|
|
|
|
|
|
|
|
|
return wfMessage( $msgName, $userText, $nickText )->inContentLanguage()->title( $this->getTitle() )->text();
|
2005-11-15 00:38:39 +00:00
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-11-15 00:38:39 +00:00
|
|
|
|
/**
|
2006-01-07 23:09:21 +00:00
|
|
|
|
* Check that the user's signature contains no bad XML
|
2005-11-15 00:38:39 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String
|
2005-11-15 00:38:39 +00:00
|
|
|
|
* @return mixed An expanded string, or false if invalid.
|
|
|
|
|
|
*/
|
2008-08-25 04:27:40 +00:00
|
|
|
|
function validateSig( $text ) {
|
2008-09-22 17:01:44 +00:00
|
|
|
|
return( Xml::isWellFormedXmlFragment( $text ) ? $text : false );
|
2005-11-15 00:38:39 +00:00
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2006-01-07 23:09:21 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Clean up signature text
|
|
|
|
|
|
*
|
2006-06-23 19:50:55 +00:00
|
|
|
|
* 1) Strip ~~~, ~~~~ and ~~~~~ out of signatures @see cleanSigInSig
|
2006-01-13 09:47:09 +00:00
|
|
|
|
* 2) Substitute all transclusions
|
2006-01-07 23:09:21 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $parsing bool Whether we're cleaning (preferences save) or parsing
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return String: signature text
|
2006-01-07 23:09:21 +00:00
|
|
|
|
*/
|
2011-12-06 23:07:13 +00:00
|
|
|
|
public function cleanSig( $text, $parsing = false ) {
|
2007-12-01 06:52:25 +00:00
|
|
|
|
if ( !$parsing ) {
|
|
|
|
|
|
global $wgTitle;
|
2011-08-11 13:57:15 +00:00
|
|
|
|
$this->startParse( $wgTitle, new ParserOptions, self::OT_PREPROCESS, true );
|
2007-12-01 06:52:25 +00:00
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2008-07-31 09:41:28 +00:00
|
|
|
|
# Option to disable this feature
|
|
|
|
|
|
if ( !$this->mOptions->getCleanSignatures() ) {
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: Regex doesn't respect extension tags or nowiki
|
2007-12-01 06:52:25 +00:00
|
|
|
|
# => Move this logic to braceSubstitution()
|
2006-07-14 15:39:23 +00:00
|
|
|
|
$substWord = MagicWord::get( 'subst' );
|
2006-01-13 09:47:09 +00:00
|
|
|
|
$substRegex = '/\{\{(?!(?:' . $substWord->getBaseRegex() . '))/x' . $substWord->getRegexCase();
|
|
|
|
|
|
$substText = '{{' . $substWord->getSynonym( 0 );
|
|
|
|
|
|
|
|
|
|
|
|
$text = preg_replace( $substRegex, $substText, $text );
|
2011-12-06 23:07:13 +00:00
|
|
|
|
$text = self::cleanSigInSig( $text );
|
2007-12-01 06:52:25 +00:00
|
|
|
|
$dom = $this->preprocessToDom( $text );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$frame = $this->getPreprocessor()->newFrame();
|
|
|
|
|
|
$text = $frame->expand( $dom );
|
2007-12-01 06:52:25 +00:00
|
|
|
|
|
|
|
|
|
|
if ( !$parsing ) {
|
|
|
|
|
|
$text = $this->mStripState->unstripBoth( $text );
|
|
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2006-01-08 05:29:58 +00:00
|
|
|
|
return $text;
|
2006-01-07 23:09:21 +00:00
|
|
|
|
}
|
2006-06-23 19:50:55 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Strip ~~~, ~~~~ and ~~~~~ out of signatures
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @return String: signature text with /~{3,5}/ removed
|
2006-06-23 19:50:55 +00:00
|
|
|
|
*/
|
2011-12-06 23:07:13 +00:00
|
|
|
|
public static function cleanSigInSig( $text ) {
|
2006-06-23 19:50:55 +00:00
|
|
|
|
$text = preg_replace( '/~{3,5}/', '', $text );
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Set up some variables which are usually set up in parse()
|
|
|
|
|
|
* so that an external function can call some class members with confidence
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $title Title|null
|
|
|
|
|
|
* @param $options ParserOptions
|
|
|
|
|
|
* @param $outputType
|
|
|
|
|
|
* @param $clearState bool
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2011-01-26 00:23:39 +00:00
|
|
|
|
public function startExternalParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
|
2011-02-22 15:05:08 +00:00
|
|
|
|
$this->startParse( $title, $options, $outputType, $clearState );
|
|
|
|
|
|
}
|
2011-02-24 20:23:49 +00:00
|
|
|
|
|
2011-08-05 00:33:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param $title Title|null
|
|
|
|
|
|
* @param $options ParserOptions
|
|
|
|
|
|
* @param $outputType
|
|
|
|
|
|
* @param $clearState bool
|
|
|
|
|
|
*/
|
2011-02-22 15:05:08 +00:00
|
|
|
|
private function startParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
|
2008-01-16 02:47:31 +00:00
|
|
|
|
$this->setTitle( $title );
|
2004-03-27 22:47:25 +00:00
|
|
|
|
$this->mOptions = $options;
|
2006-08-14 07:10:31 +00:00
|
|
|
|
$this->setOutputType( $outputType );
|
2004-03-27 22:47:25 +00:00
|
|
|
|
if ( $clearState ) {
|
|
|
|
|
|
$this->clearState();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-04-05 10:38:40 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2008-01-19 09:03:45 +00:00
|
|
|
|
* Wrapper for preprocess()
|
2007-11-20 10:55:08 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String: the text to preprocess
|
|
|
|
|
|
* @param $options ParserOptions: options
|
2011-02-09 15:19:45 +00:00
|
|
|
|
* @param $title Title object or null to use $wgTitle
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return String
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2011-02-09 15:19:45 +00:00
|
|
|
|
public function transformMsg( $text, $options, $title = null ) {
|
2004-04-05 10:38:40 +00:00
|
|
|
|
static $executing = false;
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2004-04-05 10:38:40 +00:00
|
|
|
|
# Guard against infinite recursion
|
|
|
|
|
|
if ( $executing ) {
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
$executing = true;
|
|
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2011-02-09 15:19:45 +00:00
|
|
|
|
if ( !$title ) {
|
|
|
|
|
|
global $wgTitle;
|
|
|
|
|
|
$title = $wgTitle;
|
|
|
|
|
|
}
|
2011-01-26 00:23:39 +00:00
|
|
|
|
if ( !$title ) {
|
|
|
|
|
|
# It's not uncommon having a null $wgTitle in scripts. See r80898
|
|
|
|
|
|
# Create a ghost title in such case
|
|
|
|
|
|
$title = Title::newFromText( 'Dwimmerlaik' );
|
|
|
|
|
|
}
|
|
|
|
|
|
$text = $this->preprocess( $text, $title, $options );
|
2004-04-12 23:59:37 +00:00
|
|
|
|
|
2004-04-05 10:38:40 +00:00
|
|
|
|
$executing = false;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-04-05 10:38:40 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2004-06-09 12:15:42 +00:00
|
|
|
|
|
2004-09-21 05:49:12 +00:00
|
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* Create an HTML-style tag, e.g. "<yourtag>special text</yourtag>"
|
2006-02-28 05:18:36 +00:00
|
|
|
|
* The callback should have the following form:
|
2011-04-22 19:06:52 +00:00
|
|
|
|
* function myParserHook( $text, $params, $parser, $frame ) { ... }
|
2006-02-28 05:18:36 +00:00
|
|
|
|
*
|
|
|
|
|
|
* Transform and return $text. Use $parser for any required context, e.g. use
|
|
|
|
|
|
* $parser->getTitle() and $parser->getOptions() not $wgTitle or $wgOut->mParserOptions
|
2005-11-26 23:04:05 +00:00
|
|
|
|
*
|
2011-04-22 19:06:52 +00:00
|
|
|
|
* Hooks may return extended information by returning an array, of which the
|
|
|
|
|
|
* first numbered element (index 0) must be the return string, and all other
|
|
|
|
|
|
* entries are extracted into local variables within an internal function
|
|
|
|
|
|
* in the Parser class.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This interface (introduced r61913) appears to be undocumented, but
|
|
|
|
|
|
* 'markerName' is used by some core tag hooks to override which strip
|
|
|
|
|
|
* array their results are placed in. **Use great caution if attempting
|
|
|
|
|
|
* this interface, as it is not documented and injudicious use could smash
|
|
|
|
|
|
* private variables.**
|
|
|
|
|
|
*
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* @param $tag Mixed: the tag to use, e.g. 'hook' for "<hook>"
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $callback Mixed: the callback function (and object) to use for the tag
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @return Mixed|null The old value of the mTagHooks array associated with the hook
|
2004-09-21 05:49:12 +00:00
|
|
|
|
*/
|
2010-06-10 21:05:58 +00:00
|
|
|
|
public function setHook( $tag, $callback ) {
|
2006-06-01 06:41:32 +00:00
|
|
|
|
$tag = strtolower( $tag );
|
2012-02-09 19:29:36 +00:00
|
|
|
|
if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) {
|
|
|
|
|
|
throw new MWException( "Invalid character {$m[0]} in setHook('$tag', ...) call" );
|
|
|
|
|
|
}
|
2006-11-29 05:45:03 +00:00
|
|
|
|
$oldVal = isset( $this->mTagHooks[$tag] ) ? $this->mTagHooks[$tag] : null;
|
2004-06-12 06:15:09 +00:00
|
|
|
|
$this->mTagHooks[$tag] = $callback;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !in_array( $tag, $this->mStripList ) ) {
|
2008-03-18 21:45:18 +00:00
|
|
|
|
$this->mStripList[] = $tag;
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2004-06-09 12:15:42 +00:00
|
|
|
|
return $oldVal;
|
|
|
|
|
|
}
|
2004-10-15 17:39:10 +00:00
|
|
|
|
|
2011-04-22 19:06:52 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* As setHook(), but letting the contents be parsed.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Transparent tag hooks are like regular XML-style tag hooks, except they
|
|
|
|
|
|
* operate late in the transformation sequence, on HTML instead of wikitext.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This is probably obsoleted by things dealing with parser frames?
|
|
|
|
|
|
* The only extension currently using it is geoserver.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.10
|
|
|
|
|
|
* @todo better document or deprecate this
|
|
|
|
|
|
*
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* @param $tag Mixed: the tag to use, e.g. 'hook' for "<hook>"
|
2011-04-22 19:06:52 +00:00
|
|
|
|
* @param $callback Mixed: the callback function (and object) to use for the tag
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @return Mixed|null The old value of the mTagHooks array associated with the hook
|
2011-04-22 19:06:52 +00:00
|
|
|
|
*/
|
2007-07-15 11:14:53 +00:00
|
|
|
|
function setTransparentTagHook( $tag, $callback ) {
|
|
|
|
|
|
$tag = strtolower( $tag );
|
2012-02-09 19:29:36 +00:00
|
|
|
|
if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) {
|
|
|
|
|
|
throw new MWException( "Invalid character {$m[0]} in setTransparentHook('$tag', ...) call" );
|
|
|
|
|
|
}
|
2007-07-15 11:14:53 +00:00
|
|
|
|
$oldVal = isset( $this->mTransparentTagHooks[$tag] ) ? $this->mTransparentTagHooks[$tag] : null;
|
|
|
|
|
|
$this->mTransparentTagHooks[$tag] = $callback;
|
|
|
|
|
|
|
|
|
|
|
|
return $oldVal;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-01-22 10:10:21 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Remove all tag hooks
|
|
|
|
|
|
*/
|
|
|
|
|
|
function clearTagHooks() {
|
|
|
|
|
|
$this->mTagHooks = array();
|
2012-01-04 21:30:06 +00:00
|
|
|
|
$this->mFunctionTagHooks = array();
|
2008-01-22 10:10:21 +00:00
|
|
|
|
$this->mStripList = $this->mDefaultStripList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-04-05 09:40:25 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Create a function, e.g. {{sum:1|2|3}}
|
|
|
|
|
|
* The callback function should have the form:
|
|
|
|
|
|
* function myParserFunction( &$parser, $arg1, $arg2, $arg3 ) { ... }
|
|
|
|
|
|
*
|
2008-07-23 14:51:39 +00:00
|
|
|
|
* Or with SFH_OBJECT_ARGS:
|
|
|
|
|
|
* function myParserFunction( $parser, $frame, $args ) { ... }
|
|
|
|
|
|
*
|
2006-10-17 08:49:27 +00:00
|
|
|
|
* The callback may either return the text result of the function, or an array with the text
|
|
|
|
|
|
* in element 0, and a number of flags in the other elements. The names of the flags are
|
2006-04-05 09:40:25 +00:00
|
|
|
|
* specified in the keys. Valid flags are:
|
2006-10-17 08:49:27 +00:00
|
|
|
|
* found The text returned is valid, stop processing the template. This
|
2006-04-05 09:40:25 +00:00
|
|
|
|
* is on by default.
|
|
|
|
|
|
* nowiki Wiki markup in the return value should be escaped
|
|
|
|
|
|
* isHTML The returned text is HTML, armour it against wikitext transformation
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $id String: The magic word ID
|
|
|
|
|
|
* @param $callback Mixed: the callback function (and object) to use
|
|
|
|
|
|
* @param $flags Integer: a combination of the following flags:
|
2008-07-23 14:51:39 +00:00
|
|
|
|
* SFH_NO_HASH No leading hash, i.e. {{plural:...}} instead of {{#if:...}}
|
|
|
|
|
|
*
|
2010-01-07 04:13:14 +00:00
|
|
|
|
* SFH_OBJECT_ARGS Pass the template arguments as PPNode objects instead of text. This
|
2008-07-23 14:51:39 +00:00
|
|
|
|
* allows for conditional expansion of the parse tree, allowing you to eliminate dead
|
2010-01-07 04:13:14 +00:00
|
|
|
|
* branches and thus speed up parsing. It is also possible to analyse the parse tree of
|
2008-07-23 14:51:39 +00:00
|
|
|
|
* the arguments, and to control the way they are expanded.
|
|
|
|
|
|
*
|
|
|
|
|
|
* The $frame parameter is a PPFrame. This can be used to produce expanded text from the
|
|
|
|
|
|
* arguments, for instance:
|
|
|
|
|
|
* $text = isset( $args[0] ) ? $frame->expand( $args[0] ) : '';
|
|
|
|
|
|
*
|
2010-01-07 04:13:14 +00:00
|
|
|
|
* For technical reasons, $args[0] is pre-expanded and will be a string. This may change in
|
2008-07-23 14:51:39 +00:00
|
|
|
|
* future versions. Please call $frame->expand() on it anyway so that your code keeps
|
|
|
|
|
|
* working if/when this is changed.
|
|
|
|
|
|
*
|
|
|
|
|
|
* If you want whitespace to be trimmed from $args, you need to do it yourself, post-
|
|
|
|
|
|
* expansion.
|
|
|
|
|
|
*
|
2010-01-07 04:13:14 +00:00
|
|
|
|
* Please read the documentation in includes/parser/Preprocessor.php for more information
|
2008-07-23 14:51:39 +00:00
|
|
|
|
* about the methods available in PPFrame and PPNode.
|
2006-04-05 09:40:25 +00:00
|
|
|
|
*
|
2012-02-09 17:41:50 +00:00
|
|
|
|
* @return string|callback The old callback function for this name, if any
|
2006-04-05 09:40:25 +00:00
|
|
|
|
*/
|
2010-06-10 21:05:58 +00:00
|
|
|
|
public function setFunctionHook( $id, $callback, $flags = 0 ) {
|
2009-08-26 15:47:03 +00:00
|
|
|
|
global $wgContLang;
|
|
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$oldVal = isset( $this->mFunctionHooks[$id] ) ? $this->mFunctionHooks[$id][0] : null;
|
|
|
|
|
|
$this->mFunctionHooks[$id] = array( $callback, $flags );
|
2006-07-03 11:07:00 +00:00
|
|
|
|
|
2006-07-03 03:29:57 +00:00
|
|
|
|
# Add to function cache
|
2006-07-14 16:08:16 +00:00
|
|
|
|
$mw = MagicWord::get( $id );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !$mw )
|
2008-08-26 14:37:15 +00:00
|
|
|
|
throw new MWException( __METHOD__.'() expecting a magic word identifier.' );
|
2006-07-03 11:07:00 +00:00
|
|
|
|
|
2006-07-14 16:08:16 +00:00
|
|
|
|
$synonyms = $mw->getSynonyms();
|
|
|
|
|
|
$sensitive = intval( $mw->isCaseSensitive() );
|
|
|
|
|
|
|
2006-07-03 11:07:00 +00:00
|
|
|
|
foreach ( $synonyms as $syn ) {
|
|
|
|
|
|
# Case
|
|
|
|
|
|
if ( !$sensitive ) {
|
2009-08-26 15:47:03 +00:00
|
|
|
|
$syn = $wgContLang->lc( $syn );
|
2006-07-03 11:07:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
# Add leading hash
|
|
|
|
|
|
if ( !( $flags & SFH_NO_HASH ) ) {
|
|
|
|
|
|
$syn = '#' . $syn;
|
|
|
|
|
|
}
|
|
|
|
|
|
# Remove trailing colon
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( substr( $syn, -1, 1 ) === ':' ) {
|
2006-07-03 11:07:00 +00:00
|
|
|
|
$syn = substr( $syn, 0, -1 );
|
|
|
|
|
|
}
|
|
|
|
|
|
$this->mFunctionSynonyms[$sensitive][$syn] = $id;
|
2006-07-02 17:43:32 +00:00
|
|
|
|
}
|
2006-07-03 03:29:57 +00:00
|
|
|
|
return $oldVal;
|
2006-07-02 17:43:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-08-30 07:45:07 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get all registered function hook identifiers
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @return Array
|
2006-08-30 07:45:07 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getFunctionHooks() {
|
|
|
|
|
|
return array_keys( $this->mFunctionHooks );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-07-11 13:03:35 +00:00
|
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* Create a tag function, e.g. "<test>some stuff</test>".
|
2009-07-11 13:03:35 +00:00
|
|
|
|
* Unlike tag hooks, tag functions are parsed at preprocessor level.
|
|
|
|
|
|
* Unlike parser functions, their content is not preprocessed.
|
2012-02-09 21:35:05 +00:00
|
|
|
|
* @return null
|
2009-07-11 13:03:35 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function setFunctionTagHook( $tag, $callback, $flags ) {
|
|
|
|
|
|
$tag = strtolower( $tag );
|
2011-01-16 16:41:15 +00:00
|
|
|
|
if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) throw new MWException( "Invalid character {$m[0]} in setFunctionTagHook('$tag', ...) call" );
|
2009-07-11 13:03:35 +00:00
|
|
|
|
$old = isset( $this->mFunctionTagHooks[$tag] ) ?
|
|
|
|
|
|
$this->mFunctionTagHooks[$tag] : null;
|
|
|
|
|
|
$this->mFunctionTagHooks[$tag] = array( $callback, $flags );
|
|
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( !in_array( $tag, $this->mStripList ) ) {
|
2009-07-11 13:03:35 +00:00
|
|
|
|
$this->mStripList[] = $tag;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $old;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-10-15 17:39:10 +00:00
|
|
|
|
/**
|
2011-05-17 22:03:20 +00:00
|
|
|
|
* @todo FIXME: Update documentation. makeLinkObj() is deprecated.
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* Replace "<!--LINK-->" link placeholders with actual links, in the buffer
|
2006-11-08 07:12:03 +00:00
|
|
|
|
* Placeholders created in Skin::makeLinkObj()
|
2011-08-05 00:33:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
* @param $options int
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return array of link CSS classes, indexed by PDBK.
|
2004-10-15 17:39:10 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function replaceLinkHolders( &$text, $options = 0 ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
return $this->mLinkHolders->replace( $text );
|
2004-10-15 17:39:10 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2005-05-31 08:49:03 +00:00
|
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* Replace "<!--LINK-->" link placeholders with plain text of links
|
2005-05-31 08:49:03 +00:00
|
|
|
|
* (not HTML-formatted).
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @return String
|
2005-05-31 08:49:03 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function replaceLinkHoldersText( $text ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
return $this->mLinkHolders->replaceText( $text );
|
2005-05-31 08:49:03 +00:00
|
|
|
|
}
|
2004-11-20 11:28:37 +00:00
|
|
|
|
|
2004-11-13 12:04:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Renders an image gallery from a text with one line per image.
|
|
|
|
|
|
* text labels may be given by using |-style alternative text. E.g.
|
|
|
|
|
|
* Image:one.jpg|The number "1"
|
|
|
|
|
|
* Image:tree.jpg|A tree
|
|
|
|
|
|
* given as text will return the HTML of a gallery with two images,
|
|
|
|
|
|
* labeled 'The number "1"' and
|
|
|
|
|
|
* 'A tree'.
|
2011-04-22 19:06:52 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param string $text
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param array $params
|
2011-04-22 19:06:52 +00:00
|
|
|
|
* @return string HTML
|
2004-11-13 12:04:31 +00:00
|
|
|
|
*/
|
2006-06-24 00:12:34 +00:00
|
|
|
|
function renderImageGallery( $text, $params ) {
|
2004-11-13 12:04:31 +00:00
|
|
|
|
$ig = new ImageGallery();
|
2007-01-20 22:34:05 +00:00
|
|
|
|
$ig->setContextTitle( $this->mTitle );
|
2004-11-13 12:04:31 +00:00
|
|
|
|
$ig->setShowBytes( false );
|
|
|
|
|
|
$ig->setShowFilename( false );
|
2007-08-22 13:40:22 +00:00
|
|
|
|
$ig->setParser( $this );
|
|
|
|
|
|
$ig->setHideBadImages();
|
2007-07-13 17:25:06 +00:00
|
|
|
|
$ig->setAttributes( Sanitizer::validateTagAttributes( $params, 'table' ) );
|
2004-11-20 11:28:37 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $params['showfilename'] ) ) {
|
2010-03-13 09:43:37 +00:00
|
|
|
|
$ig->setShowFilename( true );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$ig->setShowFilename( false );
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $params['caption'] ) ) {
|
2007-01-04 19:47:11 +00:00
|
|
|
|
$caption = $params['caption'];
|
|
|
|
|
|
$caption = htmlspecialchars( $caption );
|
|
|
|
|
|
$caption = $this->replaceInternalLinks( $caption );
|
2007-01-05 01:07:04 +00:00
|
|
|
|
$ig->setCaptionHtml( $caption );
|
2007-01-04 19:47:11 +00:00
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $params['perrow'] ) ) {
|
2007-02-02 03:32:03 +00:00
|
|
|
|
$ig->setPerRow( $params['perrow'] );
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $params['widths'] ) ) {
|
2007-02-02 03:32:03 +00:00
|
|
|
|
$ig->setWidths( $params['widths'] );
|
|
|
|
|
|
}
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $params['heights'] ) ) {
|
2007-02-02 03:32:03 +00:00
|
|
|
|
$ig->setHeights( $params['heights'] );
|
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-05-31 16:01:26 +00:00
|
|
|
|
wfRunHooks( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) );
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$lines = StringUtils::explode( "\n", $text );
|
2004-11-13 12:04:31 +00:00
|
|
|
|
foreach ( $lines as $line ) {
|
2004-11-20 11:28:37 +00:00
|
|
|
|
# match lines like these:
|
|
|
|
|
|
# Image:someimage.jpg|This is some image
|
2006-10-17 08:49:27 +00:00
|
|
|
|
$matches = array();
|
2004-11-13 12:04:31 +00:00
|
|
|
|
preg_match( "/^([^|]+)(\\|(.*))?$/", $line, $matches );
|
|
|
|
|
|
# Skip empty lines
|
|
|
|
|
|
if ( count( $matches ) == 0 ) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( strpos( $matches[0], '%' ) !== false ) {
|
2010-12-24 09:53:08 +00:00
|
|
|
|
$matches[1] = rawurldecode( $matches[1] );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2011-04-25 13:51:54 +00:00
|
|
|
|
$title = Title::newFromText( $matches[1], NS_FILE );
|
|
|
|
|
|
if ( is_null( $title ) ) {
|
2004-12-15 09:07:21 +00:00
|
|
|
|
# Bogus title. Ignore these so we don't bomb out later.
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2011-05-25 15:39:47 +00:00
|
|
|
|
|
2011-04-25 13:51:54 +00:00
|
|
|
|
$label = '';
|
|
|
|
|
|
$alt = '';
|
2012-04-10 10:30:17 +00:00
|
|
|
|
$link = '';
|
2004-11-13 12:04:31 +00:00
|
|
|
|
if ( isset( $matches[3] ) ) {
|
2011-04-25 13:51:54 +00:00
|
|
|
|
// look for an |alt= definition while trying not to break existing
|
|
|
|
|
|
// captions with multiple pipes (|) in it, until a more sensible grammar
|
|
|
|
|
|
// is defined for images in galleries
|
2011-05-25 15:39:47 +00:00
|
|
|
|
|
2011-04-25 13:51:54 +00:00
|
|
|
|
$matches[3] = $this->recursiveTagParse( trim( $matches[3] ) );
|
2012-04-10 10:30:17 +00:00
|
|
|
|
$parameterMatches = StringUtils::explode('|', $matches[3]);
|
2011-04-25 13:51:54 +00:00
|
|
|
|
$magicWordAlt = MagicWord::get( 'img_alt' );
|
2012-04-10 10:30:17 +00:00
|
|
|
|
$magicWordLink = MagicWord::get( 'img_link' );
|
2011-04-25 13:51:54 +00:00
|
|
|
|
|
2012-04-10 10:30:17 +00:00
|
|
|
|
foreach ( $parameterMatches as $parameterMatch ) {
|
|
|
|
|
|
if ( $match = $magicWordAlt->matchVariableStartToEnd( $parameterMatch ) ) {
|
2011-04-25 13:51:54 +00:00
|
|
|
|
$alt = $this->stripAltText( $match, false );
|
|
|
|
|
|
}
|
2012-04-10 10:30:17 +00:00
|
|
|
|
elseif( $match = $magicWordLink->matchVariableStartToEnd( $parameterMatch ) ){
|
|
|
|
|
|
$link = strip_tags($this->replaceLinkHoldersText($match));
|
|
|
|
|
|
$chars = self::EXT_LINK_URL_CLASS;
|
|
|
|
|
|
$prots = $this->mUrlProtocols;
|
|
|
|
|
|
//check to see if link matches an absolute url, if not then it must be a wiki link.
|
|
|
|
|
|
if(!preg_match( "/^($prots)$chars+$/u", $link)){
|
|
|
|
|
|
$localLinkTitle = Title::newFromText($link);
|
|
|
|
|
|
$link = $localLinkTitle->getLocalURL();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-04-25 13:51:54 +00:00
|
|
|
|
else {
|
|
|
|
|
|
// concatenate all other pipes
|
2012-04-10 10:30:17 +00:00
|
|
|
|
$label .= '|' . $parameterMatch;
|
2011-04-25 13:51:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// remove the first pipe
|
|
|
|
|
|
$label = substr( $label, 1 );
|
2004-11-13 12:04:31 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2012-04-10 10:30:17 +00:00
|
|
|
|
$ig->add( $title, $label, $alt ,$link);
|
2004-11-13 12:04:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $ig->toHTML();
|
|
|
|
|
|
}
|
2005-04-27 07:48:14 +00:00
|
|
|
|
|
2011-08-05 00:33:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param $handler
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
function getImageParams( $handler ) {
|
|
|
|
|
|
if ( $handler ) {
|
|
|
|
|
|
$handlerClass = get_class( $handler );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$handlerClass = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( !isset( $this->mImageParams[$handlerClass] ) ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Initialise static lists
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
static $internalParamNames = array(
|
|
|
|
|
|
'horizAlign' => array( 'left', 'right', 'center', 'none' ),
|
2008-04-14 07:45:50 +00:00
|
|
|
|
'vertAlign' => array( 'baseline', 'sub', 'super', 'top', 'text-top', 'middle',
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
'bottom', 'text-bottom' ),
|
2008-04-14 07:45:50 +00:00
|
|
|
|
'frame' => array( 'thumbnail', 'manualthumb', 'framed', 'frameless',
|
2008-10-08 16:33:36 +00:00
|
|
|
|
'upright', 'border', 'link', 'alt' ),
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
static $internalParamMap;
|
|
|
|
|
|
if ( !$internalParamMap ) {
|
|
|
|
|
|
$internalParamMap = array();
|
|
|
|
|
|
foreach ( $internalParamNames as $type => $names ) {
|
|
|
|
|
|
foreach ( $names as $name ) {
|
|
|
|
|
|
$magicName = str_replace( '-', '_', "img_$name" );
|
|
|
|
|
|
$internalParamMap[$magicName] = array( $type, $name );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Add handler params
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
$paramMap = $internalParamMap;
|
|
|
|
|
|
if ( $handler ) {
|
|
|
|
|
|
$handlerParamMap = $handler->getParamMap();
|
|
|
|
|
|
foreach ( $handlerParamMap as $magic => $paramName ) {
|
|
|
|
|
|
$paramMap[$magic] = array( 'handler', $paramName );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$this->mImageParams[$handlerClass] = $paramMap;
|
|
|
|
|
|
$this->mImageParamsMagicArray[$handlerClass] = new MagicWordArray( array_keys( $paramMap ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
return array( $this->mImageParams[$handlerClass], $this->mImageParamsMagicArray[$handlerClass] );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-27 07:48:14 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Parse image options text and use it to make an image
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $title Title
|
|
|
|
|
|
* @param $options String
|
2012-02-09 17:41:50 +00:00
|
|
|
|
* @param $holders LinkHolderArray|bool
|
2011-03-23 03:13:37 +00:00
|
|
|
|
* @return string HTML
|
2005-04-27 07:48:14 +00:00
|
|
|
|
*/
|
2008-08-26 14:37:15 +00:00
|
|
|
|
function makeImage( $title, $options, $holders = false ) {
|
2005-04-27 07:48:14 +00:00
|
|
|
|
# Check if the options text is of the form "options|alt text"
|
|
|
|
|
|
# Options are:
|
2008-10-08 16:33:36 +00:00
|
|
|
|
# * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
|
|
|
|
|
|
# * left no resizing, just left align. label is used for alt= only
|
|
|
|
|
|
# * right same, but right aligned
|
|
|
|
|
|
# * none same, but not aligned
|
|
|
|
|
|
# * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
|
|
|
|
|
|
# * center center the image
|
2009-07-03 05:13:58 +00:00
|
|
|
|
# * frame Keep original image size, no magnify-button.
|
|
|
|
|
|
# * framed Same as "frame"
|
2008-10-08 16:33:36 +00:00
|
|
|
|
# * frameless like 'thumb' but without a frame. Keeps user preferences for width
|
|
|
|
|
|
# * upright reduce width for upright images, rounded to full __0 px
|
|
|
|
|
|
# * border draw a 1px border around the image
|
|
|
|
|
|
# * alt Text for HTML alt attribute (defaults to empty)
|
2010-01-07 04:13:14 +00:00
|
|
|
|
# * link Set the target of the image link. Can be external, interwiki, or local
|
2007-02-02 00:44:42 +00:00
|
|
|
|
# vertical-align values (no % or length right now):
|
|
|
|
|
|
# * baseline
|
|
|
|
|
|
# * sub
|
|
|
|
|
|
# * super
|
|
|
|
|
|
# * top
|
|
|
|
|
|
# * text-top
|
|
|
|
|
|
# * middle
|
|
|
|
|
|
# * bottom
|
|
|
|
|
|
# * text-bottom
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$parts = StringUtils::explode( "|", $options );
|
2005-04-27 07:48:14 +00:00
|
|
|
|
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
# Give extensions a chance to select the file revision for us
|
2011-09-06 18:11:53 +00:00
|
|
|
|
$options = array();
|
|
|
|
|
|
$descQuery = false;
|
2011-03-24 01:44:48 +00:00
|
|
|
|
wfRunHooks( 'BeforeParserFetchFileAndTitle',
|
2011-09-06 18:11:53 +00:00
|
|
|
|
array( $this, $title, &$options, &$descQuery ) );
|
2011-03-23 17:35:40 +00:00
|
|
|
|
# Fetch and register the file (file title may be different via hooks)
|
2011-09-06 18:11:53 +00:00
|
|
|
|
list( $file, $title ) = $this->fetchFileAndTitle( $title, $options );
|
2011-03-24 01:44:48 +00:00
|
|
|
|
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
# Get parameter map
|
|
|
|
|
|
$handler = $file ? $file->getHandler() : false;
|
2005-04-27 07:48:14 +00:00
|
|
|
|
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
list( $paramMap, $mwArray ) = $this->getImageParams( $handler );
|
|
|
|
|
|
|
2011-04-20 19:43:47 +00:00
|
|
|
|
if ( !$file ) {
|
|
|
|
|
|
$this->addTrackingCategory( 'broken-file-category' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
# Process the input parameters
|
2008-08-08 21:50:37 +00:00
|
|
|
|
$caption = '';
|
2008-04-14 07:45:50 +00:00
|
|
|
|
$params = array( 'frame' => array(), 'handler' => array(),
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
'horizAlign' => array(), 'vertAlign' => array() );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
foreach ( $parts as $part ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
$part = trim( $part );
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
list( $magicName, $value ) = $mwArray->matchVariableStartToEnd( $part );
|
2008-03-25 05:17:42 +00:00
|
|
|
|
$validated = false;
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( isset( $paramMap[$magicName] ) ) {
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
list( $type, $paramName ) = $paramMap[$magicName];
|
2008-03-25 05:17:42 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Special case; width and height come in one variable together
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $type === 'handler' && $paramName === 'width' ) {
|
2012-07-25 15:31:47 +00:00
|
|
|
|
$parsedWidthParam = $this->parseWidthParam( $value );
|
|
|
|
|
|
if( isset( $parsedWidthParam['width'] ) ) {
|
|
|
|
|
|
$width = $parsedWidthParam['width'];
|
2008-03-25 08:23:10 +00:00
|
|
|
|
if ( $handler->validateParam( 'width', $width ) ) {
|
|
|
|
|
|
$params[$type]['width'] = $width;
|
|
|
|
|
|
$validated = true;
|
|
|
|
|
|
}
|
2012-07-25 15:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
if( isset( $parsedWidthParam['height'] ) ) {
|
|
|
|
|
|
$height = $parsedWidthParam['height'];
|
2008-03-25 08:23:10 +00:00
|
|
|
|
if ( $handler->validateParam( 'height', $height ) ) {
|
|
|
|
|
|
$params[$type]['height'] = $height;
|
|
|
|
|
|
$validated = true;
|
|
|
|
|
|
}
|
2012-07-25 15:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
# else no validation -- bug 13436
|
2008-03-25 05:17:42 +00:00
|
|
|
|
} else {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( $type === 'handler' ) {
|
2008-03-25 05:17:42 +00:00
|
|
|
|
# Validate handler parameter
|
|
|
|
|
|
$validated = $handler->validateParam( $paramName, $value );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# Validate internal parameters
|
2008-04-07 23:30:45 +00:00
|
|
|
|
switch( $paramName ) {
|
2008-10-08 16:33:36 +00:00
|
|
|
|
case 'manualthumb':
|
|
|
|
|
|
case 'alt':
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# @todo FIXME: Possibly check validity here for
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# manualthumb? downstream behavior seems odd with
|
|
|
|
|
|
# missing manual thumbs.
|
2008-04-07 23:30:45 +00:00
|
|
|
|
$validated = true;
|
2008-10-15 21:20:13 +00:00
|
|
|
|
$value = $this->stripAltText( $value, $holders );
|
2008-04-07 23:30:45 +00:00
|
|
|
|
break;
|
2008-10-07 00:31:26 +00:00
|
|
|
|
case 'link':
|
2008-10-06 05:55:27 +00:00
|
|
|
|
$chars = self::EXT_LINK_URL_CLASS;
|
|
|
|
|
|
$prots = $this->mUrlProtocols;
|
|
|
|
|
|
if ( $value === '' ) {
|
|
|
|
|
|
$paramName = 'no-link';
|
|
|
|
|
|
$value = true;
|
|
|
|
|
|
$validated = true;
|
|
|
|
|
|
} elseif ( preg_match( "/^$prots/", $value ) ) {
|
2011-07-27 18:03:01 +00:00
|
|
|
|
if ( preg_match( "/^($prots)$chars+$/u", $value, $m ) ) {
|
2008-10-07 00:31:26 +00:00
|
|
|
|
$paramName = 'link-url';
|
2008-10-06 05:55:27 +00:00
|
|
|
|
$this->mOutput->addExternalLink( $value );
|
2010-11-09 12:25:57 +00:00
|
|
|
|
if ( $this->mOptions->getExternalLinkTarget() ) {
|
|
|
|
|
|
$params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget();
|
|
|
|
|
|
}
|
2008-10-06 05:55:27 +00:00
|
|
|
|
$validated = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2008-10-07 00:31:26 +00:00
|
|
|
|
$linkTitle = Title::newFromText( $value );
|
|
|
|
|
|
if ( $linkTitle ) {
|
|
|
|
|
|
$paramName = 'link-title';
|
|
|
|
|
|
$value = $linkTitle;
|
|
|
|
|
|
$this->mOutput->addLink( $linkTitle );
|
2008-10-06 05:55:27 +00:00
|
|
|
|
$validated = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2008-04-07 23:30:45 +00:00
|
|
|
|
default:
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Most other things appear to be empty or numeric...
|
2008-04-07 23:30:45 +00:00
|
|
|
|
$validated = ( $value === false || is_numeric( trim( $value ) ) );
|
|
|
|
|
|
}
|
2008-03-25 05:17:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( $validated ) {
|
|
|
|
|
|
$params[$type][$paramName] = $value;
|
2007-08-25 15:49:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2008-03-25 05:17:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( !$validated ) {
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
$caption = $part;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Process alignment parameters
|
|
|
|
|
|
if ( $params['horizAlign'] ) {
|
|
|
|
|
|
$params['frame']['align'] = key( $params['horizAlign'] );
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $params['vertAlign'] ) {
|
|
|
|
|
|
$params['frame']['valign'] = key( $params['vertAlign'] );
|
|
|
|
|
|
}
|
2008-08-08 21:50:37 +00:00
|
|
|
|
|
2008-10-08 16:33:36 +00:00
|
|
|
|
$params['frame']['caption'] = $caption;
|
|
|
|
|
|
|
2009-07-03 05:13:58 +00:00
|
|
|
|
# Will the image be presented in a frame, with the caption below?
|
|
|
|
|
|
$imageIsFramed = isset( $params['frame']['frame'] ) ||
|
2010-12-11 03:52:35 +00:00
|
|
|
|
isset( $params['frame']['framed'] ) ||
|
|
|
|
|
|
isset( $params['frame']['thumbnail'] ) ||
|
|
|
|
|
|
isset( $params['frame']['manualthumb'] );
|
2008-10-08 16:33:36 +00:00
|
|
|
|
|
|
|
|
|
|
# In the old days, [[Image:Foo|text...]] would set alt text. Later it
|
|
|
|
|
|
# came to also set the caption, ordinary text after the image -- which
|
|
|
|
|
|
# makes no sense, because that just repeats the text multiple times in
|
|
|
|
|
|
# screen readers. It *also* came to set the title attribute.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2008-10-08 16:33:36 +00:00
|
|
|
|
# Now that we have an alt attribute, we should not set the alt text to
|
|
|
|
|
|
# equal the caption: that's worse than useless, it just repeats the
|
|
|
|
|
|
# text. This is the framed/thumbnail case. If there's no caption, we
|
|
|
|
|
|
# use the unnamed parameter for alt text as well, just for the time be-
|
|
|
|
|
|
# ing, if the unnamed param is set and the alt param is not.
|
2010-05-15 10:35:54 +00:00
|
|
|
|
#
|
2008-10-08 16:33:36 +00:00
|
|
|
|
# For the future, we need to figure out if we want to tweak this more,
|
|
|
|
|
|
# e.g., introducing a title= parameter for the title; ignoring the un-
|
|
|
|
|
|
# named parameter entirely for images without a caption; adding an ex-
|
|
|
|
|
|
# plicit caption= parameter and preserving the old magic unnamed para-
|
|
|
|
|
|
# meter for BC; ...
|
2009-07-03 05:13:58 +00:00
|
|
|
|
if ( $imageIsFramed ) { # Framed image
|
|
|
|
|
|
if ( $caption === '' && !isset( $params['frame']['alt'] ) ) {
|
|
|
|
|
|
# No caption or alt text, add the filename as the alt text so
|
|
|
|
|
|
# that screen readers at least get some description of the image
|
|
|
|
|
|
$params['frame']['alt'] = $title->getText();
|
|
|
|
|
|
}
|
|
|
|
|
|
# Do not set $params['frame']['title'] because tooltips don't make sense
|
|
|
|
|
|
# for framed images
|
|
|
|
|
|
} else { # Inline image
|
|
|
|
|
|
if ( !isset( $params['frame']['alt'] ) ) {
|
|
|
|
|
|
# No alt text, use the "caption" for the alt text
|
|
|
|
|
|
if ( $caption !== '') {
|
|
|
|
|
|
$params['frame']['alt'] = $this->stripAltText( $caption, $holders );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# No caption, fall back to using the filename for the
|
|
|
|
|
|
# alt text
|
|
|
|
|
|
$params['frame']['alt'] = $title->getText();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
# Use the "caption" for the tooltip text
|
|
|
|
|
|
$params['frame']['title'] = $this->stripAltText( $caption, $holders );
|
2008-10-08 16:33:36 +00:00
|
|
|
|
}
|
2007-05-31 16:01:26 +00:00
|
|
|
|
|
2012-03-09 18:32:03 +00:00
|
|
|
|
wfRunHooks( 'ParserMakeImageParams', array( $title, $file, &$params, $this ) );
|
2008-02-21 10:25:44 +00:00
|
|
|
|
|
2005-04-27 07:48:14 +00:00
|
|
|
|
# Linker does the rest
|
2011-09-06 18:11:53 +00:00
|
|
|
|
$time = isset( $options['time'] ) ? $options['time'] : false;
|
2011-04-03 11:44:11 +00:00
|
|
|
|
$ret = Linker::makeImageLink2( $title, $file, $params['frame'], $params['handler'],
|
2011-03-23 03:13:37 +00:00
|
|
|
|
$time, $descQuery, $this->mOptions->getThumbSize() );
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
|
|
|
|
|
|
# Give the handler a chance to modify the parser object
|
|
|
|
|
|
if ( $handler ) {
|
|
|
|
|
|
$handler->parserTransformHook( $this, $file );
|
2007-05-31 16:01:26 +00:00
|
|
|
|
}
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
|
|
|
|
|
|
return $ret;
|
2005-04-27 07:48:14 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2011-05-26 19:52:56 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param $caption
|
|
|
|
|
|
* @param $holders LinkHolderArray
|
|
|
|
|
|
* @return mixed|String
|
|
|
|
|
|
*/
|
2008-10-15 21:20:13 +00:00
|
|
|
|
protected function stripAltText( $caption, $holders ) {
|
|
|
|
|
|
# Strip bad stuff out of the title (tooltip). We can't just use
|
|
|
|
|
|
# replaceLinkHoldersText() here, because if this function is called
|
|
|
|
|
|
# from replaceInternalLinks2(), mLinkHolders won't be up-to-date.
|
|
|
|
|
|
if ( $holders ) {
|
|
|
|
|
|
$tooltip = $holders->replaceText( $caption );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$tooltip = $this->replaceLinkHoldersText( $caption );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# make sure there are no placeholders in thumbnail attributes
|
|
|
|
|
|
# that are later expanded to html- so expand them now and
|
|
|
|
|
|
# remove the tags
|
|
|
|
|
|
$tooltip = $this->mStripState->unstripBoth( $tooltip );
|
|
|
|
|
|
$tooltip = Sanitizer::stripAllTags( $tooltip );
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2008-10-15 21:20:13 +00:00
|
|
|
|
return $tooltip;
|
|
|
|
|
|
}
|
2005-08-07 12:09:46 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2006-01-07 13:09:30 +00:00
|
|
|
|
* Set a flag in the output object indicating that the content is dynamic and
|
2005-08-07 12:09:46 +00:00
|
|
|
|
* shouldn't be cached.
|
|
|
|
|
|
*/
|
|
|
|
|
|
function disableCache() {
|
2006-05-13 17:40:59 +00:00
|
|
|
|
wfDebug( "Parser output marked as uncacheable.\n" );
|
2011-12-15 07:17:29 +00:00
|
|
|
|
if ( !$this->mOutput ) {
|
|
|
|
|
|
throw new MWException( __METHOD__ .
|
|
|
|
|
|
" can only be called when actually parsing something" );
|
|
|
|
|
|
}
|
2010-06-01 14:28:51 +00:00
|
|
|
|
$this->mOutput->setCacheTime( -1 ); // old style, for compatibility
|
2010-06-01 19:40:35 +00:00
|
|
|
|
$this->mOutput->updateCacheExpiry( 0 ); // new style, for consistency
|
2005-08-07 12:09:46 +00:00
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2010-06-10 21:05:58 +00:00
|
|
|
|
/**
|
2005-08-23 21:49:48 +00:00
|
|
|
|
* Callback from the Sanitizer for expanding items found in HTML attribute
|
|
|
|
|
|
* values, so they can be safely tested and escaped.
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @param $frame PPFrame
|
|
|
|
|
|
* @return String
|
2005-08-23 21:49:48 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
function attributeStripCallback( &$text, $frame = false ) {
|
|
|
|
|
|
$text = $this->replaceVariables( $text, $frame );
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$text = $this->mStripState->unstripBoth( $text );
|
2005-08-29 23:34:37 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2010-06-10 21:05:58 +00:00
|
|
|
|
/**
|
2006-01-08 15:13:37 +00:00
|
|
|
|
* Accessor
|
2011-04-29 23:34:37 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return array
|
2006-01-08 15:13:37 +00:00
|
|
|
|
*/
|
2010-05-15 10:35:54 +00:00
|
|
|
|
function getTags() {
|
2012-01-04 21:30:06 +00:00
|
|
|
|
return array_merge( array_keys( $this->mTransparentTagHooks ), array_keys( $this->mTagHooks ), array_keys( $this->mFunctionTagHooks ) );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2006-06-06 00:51:34 +00:00
|
|
|
|
|
2011-02-23 06:58:15 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Replace transparent tags in $text with the values given by the callbacks.
|
|
|
|
|
|
*
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* Transparent tag hooks are like regular XML-style tag hooks, except they
|
2011-02-23 06:58:15 +00:00
|
|
|
|
* operate late in the transformation sequence, on HTML instead of wikitext.
|
2011-07-24 21:36:04 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2011-02-23 06:58:15 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function replaceTransparentTags( $text ) {
|
|
|
|
|
|
$matches = array();
|
|
|
|
|
|
$elements = array_keys( $this->mTransparentTagHooks );
|
2011-05-01 23:59:41 +00:00
|
|
|
|
$text = self::extractTagsAndParams( $elements, $text, $matches, $this->mUniqPrefix );
|
2011-06-05 19:37:08 +00:00
|
|
|
|
$replacements = array();
|
2011-02-23 06:58:15 +00:00
|
|
|
|
|
|
|
|
|
|
foreach ( $matches as $marker => $data ) {
|
|
|
|
|
|
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 ) );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$output = $tag;
|
|
|
|
|
|
}
|
2011-06-05 19:37:08 +00:00
|
|
|
|
$replacements[$marker] = $output;
|
2011-02-23 06:58:15 +00:00
|
|
|
|
}
|
2011-06-05 19:37:08 +00:00
|
|
|
|
return strtr( $text, $replacements );
|
2011-02-23 06:58:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-06-06 00:51:34 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Break wikitext input into sections, and either pull or replace
|
|
|
|
|
|
* some particular section's text.
|
|
|
|
|
|
*
|
|
|
|
|
|
* External callers should use the getSection and replaceSection methods.
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String: Page wikitext
|
|
|
|
|
|
* @param $section String: a section identifier string of the form:
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* "<flag1> - <flag2> - ... - <section number>"
|
2008-01-05 12:39:12 +00:00
|
|
|
|
*
|
|
|
|
|
|
* Currently the only recognised flag is "T", which means the target section number
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* was derived during a template inclusion parse, in other words this is a template
|
|
|
|
|
|
* section edit link. If no flags are given, it was an ordinary section edit link.
|
|
|
|
|
|
* This flag is required to avoid a section numbering mismatch when a section is
|
2012-07-10 12:48:06 +00:00
|
|
|
|
* enclosed by "<includeonly>" (bug 6563).
|
2008-01-05 12:39:12 +00:00
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* The section number 0 pulls the text before the first heading; other numbers will
|
|
|
|
|
|
* pull the given section along with its lower-level subsections. If the section is
|
2008-01-05 12:39:12 +00:00
|
|
|
|
* not found, $mode=get will return $newtext, and $mode=replace will return $text.
|
|
|
|
|
|
*
|
2011-09-05 06:56:08 +00:00
|
|
|
|
* Section 0 is always considered to exist, even if it only contains the empty
|
2011-09-14 15:07:20 +00:00
|
|
|
|
* string. If $text is the empty string and section 0 is replaced, $newText is
|
2011-09-05 06:56:08 +00:00
|
|
|
|
* returned.
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $mode String: one of "get" or "replace"
|
|
|
|
|
|
* @param $newText String: replacement text for section data.
|
|
|
|
|
|
* @return String: for "get", the extracted section text.
|
|
|
|
|
|
* for "replace", the whole page with the section replaced.
|
2006-06-06 00:51:34 +00:00
|
|
|
|
*/
|
2007-11-20 10:55:08 +00:00
|
|
|
|
private function extractSections( $text, $section, $mode, $newText='' ) {
|
2011-01-23 16:07:13 +00:00
|
|
|
|
global $wgTitle; # not generally used but removes an ugly failure mode
|
2011-02-22 15:05:08 +00:00
|
|
|
|
$this->startParse( $wgTitle, new ParserOptions, self::OT_PLAIN, true );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$outText = '';
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$frame = $this->getPreprocessor()->newFrame();
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Process section extraction flags
|
2008-01-05 12:39:12 +00:00
|
|
|
|
$flags = 0;
|
|
|
|
|
|
$sectionParts = explode( '-', $section );
|
|
|
|
|
|
$sectionIndex = array_pop( $sectionParts );
|
|
|
|
|
|
foreach ( $sectionParts as $part ) {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( $part === 'T' ) {
|
2008-01-05 12:39:12 +00:00
|
|
|
|
$flags |= self::PTD_FOR_INCLUSION;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-09-05 06:56:08 +00:00
|
|
|
|
|
|
|
|
|
|
# Check for empty input
|
|
|
|
|
|
if ( strval( $text ) === '' ) {
|
|
|
|
|
|
# Only sections 0 and T-0 exist in an empty document
|
|
|
|
|
|
if ( $sectionIndex == 0 ) {
|
|
|
|
|
|
if ( $mode === 'get' ) {
|
|
|
|
|
|
return '';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return $newText;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if ( $mode === 'get' ) {
|
|
|
|
|
|
return $newText;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Preprocess the text
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$root = $this->preprocessToDom( $text, $flags );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# <h> nodes indicate section breaks
|
|
|
|
|
|
# They can only occur at the top level, so we can find them by iterating the root's children
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$node = $root->getFirstChild();
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Find the target section
|
2008-01-05 12:39:12 +00:00
|
|
|
|
if ( $sectionIndex == 0 ) {
|
2011-03-21 15:18:11 +00:00
|
|
|
|
# Section zero doesn't nest, level=big
|
|
|
|
|
|
$targetLevel = 1000;
|
2007-11-20 10:55:08 +00:00
|
|
|
|
} else {
|
2010-06-10 21:05:58 +00:00
|
|
|
|
while ( $node ) {
|
|
|
|
|
|
if ( $node->getName() === 'h' ) {
|
|
|
|
|
|
$bits = $node->splitHeading();
|
2008-02-01 01:35:55 +00:00
|
|
|
|
if ( $bits['i'] == $sectionIndex ) {
|
2010-06-10 21:05:58 +00:00
|
|
|
|
$targetLevel = $bits['level'];
|
2007-11-20 10:55:08 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( $mode === 'replace' ) {
|
2007-12-01 07:13:31 +00:00
|
|
|
|
$outText .= $frame->expand( $node, PPFrame::RECOVER_ORIG );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$node = $node->getNextSibling();
|
2006-06-06 00:51:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
if ( !$node ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Not found
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( $mode === 'get' ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
return $newText;
|
2006-06-06 00:51:34 +00:00
|
|
|
|
} else {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
return $text;
|
2006-06-06 00:51:34 +00:00
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Find the end of the section, including nested sections
|
2007-11-20 10:55:08 +00:00
|
|
|
|
do {
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( $node->getName() === 'h' ) {
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$bits = $node->splitHeading();
|
|
|
|
|
|
$curLevel = $bits['level'];
|
2010-01-27 02:41:22 +00:00
|
|
|
|
if ( $bits['i'] != $sectionIndex && $curLevel <= $targetLevel ) {
|
2007-11-20 10:55:08 +00:00
|
|
|
|
break;
|
2006-06-06 00:51:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( $mode === 'get' ) {
|
2007-12-01 07:13:31 +00:00
|
|
|
|
$outText .= $frame->expand( $node, PPFrame::RECOVER_ORIG );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$node = $node->getNextSibling();
|
2007-11-20 10:55:08 +00:00
|
|
|
|
} while ( $node );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Write out the remainder (in replace mode only)
|
2008-08-26 14:37:15 +00:00
|
|
|
|
if ( $mode === 'replace' ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Output the replacement text
|
|
|
|
|
|
# Add two newlines on -- trailing whitespace in $newText is conventionally
|
|
|
|
|
|
# stripped by the editor, so we need both newlines to restore the paragraph gap
|
|
|
|
|
|
# Only add trailing whitespace if there is newText
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $newText != "" ) {
|
2009-02-01 18:58:18 +00:00
|
|
|
|
$outText .= $newText . "\n\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
while ( $node ) {
|
2007-12-01 07:13:31 +00:00
|
|
|
|
$outText .= $frame->expand( $node, PPFrame::RECOVER_ORIG );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
$node = $node->getNextSibling();
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
2006-06-06 00:51:34 +00:00
|
|
|
|
}
|
2007-03-14 18:20:21 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
if ( is_string( $outText ) ) {
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Re-insert stripped tags
|
2008-04-14 20:39:00 +00:00
|
|
|
|
$outText = rtrim( $this->mStripState->unstripBoth( $outText ) );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $outText;
|
2006-06-06 00:51:34 +00:00
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2006-06-06 00:51:34 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* This function returns the text of a section, specified by a number ($section).
|
|
|
|
|
|
* A section is text under a heading like == Heading == or \<h1\>Heading\</h1\>, or
|
|
|
|
|
|
* the first section before any such heading (section 0).
|
|
|
|
|
|
*
|
|
|
|
|
|
* If a section contains subsections, these are also returned.
|
|
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String: text to look in
|
|
|
|
|
|
* @param $section String: section identifier
|
|
|
|
|
|
* @param $deftext String: default to return if section is not found
|
2006-06-06 00:51:34 +00:00
|
|
|
|
* @return string text of the requested section
|
|
|
|
|
|
*/
|
2007-03-14 18:20:21 +00:00
|
|
|
|
public function getSection( $text, $section, $deftext='' ) {
|
|
|
|
|
|
return $this->extractSections( $text, $section, "get", $deftext );
|
2006-06-06 00:51:34 +00:00
|
|
|
|
}
|
2006-07-11 17:40:11 +00:00
|
|
|
|
|
2010-12-26 19:30:10 +00:00
|
|
|
|
/**
|
2011-02-19 19:18:02 +00:00
|
|
|
|
* This function returns $oldtext after the content of the section
|
2011-09-14 15:07:20 +00:00
|
|
|
|
* specified by $section has been replaced with $text. If the target
|
2011-09-05 06:56:08 +00:00
|
|
|
|
* section does not exist, $oldtext is returned unchanged.
|
2011-02-19 19:18:02 +00:00
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @param $oldtext String: former text of the article
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @param $section int section identifier
|
2010-12-26 19:30:10 +00:00
|
|
|
|
* @param $text String: replacing text
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return String: modified text
|
2010-12-26 19:30:10 +00:00
|
|
|
|
*/
|
2007-02-28 17:25:41 +00:00
|
|
|
|
public function replaceSection( $oldtext, $section, $text ) {
|
2006-06-06 00:51:34 +00:00
|
|
|
|
return $this->extractSections( $oldtext, $section, "replace", $text );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-06-10 21:05:58 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the ID of the revision we are parsing
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return Mixed: integer or null
|
|
|
|
|
|
*/
|
|
|
|
|
|
function getRevisionId() {
|
|
|
|
|
|
return $this->mRevisionId;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-12-10 18:17:20 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the revision object for $this->mRevisionId
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return Revision|null either a Revision object or null
|
2010-12-10 18:17:20 +00:00
|
|
|
|
*/
|
|
|
|
|
|
protected function getRevisionObject() {
|
2010-12-10 18:23:33 +00:00
|
|
|
|
if ( !is_null( $this->mRevisionObject ) ) {
|
2010-12-10 18:17:20 +00:00
|
|
|
|
return $this->mRevisionObject;
|
2010-12-10 18:23:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( is_null( $this->mRevisionId ) ) {
|
2010-12-10 18:17:20 +00:00
|
|
|
|
return null;
|
2010-12-10 18:23:33 +00:00
|
|
|
|
}
|
2010-12-10 18:17:20 +00:00
|
|
|
|
|
|
|
|
|
|
$this->mRevisionObject = Revision::newFromId( $this->mRevisionId );
|
|
|
|
|
|
return $this->mRevisionObject;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-11-21 09:53:45 +00:00
|
|
|
|
/**
|
2007-01-17 19:48:48 +00:00
|
|
|
|
* Get the timestamp associated with the current revision, adjusted for
|
2006-12-02 23:56:25 +00:00
|
|
|
|
* the default server-local timestamp
|
2006-11-21 09:53:45 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getRevisionTimestamp() {
|
|
|
|
|
|
if ( is_null( $this->mRevisionTimestamp ) ) {
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
2010-12-10 18:17:20 +00:00
|
|
|
|
|
2011-10-24 16:14:49 +00:00
|
|
|
|
global $wgContLang;
|
2010-12-10 18:17:20 +00:00
|
|
|
|
|
2011-10-24 16:14:49 +00:00
|
|
|
|
$revObject = $this->getRevisionObject();
|
|
|
|
|
|
$timestamp = $revObject ? $revObject->getTimestamp() : wfTimestampNow();
|
2010-12-10 18:17:20 +00:00
|
|
|
|
|
2011-10-24 16:14:49 +00:00
|
|
|
|
# The cryptic '' timezone parameter tells to use the site-default
|
|
|
|
|
|
# timezone offset instead of the user settings.
|
|
|
|
|
|
#
|
|
|
|
|
|
# Since this value will be saved into the parser cache, served
|
|
|
|
|
|
# to other users, and potentially even used inside links and such,
|
|
|
|
|
|
# it needs to be consistent for all visitors.
|
|
|
|
|
|
$this->mRevisionTimestamp = $wgContLang->userAdjust( $timestamp, '' );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-11-21 09:53:45 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $this->mRevisionTimestamp;
|
|
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2009-03-07 23:01:59 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the name of the user that edited the last revision
|
2010-06-10 21:05:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return String: user name
|
2009-03-07 23:01:59 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getRevisionUser() {
|
2010-12-10 18:17:20 +00:00
|
|
|
|
if( is_null( $this->mRevisionUser ) ) {
|
|
|
|
|
|
$revObject = $this->getRevisionObject();
|
|
|
|
|
|
|
|
|
|
|
|
# if this template is subst: the revision id will be blank,
|
|
|
|
|
|
# so just use the current user's name
|
|
|
|
|
|
if( $revObject ) {
|
|
|
|
|
|
$this->mRevisionUser = $revObject->getUserText();
|
|
|
|
|
|
} elseif( $this->ot['wiki'] || $this->mOptions->getIsPreview() ) {
|
|
|
|
|
|
$this->mRevisionUser = $this->getUser()->getName();
|
|
|
|
|
|
}
|
2009-03-07 23:01:59 +00:00
|
|
|
|
}
|
2010-12-10 18:17:20 +00:00
|
|
|
|
return $this->mRevisionUser;
|
2009-03-07 23:01:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-12-29 10:39:35 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Mutator for $mDefaultSort
|
|
|
|
|
|
*
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @param $sort string New value
|
2006-12-29 10:39:35 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function setDefaultSort( $sort ) {
|
|
|
|
|
|
$this->mDefaultSort = $sort;
|
2010-07-10 11:46:47 +00:00
|
|
|
|
$this->mOutput->setProperty( 'defaultsort', $sort );
|
2006-12-29 10:39:35 +00:00
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-12-29 10:39:35 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Accessor for $mDefaultSort
|
2011-02-05 02:16:13 +00:00
|
|
|
|
* Will use the empty string if none is set.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This value is treated as a prefix, so the
|
|
|
|
|
|
* empty string is equivalent to sorting by
|
|
|
|
|
|
* page name.
|
2006-12-29 10:39:35 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getDefaultSort() {
|
2010-03-30 21:20:05 +00:00
|
|
|
|
if ( $this->mDefaultSort !== false ) {
|
2006-12-29 10:39:35 +00:00
|
|
|
|
return $this->mDefaultSort;
|
|
|
|
|
|
} else {
|
2011-02-05 02:16:13 +00:00
|
|
|
|
return '';
|
2006-12-29 10:39:35 +00:00
|
|
|
|
}
|
2007-09-08 02:08:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2008-11-02 14:21:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Accessor for $mDefaultSort
|
|
|
|
|
|
* Unlike getDefaultSort(), will return false if none is set
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string or false
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getCustomDefaultSort() {
|
|
|
|
|
|
return $this->mDefaultSort;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-09-08 02:08:08 +00:00
|
|
|
|
/**
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* Try to guess the section anchor name based on a wikitext fragment
|
|
|
|
|
|
* presumably extracted from a heading, for example "Header" from
|
2007-09-08 02:08:08 +00:00
|
|
|
|
* "== Header ==".
|
2011-07-24 21:36:04 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2007-09-08 02:08:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function guessSectionNameFromWikiText( $text ) {
|
2009-01-10 17:16:21 +00:00
|
|
|
|
# Strip out wikitext links(they break the anchor)
|
2007-09-08 02:08:08 +00:00
|
|
|
|
$text = $this->stripSectionName( $text );
|
2010-06-21 01:17:36 +00:00
|
|
|
|
$text = Sanitizer::normalizeSectionNameWhitespace( $text );
|
2010-06-20 23:43:39 +00:00
|
|
|
|
return '#' . Sanitizer::escapeId( $text, 'noninitial' );
|
2007-09-08 02:08:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-08-05 20:16:43 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Same as guessSectionNameFromWikiText(), but produces legacy anchors
|
|
|
|
|
|
* instead. For use in redirects, since IE6 interprets Redirect: headers
|
|
|
|
|
|
* as something other than UTF-8 (apparently?), resulting in breakage.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $text String: The section name
|
|
|
|
|
|
* @return string An anchor
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function guessLegacySectionNameFromWikiText( $text ) {
|
|
|
|
|
|
# Strip out wikitext links(they break the anchor)
|
|
|
|
|
|
$text = $this->stripSectionName( $text );
|
|
|
|
|
|
$text = Sanitizer::normalizeSectionNameWhitespace( $text );
|
|
|
|
|
|
return '#' . Sanitizer::escapeId( $text, array( 'noninitial', 'legacy' ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-09-08 02:08:08 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Strips a text string of wikitext for use in a section anchor
|
2008-04-14 07:45:50 +00:00
|
|
|
|
*
|
2007-09-08 02:08:08 +00:00
|
|
|
|
* Accepts a text string and then removes all wikitext from the
|
|
|
|
|
|
* string and leaves only the resultant text (i.e. the result of
|
|
|
|
|
|
* [[User:WikiSysop|Sysop]] would be "Sysop" and the result of
|
|
|
|
|
|
* [[User:WikiSysop]] would be "User:WikiSysop") - this is intended
|
|
|
|
|
|
* to create valid section anchors by mimicing the output of the
|
|
|
|
|
|
* parser when headings are parsed.
|
2008-04-14 07:45:50 +00:00
|
|
|
|
*
|
2010-06-10 21:05:58 +00:00
|
|
|
|
* @param $text String: text string to be stripped of wikitext
|
2007-09-08 02:08:08 +00:00
|
|
|
|
* for use in a Section anchor
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @return string Filtered text string
|
2007-09-08 02:08:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function stripSectionName( $text ) {
|
|
|
|
|
|
# Strip internal link markup
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$text = preg_replace( '/\[\[:?([^[|]+)\|([^[]+)\]\]/', '$2', $text );
|
|
|
|
|
|
$text = preg_replace( '/\[\[:?([^[]+)\|?\]\]/', '$1', $text );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2011-05-17 22:03:20 +00:00
|
|
|
|
# Strip external link markup
|
|
|
|
|
|
# @todo FIXME: Not tolerant to blank link text
|
2007-09-08 02:08:08 +00:00
|
|
|
|
# I.E. [http://www.mediawiki.org] will render as [1] or something depending
|
|
|
|
|
|
# on how many empty links there are on the page - need to figure that out.
|
2012-04-14 17:07:51 +00:00
|
|
|
|
$text = preg_replace( '/\[(?:' . $this->mUrlProtocols . ')([^ ]+?) ([^[]+)\]/', '$2', $text );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-09-08 02:08:08 +00:00
|
|
|
|
# Parse wikitext quotes (italics & bold)
|
2010-03-30 21:20:05 +00:00
|
|
|
|
$text = $this->doQuotes( $text );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-09-08 02:08:08 +00:00
|
|
|
|
# Strip HTML tags
|
|
|
|
|
|
$text = StringUtils::delimiterReplace( '<', '>', '', $text );
|
|
|
|
|
|
return $text;
|
2006-12-29 10:39:35 +00:00
|
|
|
|
}
|
2007-11-20 10:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* strip/replaceVariables/unstrip for preprocessor regression testing
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $text string
|
|
|
|
|
|
* @param $title Title
|
|
|
|
|
|
* @param $options ParserOptions
|
|
|
|
|
|
* @param $outputType int
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return string
|
2007-11-20 10:55:08 +00:00
|
|
|
|
*/
|
2011-06-14 15:08:52 +00:00
|
|
|
|
function testSrvus( $text, Title $title, ParserOptions $options, $outputType = self::OT_HTML ) {
|
2011-02-22 15:05:08 +00:00
|
|
|
|
$this->startParse( $title, $options, $outputType, true );
|
2011-01-23 16:07:13 +00:00
|
|
|
|
|
2007-11-20 10:55:08 +00:00
|
|
|
|
$text = $this->replaceVariables( $text );
|
|
|
|
|
|
$text = $this->mStripState->unstripBoth( $text );
|
2007-12-17 15:07:25 +00:00
|
|
|
|
$text = Sanitizer::removeHTMLtags( $text );
|
2007-11-20 10:55:08 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2008-01-21 16:36:08 +00:00
|
|
|
|
|
2011-08-05 00:33:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param $text string
|
|
|
|
|
|
* @param $title Title
|
|
|
|
|
|
* @param $options ParserOptions
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-06-14 15:08:52 +00:00
|
|
|
|
function testPst( $text, Title $title, ParserOptions $options ) {
|
2011-05-30 16:10:23 +00:00
|
|
|
|
return $this->preSaveTransform( $text, $title, $options->getUser(), $options );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-08-05 00:33:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param $text
|
|
|
|
|
|
* @param $title Title
|
|
|
|
|
|
* @param $options ParserOptions
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-06-14 15:08:52 +00:00
|
|
|
|
function testPreprocess( $text, Title $title, ParserOptions $options ) {
|
2008-01-22 10:47:44 +00:00
|
|
|
|
return $this->testSrvus( $text, $title, $options, self::OT_PREPROCESS );
|
2008-01-21 16:36:08 +00:00
|
|
|
|
}
|
2008-01-24 09:07:47 +00:00
|
|
|
|
|
2011-02-23 06:58:15 +00:00
|
|
|
|
/**
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* Call a callback function on all regions of the given text that are not
|
|
|
|
|
|
* inside strip markers, and replace those regions with the return value
|
2011-02-23 06:58:15 +00:00
|
|
|
|
* of the callback. For example, with input:
|
|
|
|
|
|
*
|
|
|
|
|
|
* aaa<MARKER>bbb
|
|
|
|
|
|
*
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* This will call the callback function twice, with 'aaa' and 'bbb'. Those
|
2011-02-23 06:58:15 +00:00
|
|
|
|
* two strings will be replaced with the value returned by the callback in
|
|
|
|
|
|
* each case.
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $s string
|
|
|
|
|
|
* @param $callback
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return string
|
2011-02-23 06:58:15 +00:00
|
|
|
|
*/
|
2008-01-24 09:07:47 +00:00
|
|
|
|
function markerSkipCallback( $s, $callback ) {
|
|
|
|
|
|
$i = 0;
|
|
|
|
|
|
$out = '';
|
|
|
|
|
|
while ( $i < strlen( $s ) ) {
|
|
|
|
|
|
$markerStart = strpos( $s, $this->mUniqPrefix, $i );
|
|
|
|
|
|
if ( $markerStart === false ) {
|
|
|
|
|
|
$out .= call_user_func( $callback, substr( $s, $i ) );
|
|
|
|
|
|
break;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$out .= call_user_func( $callback, substr( $s, $i, $markerStart - $i ) );
|
2008-03-27 00:00:25 +00:00
|
|
|
|
$markerEnd = strpos( $s, self::MARKER_SUFFIX, $markerStart );
|
2008-01-24 09:07:47 +00:00
|
|
|
|
if ( $markerEnd === false ) {
|
|
|
|
|
|
$out .= substr( $s, $markerStart );
|
|
|
|
|
|
break;
|
|
|
|
|
|
} else {
|
2008-03-27 00:00:25 +00:00
|
|
|
|
$markerEnd += strlen( self::MARKER_SUFFIX );
|
2008-01-24 09:07:47 +00:00
|
|
|
|
$out .= substr( $s, $markerStart, $markerEnd - $markerStart );
|
|
|
|
|
|
$i = $markerEnd;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return $out;
|
|
|
|
|
|
}
|
2009-02-03 04:58:08 +00:00
|
|
|
|
|
2012-03-20 04:39:09 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Remove any strip markers found in the given text.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $text Input string
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
function killMarkers( $text ) {
|
|
|
|
|
|
return $this->mStripState->killMarkers( $text );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-02-23 06:58:15 +00:00
|
|
|
|
/**
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* Save the parser state required to convert the given half-parsed text to
|
|
|
|
|
|
* HTML. "Half-parsed" in this context means the output of
|
|
|
|
|
|
* recursiveTagParse() or internalParse(). This output has strip markers
|
|
|
|
|
|
* from replaceVariables (extensionSubstitution() etc.), and link
|
|
|
|
|
|
* placeholders from replaceLinkHolders().
|
2011-02-23 06:58:15 +00:00
|
|
|
|
*
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* Returns an array which can be serialized and stored persistently. This
|
|
|
|
|
|
* array can later be loaded into another parser instance with
|
|
|
|
|
|
* unserializeHalfParsedText(). The text can then be safely incorporated into
|
2011-02-23 06:58:15 +00:00
|
|
|
|
* the return value of a parser hook.
|
2011-05-01 23:54:41 +00:00
|
|
|
|
*
|
2011-08-05 00:33:03 +00:00
|
|
|
|
* @param $text string
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @return array
|
2011-02-23 06:58:15 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function serializeHalfParsedText( $text ) {
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
$data = array(
|
|
|
|
|
|
'text' => $text,
|
|
|
|
|
|
'version' => self::HALF_PARSED_VERSION,
|
|
|
|
|
|
'stripState' => $this->mStripState->getSubState( $text ),
|
|
|
|
|
|
'linkHolders' => $this->mLinkHolders->getSubArray( $text )
|
|
|
|
|
|
);
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2009-02-03 04:58:08 +00:00
|
|
|
|
return $data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
/**
|
2011-02-23 06:58:15 +00:00
|
|
|
|
* Load the parser state given in the $data array, which is assumed to
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* have been generated by serializeHalfParsedText(). The text contents is
|
|
|
|
|
|
* extracted from the array, and its markers are transformed into markers
|
|
|
|
|
|
* appropriate for the current Parser instance. This transformed text is
|
2011-02-23 06:58:15 +00:00
|
|
|
|
* returned, and can be safely included in the return value of a parser
|
|
|
|
|
|
* hook.
|
|
|
|
|
|
*
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* If the $data array has been stored persistently, the caller should first
|
|
|
|
|
|
* check whether it is still valid, by calling isValidHalfParsedText().
|
2011-02-23 06:58:15 +00:00
|
|
|
|
*
|
2012-02-09 19:29:36 +00:00
|
|
|
|
* @param $data array Serialized data
|
2010-03-30 21:53:56 +00:00
|
|
|
|
* @return String
|
|
|
|
|
|
*/
|
2011-02-23 06:58:15 +00:00
|
|
|
|
function unserializeHalfParsedText( $data ) {
|
|
|
|
|
|
if ( !isset( $data['version'] ) || $data['version'] != self::HALF_PARSED_VERSION ) {
|
|
|
|
|
|
throw new MWException( __METHOD__.': invalid version' );
|
2010-03-30 21:20:05 +00:00
|
|
|
|
}
|
2010-01-07 04:13:14 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# First, extract the strip state.
|
2011-02-23 06:58:15 +00:00
|
|
|
|
$texts = array( $data['text'] );
|
|
|
|
|
|
$texts = $this->mStripState->merge( $data['stripState'], $texts );
|
2009-02-03 04:58:08 +00:00
|
|
|
|
|
2011-02-23 06:58:15 +00:00
|
|
|
|
# Now renumber links
|
|
|
|
|
|
$texts = $this->mLinkHolders->mergeForeign( $data['linkHolders'], $texts );
|
2009-02-03 04:58:08 +00:00
|
|
|
|
|
2010-03-30 21:53:56 +00:00
|
|
|
|
# Should be good to go.
|
2011-02-23 06:58:15 +00:00
|
|
|
|
return $texts[0];
|
2006-06-16 13:58:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-02-23 06:58:15 +00:00
|
|
|
|
/**
|
2011-02-24 20:23:49 +00:00
|
|
|
|
* Returns true if the given array, presumed to be generated by
|
|
|
|
|
|
* serializeHalfParsedText(), is compatible with the current version of the
|
2011-02-23 06:58:15 +00:00
|
|
|
|
* parser.
|
|
|
|
|
|
*
|
2011-05-01 23:54:41 +00:00
|
|
|
|
* @param $data Array
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return bool
|
2011-02-23 06:58:15 +00:00
|
|
|
|
*/
|
2011-02-24 20:23:49 +00:00
|
|
|
|
function isValidHalfParsedText( $data ) {
|
2011-02-23 06:58:15 +00:00
|
|
|
|
return isset( $data['version'] ) && $data['version'] == self::HALF_PARSED_VERSION;
|
2008-01-17 04:02:57 +00:00
|
|
|
|
}
|
2012-07-25 15:31:47 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Parsed a width param of imagelink like 300px or 200x300px
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param $value String
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
* @since 1.20
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function parseWidthParam( $value ) {
|
|
|
|
|
|
$parsedWidthParam = array();
|
|
|
|
|
|
if( $value === '' ) {
|
|
|
|
|
|
return $parsedWidthParam;
|
|
|
|
|
|
}
|
|
|
|
|
|
$m = array();
|
|
|
|
|
|
# (bug 13500) In both cases (width/height and width only),
|
|
|
|
|
|
# permit trailing "px" for backward compatibility.
|
|
|
|
|
|
if ( preg_match( '/^([0-9]*)x([0-9]*)\s*(?:px)?\s*$/', $value, $m ) ) {
|
|
|
|
|
|
$width = intval( $m[1] );
|
|
|
|
|
|
$height = intval( $m[2] );
|
|
|
|
|
|
$parsedWidthParam['width'] = $width;
|
|
|
|
|
|
$parsedWidthParam['height'] = $height;
|
|
|
|
|
|
} elseif ( preg_match( '/^[0-9]*\s*(?:px)?\s*$/', $value ) ) {
|
|
|
|
|
|
$width = intval( $value );
|
|
|
|
|
|
$parsedWidthParam['width'] = $width;
|
|
|
|
|
|
}
|
|
|
|
|
|
return $parsedWidthParam;
|
|
|
|
|
|
}
|
2008-01-17 04:02:57 +00:00
|
|
|
|
}
|