';
}
return $text;
}
/**
* Display a page stating that the Wiki is in read-only mode,
* and optionally show the source of the page that the user
* was trying to edit. Should only be called (for this
* purpose) after wfReadOnly() has returned true.
*
* For historical reasons, this function is _also_ used to
* show the error message when a user tries to edit a page
* they are not allowed to edit. (Unless it's because they're
* blocked, then we show blockedPage() instead.) In this
* case, the second parameter should be set to true and a list
* of reasons supplied as the third parameter.
*
* @todo Needs to be split into multiple functions.
*
* @param string $source Source code to show (or null).
* @param bool $protected Is this a permissions error?
* @param array $reasons List of reasons for this error, as returned by Title::getUserPermissionsErrors().
*/
public function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) {
global $wgUser, $wgTitle;
$skin = $wgUser->getSkin();
$this->setRobotPolicy( 'noindex,nofollow' );
$this->setArticleRelated( false );
// If no reason is given, just supply a default "I can't let you do
// that, Dave" message. Should only occur if called by legacy code.
if ( $protected && empty($reasons) ) {
$reasons[] = array( 'badaccess-group0' );
}
if ( !empty($reasons) ) {
// Permissions error
if( $source ) {
$this->setPageTitle( wfMsg( 'viewsource' ) );
$this->setSubtitle( wfMsg( 'viewsourcefor', $skin->makeKnownLinkObj( $wgTitle ) ) );
} else {
$this->setPageTitle( wfMsg( 'badaccess' ) );
}
$this->addWikiText( $this->formatPermissionsErrorMessage( $reasons, $action ) );
} else {
// Wiki is read only
$this->setPageTitle( wfMsg( 'readonly' ) );
$reason = wfReadOnlyReason();
$this->wrapWikiMsg( '
" );
}
# If the title doesn't exist, it's fairly pointless to print a return
# link to it. After all, you just tried editing it and couldn't, so
# what's there to do there?
if( $wgTitle->exists() ) {
$this->returnToMain( null, $wgTitle );
}
}
/** @deprecated */
public function fatalError( $message ) {
wfDeprecated( __METHOD__ );
throw new FatalError( $message );
}
/** @deprecated */
public function unexpectedValueError( $name, $val ) {
wfDeprecated( __METHOD__ );
throw new FatalError( wfMsg( 'unexpected', $name, $val ) );
}
/** @deprecated */
public function fileCopyError( $old, $new ) {
wfDeprecated( __METHOD__ );
throw new FatalError( wfMsg( 'filecopyerror', $old, $new ) );
}
/** @deprecated */
public function fileRenameError( $old, $new ) {
wfDeprecated( __METHOD__ );
throw new FatalError( wfMsg( 'filerenameerror', $old, $new ) );
}
/** @deprecated */
public function fileDeleteError( $name ) {
wfDeprecated( __METHOD__ );
throw new FatalError( wfMsg( 'filedeleteerror', $name ) );
}
/** @deprecated */
public function fileNotFoundError( $name ) {
wfDeprecated( __METHOD__ );
throw new FatalError( wfMsg( 'filenotfound', $name ) );
}
public function showFatalError( $message ) {
$this->setPageTitle( wfMsg( "internalerror" ) );
$this->setRobotPolicy( "noindex,nofollow" );
$this->setArticleRelated( false );
$this->enableClientCache( false );
$this->mRedirect = '';
$this->mBodytext = $message;
}
public function showUnexpectedValueError( $name, $val ) {
$this->showFatalError( wfMsg( 'unexpected', $name, $val ) );
}
public function showFileCopyError( $old, $new ) {
$this->showFatalError( wfMsg( 'filecopyerror', $old, $new ) );
}
public function showFileRenameError( $old, $new ) {
$this->showFatalError( wfMsg( 'filerenameerror', $old, $new ) );
}
public function showFileDeleteError( $name ) {
$this->showFatalError( wfMsg( 'filedeleteerror', $name ) );
}
public function showFileNotFoundError( $name ) {
$this->showFatalError( wfMsg( 'filenotfound', $name ) );
}
/**
* Add a "return to" link pointing to a specified title
*
* @param Title $title Title to link
*/
public function addReturnTo( $title ) {
global $wgUser;
$this->addLink( array( 'rel' => 'next', 'href' => $title->getFullUrl() ) );
$link = wfMsg( 'returnto', $wgUser->getSkin()->makeLinkObj( $title ) );
$this->addHTML( "
{$link}
\n" );
}
/**
* Add a "return to" link pointing to a specified title,
* or the title indicated in the request, or else the main page
*
* @param null $unused No longer used
* @param Title $returnto Title to return to
*/
public function returnToMain( $unused = null, $returnto = NULL ) {
global $wgRequest;
if ( $returnto == NULL ) {
$returnto = $wgRequest->getText( 'returnto' );
}
if ( '' === $returnto ) {
$returnto = Title::newMainPage();
}
if ( is_object( $returnto ) ) {
$titleObj = $returnto;
} else {
$titleObj = Title::newFromText( $returnto );
}
if ( !is_object( $titleObj ) ) {
$titleObj = Title::newMainPage();
}
$this->addReturnTo( $titleObj );
}
/**
* This function takes the title (first item of mGoodLinks), categories, existing and broken links for the page
* and uses the first 10 of them for META keywords
*
* @param ParserOutput &$parserOutput
*/
private function addKeywords( &$parserOutput ) {
global $wgTitle;
$this->addKeyword( $wgTitle->getPrefixedText() );
$count = 1;
$links2d =& $parserOutput->getLinks();
if ( !is_array( $links2d ) ) {
return;
}
foreach ( $links2d as $dbkeys ) {
foreach( $dbkeys as $dbkey => $unused ) {
$this->addKeyword( $dbkey );
if ( ++$count > 10 ) {
break 2;
}
}
}
}
/**
* @return string The doctype, opening , and head element.
*/
public function headElement( Skin $sk ) {
global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType;
global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces;
global $wgUser, $wgContLang, $wgUseTrackbacks, $wgTitle, $wgStyleVersion;
$this->addMeta( "http:Content-type", "$wgMimeType; charset={$wgOutputEncoding}" );
$this->addStyle( 'common/wikiprintable.css', 'print' );
$sk->setupUserCss( $this );
$ret = '';
if( $wgMimeType == 'text/xml' || $wgMimeType == 'application/xhtml+xml' || $wgMimeType == 'application/xml' ) {
$ret .= "\n";
}
$ret .= "\n";
if ( '' == $this->getHTMLTitle() ) {
$this->setHTMLTitle( wfMsg( 'pagetitle', $this->getPageTitle() ));
}
$rtl = $wgContLang->isRTL() ? " dir='RTL'" : '';
$ret .= " $ns) {
$ret .= "xmlns:{$tag}=\"{$ns}\" ";
}
$ret .= "xml:lang=\"$wgContLanguageCode\" lang=\"$wgContLanguageCode\" $rtl>\n";
$ret .= "\n" . htmlspecialchars( $this->getHTMLTitle() ) . "\n\t\t";
$ret .= implode( "\t\t", array(
$this->getHeadLinks(),
$this->buildCssLinks(),
$sk->getHeadScripts( $this->mAllowUserJs ),
$this->mScripts,
$this->getHeadItems(),
));
if( $sk->usercss ){
$ret .= "";
}
if ($wgUseTrackbacks && $this->isArticleRelated())
$ret .= $wgTitle->trackbackRDF();
$ret .= "\n";
return $ret;
}
protected function addDefaultMeta() {
global $wgVersion;
$this->addMeta( 'http:Content-Style-Type', 'text/css' ); //bug 15835
$this->addMeta( 'generator', "MediaWiki $wgVersion" );
$p = "{$this->mIndexPolicy},{$this->mFollowPolicy}";
if( $p !== 'index,follow' ) {
// http://www.robotstxt.org/wc/meta-user.html
// Only show if it's different from the default robots policy
$this->addMeta( 'robots', $p );
}
if ( count( $this->mKeywords ) > 0 ) {
$strip = array(
"/<.*?>/" => '',
"/_/" => ' '
);
$this->addMeta( 'keywords', preg_replace(array_keys($strip), array_values($strip),implode( ",", $this->mKeywords ) ) );
}
}
/**
* @return string HTML tag links to be put in the header.
*/
public function getHeadLinks() {
global $wgRequest, $wgFeed;
// Ideally this should happen earlier, somewhere. :P
$this->addDefaultMeta();
$tags = array();
foreach ( $this->mMetatags as $tag ) {
if ( 0 == strcasecmp( 'http:', substr( $tag[0], 0, 5 ) ) ) {
$a = 'http-equiv';
$tag[0] = substr( $tag[0], 5 );
} else {
$a = 'name';
}
$tags[] = Xml::element( 'meta',
array(
$a => $tag[0],
'content' => $tag[1] ) );
}
foreach ( $this->mLinktags as $tag ) {
$tags[] = Xml::element( 'link', $tag );
}
// Language Links
global $wgContLang;
$langLinks = $this->getLanguageLinks();
foreach( $langLinks as $link ) {
$t = Title::newFromText( $link );
$tags[] = Xml::element( 'link', array(
'title' => wfMsg( 'language-link-title', $wgContLang->getLanguageName( $t->getInterwiki() ) ),
'rel' => 'alternate',
'lang' => $t->getInterwiki(),
'xml:lang' => $t->getInterwiki(),
'hreflang' => $t->getInterwiki(),
'href' => $t->getFullURL()
) );
}
if( $wgFeed ) {
global $wgTitle;
foreach( $this->getSyndicationLinks() as $format => $link ) {
# Use the page name for the title (accessed through $wgTitle since
# there's no other way). In principle, this could lead to issues
# with having the same name for different feeds corresponding to
# the same page, but we can't avoid that at this low a level.
$tags[] = $this->feedLink(
$format,
$link,
wfMsg( "page-{$format}-feed", $wgTitle->getPrefixedText() ) ); # Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
}
# Recent changes feed should appear on every page (except recentchanges,
# that would be redundant). Put it after the per-page feed to avoid
# changing existing behavior. It's still available, probably via a
# menu in your browser. Some sites might have a different feed they'd
# like to promote instead of the RC feed (maybe like a "Recent New Articles"
# or "Breaking news" one). For this, we see if $wgOverrideSiteFeed is defined.
# If so, use it instead.
global $wgOverrideSiteFeed, $wgSitename, $wgFeedClasses;
$rctitle = SpecialPage::getTitleFor( 'Recentchanges' );
if ( $wgOverrideSiteFeed ) {
foreach ( $wgOverrideSiteFeed as $type => $feedUrl ) {
$tags[] = $this->feedLink (
$type,
htmlspecialchars( $feedUrl ),
wfMsg( "site-{$type}-feed", $wgSitename ) );
}
}
else if ( $wgTitle->getPrefixedText() != $rctitle->getPrefixedText() ) {
foreach( $wgFeedClasses as $format => $class ) {
$tags[] = $this->feedLink(
$format,
$rctitle->getFullURL( "feed={$format}" ),
wfMsg( "site-{$format}-feed", $wgSitename ) ); # For grep: 'site-rss-feed', 'site-atom-feed'.
}
}
}
return implode( "\n\t\t", $tags ) . "\n";
}
/**
* Return URLs for each supported syndication format for this page.
* @return array associating format keys with URLs
*/
public function getSyndicationLinks() {
global $wgTitle, $wgFeedClasses;
$links = array();
if( $this->isSyndicated() ) {
if( is_string( $this->getFeedAppendQuery() ) ) {
$appendQuery = "&" . $this->getFeedAppendQuery();
} else {
$appendQuery = "";
}
foreach( $wgFeedClasses as $format => $class ) {
$links[$format] = $wgTitle->getLocalUrl( "feed=$format{$appendQuery}" );
}
}
return $links;
}
/**
* Generate a for an RSS feed.
*/
private function feedLink( $type, $url, $text ) {
return Xml::element( 'link', array(
'rel' => 'alternate',
'type' => "application/$type+xml",
'title' => $text,
'href' => $url ) );
}
/**
* Add a local or specified stylesheet, with the given media options.
* Meant primarily for internal use...
*
* @param $media -- to specify a media type, 'screen', 'printable', 'handheld' or any.
* @param $conditional -- for IE conditional comments, specifying an IE version
* @param $dir -- set to 'rtl' or 'ltr' for direction-specific sheets
*/
public function addStyle( $style, $media='', $condition='', $dir='' ) {
$options = array();
if( $media )
$options['media'] = $media;
if( $condition )
$options['condition'] = $condition;
if( $dir )
$options['dir'] = $dir;
$this->styles[$style] = $options;
}
/**
* Build a set of s for the stylesheets specified in the $this->styles array.
* These will be applied to various media & IE conditionals.
*/
public function buildCssLinks() {
$links = array();
foreach( $this->styles as $file => $options ) {
$link = $this->styleLink( $file, $options );
if( $link )
$links[] = $link;
}
return implode( "\n\t\t", $links );
}
protected function styleLink( $style, $options ) {
global $wgRequest;
if( isset( $options['dir'] ) ) {
global $wgContLang;
$siteDir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
if( $siteDir != $options['dir'] )
return '';
}
if( isset( $options['media'] ) ) {
$media = $this->transformCssMedia( $options['media'] );
if( is_null( $media ) ) {
return '';
}
} else {
$media = '';
}
if( substr( $style, 0, 1 ) == '/' ||
substr( $style, 0, 5 ) == 'http:' ||
substr( $style, 0, 6 ) == 'https:' ) {
$url = $style;
} else {
global $wgStylePath, $wgStyleVersion;
$url = $wgStylePath . '/' . $style . '?' . $wgStyleVersion;
}
$attribs = array(
'rel' => 'stylesheet',
'href' => $url,
'type' => 'text/css' );
if( $media ) {
$attribs['media'] = $media;
}
$link = Xml::element( 'link', $attribs );
if( isset( $options['condition'] ) ) {
$condition = htmlspecialchars( $options['condition'] );
$link = "";
}
return $link;
}
function transformCssMedia( $media ) {
global $wgRequest, $wgHandheldForIPhone;
// Switch in on-screen display for media testing
$switches = array(
'printable' => 'print',
'handheld' => 'handheld',
);
foreach( $switches as $switch => $targetMedia ) {
if( $wgRequest->getBool( $switch ) ) {
if( $media == $targetMedia ) {
$media = '';
} elseif( $media == 'screen' ) {
return null;
}
}
}
// Expand longer media queries as iPhone doesn't grok 'handheld'
if( $wgHandheldForIPhone ) {
$mediaAliases = array(
'screen' => 'screen and (min-device-width: 481px)',
'handheld' => 'handheld, only screen and (max-device-width: 480px)',
);
if( isset( $mediaAliases[$media] ) ) {
$media = $mediaAliases[$media];
}
}
return $media;
}
/**
* Turn off regular page output and return an error reponse
* for when rate limiting has triggered.
*/
public function rateLimited() {
global $wgTitle;
$this->setPageTitle(wfMsg('actionthrottled'));
$this->setRobotPolicy( 'noindex,follow' );
$this->setArticleRelated( false );
$this->enableClientCache( false );
$this->mRedirect = '';
$this->clearHTML();
$this->setStatusCode(503);
$this->addWikiMsg( 'actionthrottledtext' );
$this->returnToMain( null, $wgTitle );
}
/**
* Show an "add new section" link?
*
* @return bool
*/
public function showNewSectionLink() {
return $this->mNewSectionLink;
}
/**
* Show a warning about slave lag
*
* If the lag is higher than $wgSlaveLagCritical seconds,
* then the warning is a bit more obvious. If the lag is
* lower than $wgSlaveLagWarning, then no warning is shown.
*
* @param int $lag Slave lag
*/
public function showLagWarning( $lag ) {
global $wgSlaveLagWarning, $wgSlaveLagCritical;
if( $lag >= $wgSlaveLagWarning ) {
$message = $lag < $wgSlaveLagCritical
? 'lag-warn-normal'
: 'lag-warn-high';
$warning = wfMsgExt( $message, 'parse', $lag );
$this->addHTML( "
\n{$warning}\n
\n" );
}
}
/**
* Add a wikitext-formatted message to the output.
* This is equivalent to:
*
* $wgOut->addWikiText( wfMsgNoTrans( ... ) )
*/
public function addWikiMsg( /*...*/ ) {
$args = func_get_args();
$name = array_shift( $args );
$this->addWikiMsgArray( $name, $args );
}
/**
* Add a wikitext-formatted message to the output.
* Like addWikiMsg() except the parameters are taken as an array
* instead of a variable argument list.
*
* $options is passed through to wfMsgExt(), see that function for details.
*/
public function addWikiMsgArray( $name, $args, $options = array() ) {
$options[] = 'parse';
$text = wfMsgExt( $name, $options, $args );
$this->addHTML( $text );
}
/**
* This function takes a number of message/argument specifications, wraps them in
* some overall structure, and then parses the result and adds it to the output.
*
* In the $wrap, $1 is replaced with the first message, $2 with the second, and so
* on. The subsequent arguments may either be strings, in which case they are the
* message names, or an arrays, in which case the first element is the message name,
* and subsequent elements are the parameters to that message.
*
* The special named parameter 'options' in a message specification array is passed
* through to the $options parameter of wfMsgExt().
*
* Don't use this for messages that are not in users interface language.
*
* For example:
*
* $wgOut->wrapWikiMsg( '
$1
', 'some-error' );
*
* Is equivalent to:
*
* $wgOut->addWikiText( '