Doing this allows skins to override doEditSectionLinks without poluting the parser cache or fragmenting the parser cache more.
As a side effect it eliminates the primary cause of user language based parser cache fragmentation.
Because this makes most old parser cache entries invalid $wgUseEditSectionTokens is provided so that large installations like Wikipedia can keep their old parser cache entries.
* Skin names are no longer created based on a ucfirst version of the key in $wgValidSkinNames but now
the value. This means for $wgValidSkinNames["monobook"] = "MonoBook"; the skin
loader will no longer try loading SkinMonobook and will instead load SkinMonoBook.
+* The parser now attempts to output markers for editsection tokens and defer the rendering
+ of them so skin and language specific markup does not need to be saved inside the parser cache
+ note that this changes the cache key making all old entries in the parser cache invalid you
+ can set $wgUseEditSectionTokens to false to disable this and keep your old parser cache entries.
+ Note that this feature should reduce parser cache fragmentation when enabled.
=== New features in 1.18 ===
* Added a special page, disabled by default, that allows users with the
*/
$wgTranscludeCacheExpiry = 3600;
+/**
+ * Output edit section links as tokens in the parser output for articles instead
+ * of directly as markup.
+ * This feature changes the default parser cache key so it's presented with a
+ * configuration option so that large installations with a large number of already
+ * existing parser cache keys can retain them.
+ * The purpose of this feature is to allow skins to customize the editsection
+ * links, however it has the side effect of also removing the most common use of
+ * the getUserLang parser option which causes cache fragmentation by user lang.
+ */
+$wgUseEditSectionTokens = true;
+
/** @} */ # end of parser settings }
/************************************************************************//**
} else {
$showEditLink = $this->mOptions->getEditSection();
}
+ if ( $showEditLink ) {
+ $editLinkAsToken = $this->mOptions->getEditSectionTokens();
+ if ( $editLinkAsToken ) {
+ $this->mOutput->setEditSectionTokens( "{$this->mUniqPrefix}-editsection-", self::MARKER_SUFFIX );
+ }
+ }
# 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
# give headline the correct <h#> tag
if ( $showEditLink && $sectionIndex !== false ) {
- if ( $isTemplate ) {
- # Put a T flag in the section identifier, to indicate to extractSections()
- # that sections inside <includeonly> should be counted.
- $editlink = $sk->doEditSectionLink( Title::newFromText( $titleText ), "T-$sectionIndex", null, $this->mOptions->getUserLang() );
+ if ( $editLinkAsToken ) {
+ // 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 );
+ } else {
+ $editlinkArgs = array( $this->mTitle->getPrefixedText(), $sectionIndex, $headlineHint );
+ }
+ // We use nearly the same structure as uniqPrefix and the marker stuffix (besides there being nothing random)
+ // However the this is output into the parser output itself not replaced early, so we hardcode this in case
+ // the constants change in a different version of MediaWiki, which would break this code.
+ $editlink = "{$this->mUniqPrefix}-editsection-" . serialize($editlinkArgs) . self::MARKER_SUFFIX;
} else {
- $editlink = $sk->doEditSectionLink( $this->mTitle, $sectionIndex, $headlineHint, $this->mOptions->getUserLang() );
+ // Output edit section links directly as markup like we used to
+ if ( $isTemplate ) {
+ # Put a T flag in the section identifier, to indicate to extractSections()
+ # that sections inside <includeonly> should be counted.
+ $editlink = $sk->doEditSectionLink( Title::newFromText( $titleText ), "T-$sectionIndex", null, $this->mOptions->getUserLang() );
+ } else {
+ $editlink = $sk->doEditSectionLink( $this->mTitle, $sectionIndex, $headlineHint, $this->mOptions->getUserLang() );
+ }
}
} else {
$editlink = '';
var $mSkin = null; # Reference to the preferred skin
var $mDateFormat = null; # Date format index
var $mEditSection = true; # Create "edit section" links
+ var $mEditSectionTokens = false; # Output replaceable tokens for editsections instead of markup
var $mAllowSpecialInclusion; # Allow inclusion of special pages
var $mTidy = false; # Ask for tidy cleanup
var $mInterfaceMessage = false; # Which lang to call for PLURAL and GRAMMAR
function getEnableImageWhitelist() { return $this->mEnableImageWhitelist; }
function getEditSection() { $this->optionUsed('editsection');
return $this->mEditSection; }
+ function getEditSectionTokens() { $this->optionUsed('editsectiontokens');
+ return $this->mEditSectionTokens; }
function getNumberHeadings() { $this->optionUsed('numberheadings');
return $this->mNumberHeadings; }
function getAllowSpecialInclusion() { return $this->mAllowSpecialInclusion; }
function setEnableImageWhitelist( $x ) { return wfSetVar( $this->mEnableImageWhitelist, $x ); }
function setDateFormat( $x ) { return wfSetVar( $this->mDateFormat, $x ); }
function setEditSection( $x ) { return wfSetVar( $this->mEditSection, $x ); }
+ function setEditSectionTokens( $x ) { return wfSetVar( $this->mEditSectionTokens, $x ); }
function setNumberHeadings( $x ) { return wfSetVar( $this->mNumberHeadings, $x ); }
function setAllowSpecialInclusion( $x ) { return wfSetVar( $this->mAllowSpecialInclusion, $x ); }
function setTidy( $x ) { return wfSetVar( $this->mTidy, $x); }
function initialiseFromUser( $userInput ) {
global $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages;
global $wgAllowExternalImagesFrom, $wgEnableImageWhitelist, $wgAllowSpecialInclusion, $wgMaxArticleSize;
- global $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth, $wgCleanSignatures;
+ global $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth, $wgCleanSignatures, $wgUseEditSectionTokens;
global $wgExternalLinkTarget, $wgLang;
wfProfileIn( __METHOD__ );
$this->mMaxTemplateDepth = $wgMaxTemplateDepth;
$this->mCleanSignatures = $wgCleanSignatures;
$this->mExternalLinkTarget = $wgExternalLinkTarget;
+ $this->mEditSectionTokens = $wgUseEditSectionTokens;
$this->mNumberHeadings = $user->getOption( 'numberheadings' );
$this->mMath = $user->getOption( 'math' );
if ( !$this->mEditSection && in_array( 'editsection', $forOptions ) )
$confstr .= '!edit=0';
+ if ( $this->mEditSectionTokens && in_array( 'editsectiontokens', $forOptions ) )
+ $confstr .= '!estok=1';
if ( $this->mIsPrintable && in_array( 'printable', $forOptions ) )
$confstr .= '!printable=1';
$mOutputHooks = array(), # Hook tags as per $wgParserOutputHooks
$mWarnings = array(), # Warning text to be returned to the user. Wikitext formatted, in the key only
$mSections = array(), # Table of contents
+ $mEditSectionTokens = false, # prefix/suffix markers if edit sections were output as tokens
$mProperties = array(), # Name/value pairs to be cached in the DB
$mTOCHTML = ''; # HTML of the TOC
private $mIndexPolicy = ''; # 'index' or 'noindex'? Any other value will result in no change.
$this->mTitleText = $titletext;
}
- function getText() { return $this->mText; }
+ function getText() {
+ if ( $this->mEditSectionTokens ) {
+ $editSectionTokens = $this->mEditSectionTokens;
+ return preg_replace_callback( "#{$editSectionTokens[0]}(.*?){$editSectionTokens[1]}#", array( &$this, 'replaceEditSectionLinksCallback' ), $this->mText );
+ }
+ return $this->mText;
+ }
+
+ /**
+ * callback used by getText to replace editsection tokens
+ * @private
+ */
+ function replaceEditSectionLinksCallback( $m ) {
+ global $wgUser, $wgLang;
+ $args = unserialize($m[1]);
+ $args[0] = Title::newFromText( $args[0] );
+ $args[] = $wgLang->getCode();
+ $skin = $wgUser->getSkin();
+ return call_user_func_array( array( $skin, 'doEditSectionLink' ), $args );
+ }
+
function &getLanguageLinks() { return $this->mLanguageLinks; }
function getInterwikiLinks() { return $this->mInterwikiLinks; }
function getCategoryLinks() { return array_keys( $this->mCategories ); }
function &getCategories() { return $this->mCategories; }
function getTitleText() { return $this->mTitleText; }
function getSections() { return $this->mSections; }
+ function getEditSectionTokens() { return $this->mEditSectionTokens; }
function &getLinks() { return $this->mLinks; }
function &getTemplates() { return $this->mTemplates; }
function &getImages() { return $this->mImages; }
function setTitleText( $t ) { return wfSetVar( $this->mTitleText, $t ); }
function setSections( $toc ) { return wfSetVar( $this->mSections, $toc ); }
+ function setEditSectionTokens( $p, $s ) { return wfSetVar( $this->mEditSectionTokens, array( $p, $s ) ); }
function setIndexPolicy( $policy ) { return wfSetVar( $this->mIndexPolicy, $policy ); }
function setTOCHTML( $tochtml ) { return wfSetVar( $this->mTOCHTML, $tochtml ); }