diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2013-12-08 09:55:49 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2013-12-08 09:55:49 +0100 |
commit | 4ac9fa081a7c045f6a9f1cfc529d82423f485b2e (patch) | |
tree | af68743f2f4a47d13f2b0eb05f5c4aaf86d8ea37 /includes/OutputPage.php | |
parent | af4da56f1ad4d3ef7b06557bae365da2ea27a897 (diff) |
Update to MediaWiki 1.22.0
Diffstat (limited to 'includes/OutputPage.php')
-rw-r--r-- | includes/OutputPage.php | 476 |
1 files changed, 229 insertions, 247 deletions
diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 1e0c396a..7f0454f6 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -39,9 +39,6 @@ class OutputPage extends ContextSource { /// Should be private. Used with addMeta() which adds "<meta>" var $mMetatags = array(); - /// "<meta keywords='stuff'>" most of the time the first 10 links to an article - var $mKeywords = array(); - var $mLinktags = array(); var $mCanonicalUrl = false; @@ -254,6 +251,16 @@ class OutputPage extends ContextSource { private $mProperties = array(); /** + * @var string|null: ResourceLoader target for load.php links. If null, will be omitted + */ + private $mTarget = null; + + /** + * @var bool: Whether output should contain table of contents + */ + private $mEnableTOC = true; + + /** * Constructor for OutputPage. This should not be called directly. * Instead a new RequestContext should be created and it will implicitly create * a OutputPage tied to that context. @@ -309,19 +316,6 @@ class OutputPage extends ContextSource { } /** - * Add a keyword or a list of keywords in the page header - * - * @param string $text or array of strings - */ - function addKeyword( $text ) { - if( is_array( $text ) ) { - $this->mKeywords = array_merge( $this->mKeywords, $text ); - } else { - array_push( $this->mKeywords, $text ); - } - } - - /** * Add a new \<link\> tag to the page header. * * Note: use setCanonicalUrl() for rel=canonical. @@ -408,13 +402,14 @@ class OutputPage extends ContextSource { public function addScriptFile( $file, $version = null ) { global $wgStylePath, $wgStyleVersion; // See if $file parameter is an absolute URL or begins with a slash - if( substr( $file, 0, 1 ) == '/' || preg_match( '#^[a-z]*://#i', $file ) ) { + if ( substr( $file, 0, 1 ) == '/' || preg_match( '#^[a-z]*://#i', $file ) ) { $path = $file; } else { $path = "{$wgStylePath}/common/{$file}"; } - if ( is_null( $version ) ) + if ( is_null( $version ) ) { $version = $wgStyleVersion; + } $this->addScript( Html::linkedScript( wfAppendQuery( $path, $version ) ) ); } @@ -447,11 +442,12 @@ class OutputPage extends ContextSource { protected function filterModules( $modules, $position = null, $type = ResourceLoaderModule::TYPE_COMBINED ) { $resourceLoader = $this->getResourceLoader(); $filteredModules = array(); - foreach( $modules as $val ) { + foreach ( $modules as $val ) { $module = $resourceLoader->getModule( $val ); - if( $module instanceof ResourceLoaderModule + if ( $module instanceof ResourceLoaderModule && $module->getOrigin() <= $this->getAllowedModules( $type ) - && ( is_null( $position ) || $module->getPosition() == $position ) ) + && ( is_null( $position ) || $module->getPosition() == $position ) + && ( !$this->mTarget || in_array( $this->mTarget, $module->getTargets() ) ) ) { $filteredModules[] = $val; } @@ -557,6 +553,22 @@ class OutputPage extends ContextSource { } /** + * @return null|string: ResourceLoader target + */ + public function getTarget() { + return $this->mTarget; + } + + /** + * Sets ResourceLoader target for load.php links. If null, will be omitted + * + * @param $target string|null + */ + public function setTarget( $target ) { + $this->mTarget = $target; + } + + /** * Get an array of head items * * @return Array @@ -662,20 +674,20 @@ class OutputPage extends ContextSource { * * @param $timestamp string * - * @return Boolean: true iff cache-ok headers was sent. + * @return Boolean: true if cache-ok headers was sent. */ public function checkLastModified( $timestamp ) { - global $wgCachePages, $wgCacheEpoch; + global $wgCachePages, $wgCacheEpoch, $wgUseSquid, $wgSquidMaxage; if ( !$timestamp || $timestamp == '19700101000000' ) { wfDebug( __METHOD__ . ": CACHE DISABLED, NO TIMESTAMP\n" ); return false; } - if( !$wgCachePages ) { + if ( !$wgCachePages ) { wfDebug( __METHOD__ . ": CACHE DISABLED\n", false ); return false; } - if( $this->getUser()->getOption( 'nocache' ) ) { + if ( $this->getUser()->getOption( 'nocache' ) ) { wfDebug( __METHOD__ . ": USER DISABLED CACHE\n", false ); return false; } @@ -686,6 +698,10 @@ class OutputPage extends ContextSource { 'user' => $this->getUser()->getTouched(), 'epoch' => $wgCacheEpoch ); + if ( $wgUseSquid ) { + // bug 44570: the core page itself may not change, but resources might + $modifiedTimes['sepoch'] = wfTimestamp( TS_MW, time() - $wgSquidMaxage ); + } wfRunHooks( 'OutputPageCheckLastModified', array( &$modifiedTimes ) ); $maxModified = max( $modifiedTimes ); @@ -724,7 +740,7 @@ class OutputPage extends ContextSource { wfTimestamp( TS_ISO_8601, $clientHeaderTime ) . "\n", false ); wfDebug( __METHOD__ . ": effective Last-Modified: " . wfTimestamp( TS_ISO_8601, $maxModified ) . "\n", false ); - if( $clientHeaderTime < $maxModified ) { + if ( $clientHeaderTime < $maxModified ) { wfDebug( __METHOD__ . ": STALE, $info\n", false ); return false; } @@ -766,10 +782,10 @@ class OutputPage extends ContextSource { public function setRobotPolicy( $policy ) { $policy = Article::formatRobotPolicy( $policy ); - if( isset( $policy['index'] ) ) { + if ( isset( $policy['index'] ) ) { $this->setIndexPolicy( $policy['index'] ); } - if( isset( $policy['follow'] ) ) { + if ( isset( $policy['follow'] ) ) { $this->setFollowPolicy( $policy['follow'] ); } } @@ -783,7 +799,7 @@ class OutputPage extends ContextSource { */ public function setIndexPolicy( $policy ) { $policy = trim( $policy ); - if( in_array( $policy, array( 'index', 'noindex' ) ) ) { + if ( in_array( $policy, array( 'index', 'noindex' ) ) ) { $this->mIndexPolicy = $policy; } } @@ -797,7 +813,7 @@ class OutputPage extends ContextSource { */ public function setFollowPolicy( $policy ) { $policy = trim( $policy ); - if( in_array( $policy, array( 'follow', 'nofollow' ) ) ) { + if ( in_array( $policy, array( 'follow', 'nofollow' ) ) ) { $this->mFollowPolicy = $policy; } } @@ -1269,7 +1285,6 @@ class OutputPage extends ContextSource { * Return whether user JavaScript is allowed for this page * @deprecated since 1.18 Load modules with ResourceLoader, and origin and * trustworthiness is identified and enforced automagically. - * Will be removed in 1.20. * @return Boolean */ public function isUserJsAllowed() { @@ -1284,7 +1299,7 @@ class OutputPage extends ContextSource { * @return Int ResourceLoaderModule ORIGIN_ class constant */ public function getAllowedModules( $type ) { - if( $type == ResourceLoaderModule::TYPE_COMBINED ) { + if ( $type == ResourceLoaderModule::TYPE_COMBINED ) { return min( array_values( $this->mAllowedModules ) ); } else { return isset( $this->mAllowedModules[$type] ) @@ -1401,7 +1416,7 @@ class OutputPage extends ContextSource { * @param $timestamp Mixed: string, or null * @return Mixed: previous value */ - public function setRevisionTimestamp( $timestamp) { + public function setRevisionTimestamp( $timestamp ) { return wfSetVar( $this->mRevisionTimestamp, $timestamp ); } @@ -1524,7 +1539,7 @@ class OutputPage extends ContextSource { $popts = $this->parserOptions(); $oldTidy = $popts->setTidy( $tidy ); - $popts->setInterfaceMessage( (bool) $interface ); + $popts->setInterfaceMessage( (bool)$interface ); $parserOutput = $wgParser->parse( $text, $title, $popts, @@ -1582,6 +1597,10 @@ class OutputPage extends ContextSource { } } + // Link flags are ignored for now, but may in the future be + // used to mark individual language links. + $linkFlags = array(); + wfRunHooks( 'LanguageLinks', array( $this->getTitle(), &$this->mLanguageLinks, &$linkFlags ) ); wfRunHooks( 'OutputPageParserOutput', array( &$this, $parserOutput ) ); } @@ -1592,6 +1611,7 @@ class OutputPage extends ContextSource { */ function addParserOutput( &$parserOutput ) { $this->addParserOutputNoText( $parserOutput ); + $parserOutput->setTOCEnabled( $this->mEnableTOC ); $text = $parserOutput->getText(); wfRunHooks( 'OutputPageBeforeHTML', array( &$this, &$text ) ); $this->addHTML( $text ); @@ -1626,7 +1646,7 @@ class OutputPage extends ContextSource { public function parse( $text, $linestart = true, $interface = false, $language = null ) { global $wgParser; - if( is_null( $this->getTitle() ) ) { + if ( is_null( $this->getTitle() ) ) { throw new MWException( 'Empty $mTitle in ' . __METHOD__ ); } @@ -1707,6 +1727,7 @@ class OutputPage extends ContextSource { array( "{$wgCookiePrefix}Token", "{$wgCookiePrefix}LoggedOut", + "forceHTTPS", session_name() ), $wgCacheVaryCookies @@ -1750,8 +1771,8 @@ class OutputPage extends ContextSource { public function addVaryHeader( $header, $option = null ) { if ( !array_key_exists( $header, $this->mVaryHeader ) ) { $this->mVaryHeader[$header] = (array)$option; - } elseif( is_array( $option ) ) { - if( is_array( $this->mVaryHeader[$header] ) ) { + } elseif ( is_array( $option ) ) { + if ( is_array( $this->mVaryHeader[$header] ) ) { $this->mVaryHeader[$header] = array_merge( $this->mVaryHeader[$header], $option ); } else { $this->mVaryHeader[$header] = $option; @@ -1785,7 +1806,7 @@ class OutputPage extends ContextSource { $this->addVaryHeader( 'Cookie', $cookiesOption ); $headers = array(); - foreach( $this->mVaryHeader as $header => $option ) { + foreach ( $this->mVaryHeader as $header => $option ) { $newheader = $header; if ( is_array( $option ) && count( $option ) > 0 ) { $newheader .= ';' . implode( ';', $option ); @@ -1807,11 +1828,11 @@ class OutputPage extends ContextSource { */ function addAcceptLanguage() { $lang = $this->getTitle()->getPageLanguage(); - if( !$this->getRequest()->getCheck( 'variant' ) && $lang->hasVariants() ) { + if ( !$this->getRequest()->getCheck( 'variant' ) && $lang->hasVariants() ) { $variants = $lang->getVariants(); $aloption = array(); foreach ( $variants as $variant ) { - if( $variant === $lang->getCode() ) { + if ( $variant === $lang->getCode() ) { continue; } else { $aloption[] = 'string-contains=' . $variant; @@ -1892,12 +1913,11 @@ class OutputPage extends ContextSource { $response->header( $this->getXVO() ); } - if( $this->mEnableClientCache ) { - if( + if ( $this->mEnableClientCache ) { + if ( $wgUseSquid && session_id() == '' && !$this->isPrintable() && $this->mSquidMaxage != 0 && !$this->haveCacheVaryCookies() - ) - { + ) { if ( $wgUseESI ) { # We'll purge the proxy cache explicitly, but require end user agents # to revalidate against the proxy on each visit. @@ -1924,7 +1944,7 @@ class OutputPage extends ContextSource { $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' ); $response->header( "Cache-Control: private, must-revalidate, max-age=0" ); } - if( $this->mLastModified ) { + if ( $this->mLastModified ) { $response->header( "Last-Modified: {$this->mLastModified}" ); } } else { @@ -1957,9 +1977,10 @@ class OutputPage extends ContextSource { * the object, let's actually output it: */ public function output() { - global $wgLanguageCode, $wgDebugRedirects, $wgMimeType, $wgVaryOnXFP; + global $wgLanguageCode, $wgDebugRedirects, $wgMimeType, $wgVaryOnXFP, + $wgUseAjax, $wgResponsiveImages; - if( $this->mDoNothing ) { + if ( $this->mDoNothing ) { return; } @@ -1974,9 +1995,9 @@ class OutputPage extends ContextSource { $redirect = $this->mRedirect; $code = $this->mRedirectCode; - if( wfRunHooks( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) { - if( $code == '301' || $code == '303' ) { - if( !$wgDebugRedirects ) { + if ( wfRunHooks( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) { + if ( $code == '301' || $code == '303' ) { + if ( !$wgDebugRedirects ) { $message = HttpStatus::getMessage( $code ); $response->header( "HTTP/1.1 $code $message" ); } @@ -1988,7 +2009,7 @@ class OutputPage extends ContextSource { $this->sendCacheControl(); $response->header( "Content-Type: text/html; charset=utf-8" ); - if( $wgDebugRedirects ) { + if ( $wgDebugRedirects ) { $url = htmlspecialchars( $redirect ); print "<html>\n<head>\n<title>Redirect</title>\n</head>\n<body>\n"; print "<p>Location: <a href=\"$url\">$url</a></p>\n"; @@ -2020,11 +2041,34 @@ class OutputPage extends ContextSource { } if ( $this->mArticleBodyOnly ) { - $this->out( $this->mBodytext ); + echo $this->mBodytext; } else { - $this->addDefaultModules(); $sk = $this->getSkin(); + // add skin specific modules + $modules = $sk->getDefaultModules(); + + // enforce various default modules for all skins + $coreModules = array( + // keep this list as small as possible + 'mediawiki.page.startup', + 'mediawiki.user', + ); + + // Support for high-density display images if enabled + if ( $wgResponsiveImages ) { + $coreModules[] = 'mediawiki.hidpi'; + } + + $this->addModules( $coreModules ); + foreach ( $modules as $group ) { + $this->addModules( $group ); + } + MWDebug::addModules( $this ); + if ( $wgUseAjax ) { + // FIXME: deprecate? - not clear why this is useful + wfRunHooks( 'AjaxAddScript', array( &$this ) ); + } // Hook that allows last minute changes to the output page, e.g. // adding of CSS or Javascript by extensions. @@ -2046,11 +2090,13 @@ class OutputPage extends ContextSource { } /** - * Actually output something with print(). + * Actually output something with print. * * @param string $ins the string to output + * @deprecated since 1.22 Use echo yourself. */ public function out( $ins ) { + wfDeprecated( __METHOD__, '1.22' ); print $ins; } @@ -2097,7 +2143,7 @@ class OutputPage extends ContextSource { * @param array $params message parameters; ignored if $msg is a Message object */ public function showErrorPage( $title, $msg, $params = array() ) { - if( !$title instanceof Message ) { + if ( !$title instanceof Message ) { $title = $this->msg( $title ); } @@ -2238,7 +2284,7 @@ class OutputPage extends ContextSource { if ( count( $errors ) > 1 ) { $text .= '<ul class="permissions-errors">' . "\n"; - foreach( $errors as $error ) { + foreach ( $errors as $error ) { $text .= '<li>'; $text .= call_user_func_array( array( $this, 'msg' ), $error )->plain(); $text .= "</li>\n"; @@ -2286,7 +2332,7 @@ class OutputPage extends ContextSource { if ( !empty( $reasons ) ) { // Permissions error - if( $source ) { + if ( $source ) { $this->setPageTitle( $this->msg( 'viewsource-title', $this->getTitle()->getPrefixedText() ) ); $this->addBacklinkSubtitle( $this->getTitle() ); } else { @@ -2299,7 +2345,7 @@ class OutputPage extends ContextSource { } // Show source, if supplied - if( is_string( $source ) ) { + if ( is_string( $source ) ) { $this->addWikiMsg( 'viewsourcetext' ); $pageLang = $this->getTitle()->getPageLanguage(); @@ -2325,7 +2371,7 @@ $templates # 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( $this->getTitle()->exists() ) { + if ( $this->getTitle()->exists() ) { $this->returnToMain( null, $this->getTitle() ); } } @@ -2349,7 +2395,7 @@ $templates */ public function showLagWarning( $lag ) { global $wgSlaveLagWarning, $wgSlaveLagCritical; - if( $lag >= $wgSlaveLagWarning ) { + if ( $lag >= $wgSlaveLagWarning ) { $message = $lag < $wgSlaveLagCritical ? 'lag-warn-normal' : 'lag-warn-high'; @@ -2393,15 +2439,6 @@ $templates * @param $options Options array to pass to Linker */ public function addReturnTo( $title, $query = array(), $text = null, $options = array() ) { - if( in_array( 'http', $options ) ) { - $proto = PROTO_HTTP; - } elseif( in_array( 'https', $options ) ) { - $proto = PROTO_HTTPS; - } else { - $proto = PROTO_RELATIVE; - } - - $this->addLink( array( 'rel' => 'next', 'href' => $title->getFullURL( '', false, $proto ) ) ); $link = $this->msg( 'returnto' )->rawParams( Linker::link( $title, $text, array(), $query, $options ) )->escaped(); $this->addHTML( "<p id=\"mw-returnto\">{$link}</p>\n" ); @@ -2446,15 +2483,11 @@ $templates * @return String: The doctype, opening "<html>", and head element. */ public function headElement( Skin $sk, $includeStyle = true ) { - global $wgContLang; + global $wgContLang, $wgMimeType; $userdir = $this->getLanguage()->getDir(); $sitedir = $wgContLang->getDir(); - if ( $sk->commonPrintStylesheet() ) { - $this->addModuleStyles( 'mediawiki.legacy.wikiprintable' ); - } - $ret = Html::htmlHeader( array( 'lang' => $this->getLanguage()->getHtmlCode(), 'dir' => $userdir, 'class' => 'client-nojs' ) ); if ( $this->getHTMLTitle() == '' ) { @@ -2467,10 +2500,22 @@ $templates $ret .= "$openHead\n"; } + if ( !Html::isXmlMimeType( $wgMimeType ) ) { + // Add <meta charset="UTF-8"> + // This should be before <title> since it defines the charset used by + // text including the text inside <title>. + // The spec recommends defining XHTML5's charset using the XML declaration + // instead of meta. + // Our XML declaration is output by Html::htmlHeader. + // http://www.whatwg.org/html/semantics.html#attr-meta-http-equiv-content-type + // http://www.whatwg.org/html/semantics.html#charset + $ret .= Html::element( 'meta', array( 'charset' => 'UTF-8' ) ); + } + $ret .= Html::element( 'title', null, $this->getHTMLTitle() ) . "\n"; $ret .= implode( "\n", array( - $this->getHeadLinks( null, true ), + $this->getHeadLinks(), $this->buildCssLinks(), $this->getHeadScripts(), $this->getHeadItems() @@ -2481,20 +2526,29 @@ $templates $ret .= "$closeHead\n"; } - $bodyAttrs = array(); + $bodyClasses = array(); + $bodyClasses[] = 'mediawiki'; # Classes for LTR/RTL directionality support - $bodyAttrs['class'] = "mediawiki $userdir sitedir-$sitedir"; + $bodyClasses[] = $userdir; + $bodyClasses[] = "sitedir-$sitedir"; if ( $this->getLanguage()->capitalizeAllNouns() ) { # A <body> class is probably not the best way to do this . . . - $bodyAttrs['class'] .= ' capitalize-all-nouns'; + $bodyClasses[] = 'capitalize-all-nouns'; } - $bodyAttrs['class'] .= ' ' . $sk->getPageClasses( $this->getTitle() ); - $bodyAttrs['class'] .= ' skin-' . Sanitizer::escapeClass( $sk->getSkinName() ); - $bodyAttrs['class'] .= ' action-' . Sanitizer::escapeClass( Action::getActionName( $this->getContext() ) ); - $sk->addToBodyAttributes( $this, $bodyAttrs ); // Allow skins to add body attributes they need + $bodyClasses[] = $sk->getPageClasses( $this->getTitle() ); + $bodyClasses[] = 'skin-' . Sanitizer::escapeClass( $sk->getSkinName() ); + $bodyClasses[] = 'action-' . Sanitizer::escapeClass( Action::getActionName( $this->getContext() ) ); + + $bodyAttrs = array(); + // While the implode() is not strictly needed, it's used for backwards compatibility + // (this used to be built as a string and hooks likely still expect that). + $bodyAttrs['class'] = implode( ' ', $bodyClasses ); + + // Allow skins and extensions to add body attributes they need + $sk->addToBodyAttributes( $this, $bodyAttrs ); wfRunHooks( 'OutputPageBodyAttributes', array( $this, $sk, &$bodyAttrs ) ); $ret .= Html::openElement( 'body', $bodyAttrs ) . "\n"; @@ -2503,59 +2557,6 @@ $templates } /** - * Add the default ResourceLoader modules to this object - */ - private function addDefaultModules() { - global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax, - $wgAjaxWatch, $wgResponsiveImages; - - // Add base resources - $this->addModules( array( - 'mediawiki.user', - 'mediawiki.page.startup', - 'mediawiki.page.ready', - ) ); - if ( $wgIncludeLegacyJavaScript ) { - $this->addModules( 'mediawiki.legacy.wikibits' ); - } - - if ( $wgPreloadJavaScriptMwUtil ) { - $this->addModules( 'mediawiki.util' ); - } - - MWDebug::addModules( $this ); - - // Add various resources if required - if ( $wgUseAjax ) { - $this->addModules( 'mediawiki.legacy.ajax' ); - - wfRunHooks( 'AjaxAddScript', array( &$this ) ); - - if( $wgAjaxWatch && $this->getUser()->isLoggedIn() ) { - $this->addModules( 'mediawiki.page.watch.ajax' ); - } - - if ( !$this->getUser()->getOption( 'disablesuggest', false ) ) { - $this->addModules( 'mediawiki.searchSuggest' ); - } - } - - if ( $this->getUser()->getBoolOption( 'editsectiononrightclick' ) ) { - $this->addModules( 'mediawiki.action.view.rightClickEdit' ); - } - - # Crazy edit-on-double-click stuff - if ( $this->isArticle() && $this->getUser()->getOption( 'editondblclick' ) ) { - $this->addModules( 'mediawiki.action.view.dblClickEdit' ); - } - - // Support for high-density display images - if ( $wgResponsiveImages ) { - $this->addModules( 'mediawiki.hidpi' ); - } - } - - /** * Get a ResourceLoader object associated with this OutputPage * * @return ResourceLoader @@ -2579,7 +2580,7 @@ $templates protected function makeResourceLoaderLink( $modules, $only, $useESI = false, array $extraQuery = array(), $loadCall = false ) { global $wgResourceLoaderUseESI; - $modules = (array) $modules; + $modules = (array)$modules; if ( !count( $modules ) ) { return ''; @@ -2600,6 +2601,9 @@ $templates return $links; } } + if ( !is_null( $this->mTarget ) ) { + $extraQuery['target'] = $this->mTarget; + } // Create keyed-by-group list of module objects from modules list $groups = array(); @@ -2612,8 +2616,8 @@ $templates && $only == ResourceLoaderModule::TYPE_SCRIPTS ) || ( $module->getOrigin() > $this->getAllowedModules( ResourceLoaderModule::TYPE_STYLES ) && $only == ResourceLoaderModule::TYPE_STYLES ) - ) - { + || ( $this->mTarget && !in_array( $this->mTarget, $module->getTargets() ) ) + ) { continue; } @@ -2648,7 +2652,7 @@ $templates ); $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) ); // Extract modules that know they're empty - $emptyModules = array (); + $emptyModules = array(); foreach ( $grpModules as $key => $module ) { if ( $module->isKnownEmpty( $context ) ) { $emptyModules[$key] = 'ready'; @@ -2659,13 +2663,9 @@ $templates if ( count( $emptyModules ) > 0 && $only !== ResourceLoaderModule::TYPE_STYLES ) { // If we're only getting the styles, we don't need to do anything for empty modules. $links .= Html::inlineScript( - ResourceLoader::makeLoaderConditionalScript( - ResourceLoader::makeLoaderStateScript( $emptyModules ) - ) - ) . "\n"; } @@ -2732,7 +2732,7 @@ $templates // Automatically select style/script elements if ( $only === ResourceLoaderModule::TYPE_STYLES ) { $link = Html::linkedStyle( $url ); - } else if ( $loadCall ) { + } elseif ( $loadCall ) { $link = Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) ) @@ -2743,7 +2743,7 @@ $templates } } - if( $group == 'noscript' ) { + if ( $group == 'noscript' ) { $links .= Html::rawElement( 'noscript', array(), $link ) . "\n"; } else { $links .= $link . "\n"; @@ -2847,14 +2847,14 @@ $templates ); $defaultModules['site'] = 'loading'; } else { - // The wiki is configured to not allow a site module. - $defaultModules['site'] = 'missing'; + // Site module is empty, save request by marking ready in advance (bug 46857) + $defaultModules['site'] = 'ready'; } // Add user JS if enabled if ( $wgAllowUserJs ) { if ( $this->getUser()->isLoggedIn() ) { - if( $this->getTitle() && $this->getTitle()->isJsSubpage() && $this->userCanPreview() ) { + if ( $this->getTitle() && $this->getTitle()->isJsSubpage() && $this->userCanPreview() ) { # XXX: additional security check/prompt? // We're on a preview of a JS subpage // Exclude this page from the user module in case it's in there (bug 26283) @@ -2874,15 +2874,14 @@ $templates } $defaultModules['user'] = 'loading'; } else { - // Non-logged-in users have no user module. Treat it as empty and 'ready' to avoid - // blocking default gadgets that might depend on it. Although arguably default-enabled - // gadgets should not depend on the user module, it's harmless and less error-prone to - // handle this case. + // Non-logged-in users have an empty user module. + // Save request by marking ready in advance (bug 46857) $defaultModules['user'] = 'ready'; } } else { - // User JS disabled - $defaultModules['user'] = 'missing'; + // User modules are disabled on this wiki. + // Save request by marking ready in advance (bug 46857) + $defaultModules['user'] = 'ready'; } // Group JS is only enabled if site JS is enabled. @@ -2893,13 +2892,13 @@ $templates ); $defaultModules['user.groups'] = 'loading'; } else { - // Non-logged-in users have no user.groups module. Treat it as empty and 'ready' to - // avoid blocking gadgets that might depend upon the module. + // Non-logged-in users have no user.groups module. + // Save request by marking ready in advance (bug 46857) $defaultModules['user.groups'] = 'ready'; } } else { // Site (and group JS) disabled - $defaultModules['user.groups'] = 'missing'; + $defaultModules['user.groups'] = 'ready'; } $loaderInit = ''; @@ -2927,11 +2926,18 @@ $templates */ function getBottomScripts() { global $wgResourceLoaderExperimentalAsyncLoading; + + // Optimise jQuery ready event cross-browser. + // This also enforces $.isReady to be true at </body> which fixes the + // mw.loader bug in Firefox with using document.write between </body> + // and the DOMContentReady event (bug 47457). + $html = Html::inlineScript( 'window.jQuery && jQuery.ready();' ); + if ( !$wgResourceLoaderExperimentalAsyncLoading ) { - return $this->getScriptsForBottomQueue( false ); - } else { - return ''; + $html .= $this->getScriptsForBottomQueue( false ); } + + return $html; } /** @@ -2966,24 +2972,24 @@ $templates public function getJSVars() { global $wgContLang; - $latestRevID = 0; - $pageID = 0; - $canonicalName = false; # bug 21115 + $curRevisionId = 0; + $articleId = 0; + $canonicalSpecialPageName = false; # bug 21115 $title = $this->getTitle(); $ns = $title->getNamespace(); - $nsname = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $title->getNsText(); + $canonicalNamespace = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $title->getNsText(); // Get the relevant title so that AJAX features can use the correct page name // when making API requests from certain special pages (bug 34972). $relevantTitle = $this->getSkin()->getRelevantTitle(); if ( $ns == NS_SPECIAL ) { - list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); + list( $canonicalSpecialPageName, /*...*/ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); } elseif ( $this->canUseWikiPage() ) { $wikiPage = $this->getWikiPage(); - $latestRevID = $wikiPage->getLatest(); - $pageID = $wikiPage->getId(); + $curRevisionId = $wikiPage->getLatest(); + $articleId = $wikiPage->getId(); } $lang = $title->getPageLanguage(); @@ -3005,20 +3011,23 @@ $templates $user = $this->getUser(); $vars = array( - 'wgCanonicalNamespace' => $nsname, - 'wgCanonicalSpecialPageName' => $canonicalName, + 'wgCanonicalNamespace' => $canonicalNamespace, + 'wgCanonicalSpecialPageName' => $canonicalSpecialPageName, 'wgNamespaceNumber' => $title->getNamespace(), 'wgPageName' => $title->getPrefixedDBkey(), 'wgTitle' => $title->getText(), - 'wgCurRevisionId' => $latestRevID, - 'wgArticleId' => $pageID, + 'wgCurRevisionId' => $curRevisionId, + 'wgRevisionId' => (int)$this->getRevisionId(), + 'wgArticleId' => $articleId, 'wgIsArticle' => $this->isArticle(), + 'wgIsRedirect' => $title->isRedirect(), 'wgAction' => Action::getActionName( $this->getContext() ), 'wgUserName' => $user->isAnon() ? null : $user->getName(), 'wgUserGroups' => $user->getEffectiveGroups(), 'wgCategories' => $this->getCategories(), 'wgBreakFrames' => $this->getFrameOptions() == 'DENY', 'wgPageContentLanguage' => $lang->getCode(), + 'wgPageContentModel' => $title->getContentModel(), 'wgSeparatorTransformTable' => $compactSeparatorTransTable, 'wgDigitTransformTable' => $compactDigitTransTable, 'wgDefaultDateFormat' => $lang->getDefaultDateFormat(), @@ -3031,10 +3040,16 @@ $templates $vars['wgUserEditCount'] = $user->getEditCount(); $userReg = wfTimestampOrNull( TS_UNIX, $user->getRegistration() ); $vars['wgUserRegistration'] = $userReg !== null ? ( $userReg * 1000 ) : null; + // Get the revision ID of the oldest new message on the user's talk + // page. This can be used for constructing new message alerts on + // the client side. + $vars['wgUserNewMsgRevisionId'] = $user->getNewMessageRevisionId(); } if ( $wgContLang->hasVariants() ) { $vars['wgUserVariant'] = $wgContLang->getPreferredVariant(); } + // Same test as SkinTemplate + $vars['wgIsProbablyEditable'] = $title->quickUserCan( 'edit', $user ) && ( $title->exists() || $title->quickUserCan( 'create', $user ) ); foreach ( $title->getRestrictionTypes() as $type ) { $vars['wgRestriction' . ucfirst( $type )] = $title->getRestrictions( $type ); } @@ -3080,13 +3095,11 @@ $templates } /** - * @param bool $addContentType Whether "<meta>" specifying content type should be returned - * * @return array in format "link name or number => 'link html'". */ - public function getHeadLinksArray( $addContentType = false ) { + public function getHeadLinksArray() { global $wgUniversalEditButton, $wgFavicon, $wgAppleTouchIcon, $wgEnableAPI, - $wgSitename, $wgVersion, $wgHtml5, $wgMimeType, + $wgSitename, $wgVersion, $wgFeed, $wgOverrideSiteFeed, $wgAdvertisedFeedTypes, $wgDisableLangConversion, $wgCanonicalLanguageLinks, $wgRightsPage, $wgRightsUrl; @@ -3095,30 +3108,13 @@ $templates $canonicalUrl = $this->mCanonicalUrl; - if ( $addContentType ) { - if ( $wgHtml5 ) { - # More succinct than <meta http-equiv=Content-Type>, has the - # same effect - $tags['meta-charset'] = Html::element( 'meta', array( 'charset' => 'UTF-8' ) ); - } else { - $tags['meta-content-type'] = Html::element( 'meta', array( - 'http-equiv' => 'Content-Type', - 'content' => "$wgMimeType; charset=UTF-8" - ) ); - $tags['meta-content-style-type'] = Html::element( 'meta', array( // bug 15835 - 'http-equiv' => 'Content-Style-Type', - 'content' => 'text/css' - ) ); - } - } - $tags['meta-generator'] = Html::element( 'meta', array( 'name' => 'generator', 'content' => "MediaWiki $wgVersion", ) ); $p = "{$this->mIndexPolicy},{$this->mFollowPolicy}"; - if( $p !== 'index,follow' ) { + if ( $p !== 'index,follow' ) { // http://www.robotstxt.org/wc/meta-user.html // Only show if it's different from the default robots policy $tags['meta-robots'] = Html::element( 'meta', array( @@ -3127,21 +3123,6 @@ $templates ) ); } - if ( count( $this->mKeywords ) > 0 ) { - $strip = array( - "/<.*?" . ">/" => '', - "/_/" => ' ' - ); - $tags['meta-keywords'] = Html::element( 'meta', array( - 'name' => 'keywords', - 'content' => preg_replace( - array_keys( $strip ), - array_values( $strip ), - implode( ',', $this->mKeywords ) - ) - ) ); - } - foreach ( $this->mMetatags as $tag ) { if ( 0 == strcasecmp( 'http:', substr( $tag[0], 0, 5 ) ) ) { $a = 'http-equiv'; @@ -3233,7 +3214,7 @@ $templates foreach ( $variants as $_v ) { $tags["variant-$_v"] = Html::element( 'link', array( 'rel' => 'alternate', - 'hreflang' => $_v, + 'hreflang' => wfBCP47( $_v ), 'href' => $this->getTitle()->getLocalURL( array( 'variant' => $_v ) ) ) ); } @@ -3266,7 +3247,7 @@ $templates # Feeds if ( $wgFeed ) { - foreach( $this->getSyndicationLinks() as $format => $link ) { + foreach ( $this->getSyndicationLinks() as $format => $link ) { # Use the page name for the title. 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 @@ -3301,7 +3282,7 @@ $templates foreach ( $wgAdvertisedFeedTypes as $format ) { $tags[] = $this->feedLink( $format, - $rctitle->getLocalURL( "feed={$format}" ), + $rctitle->getLocalURL( array( 'feed' => $format ) ), $this->msg( "site-{$format}-feed", $wgSitename )->text() # For grep: 'site-rss-feed', 'site-atom-feed'. ); } @@ -3329,13 +3310,10 @@ $templates } /** - * @param $unused - * @param bool $addContentType Whether "<meta>" specifying content type should be returned - * * @return string HTML tag links to be put in the header. */ - public function getHeadLinks( $unused = null, $addContentType = false ) { - return implode( "\n", $this->getHeadLinksArray( $addContentType ) ); + public function getHeadLinks() { + return implode( "\n", $this->getHeadLinksArray() ); } /** @@ -3368,13 +3346,13 @@ $templates $options = array(); // Even though we expect the media type to be lowercase, but here we // force it to lowercase to be safe. - if( $media ) { + if ( $media ) { $options['media'] = $media; } - if( $condition ) { + if ( $condition ) { $options['condition'] = $condition; } - if( $dir ) { + if ( $dir ) { $options['dir'] = $dir; } $this->styles[$style] = $options; @@ -3386,7 +3364,7 @@ $templates * @param string $flip Set to 'flip' to flip the CSS if needed */ public function addInlineStyle( $style_css, $flip = 'noflip' ) { - if( $flip === 'flip' && $this->getLanguage()->isRTL() ) { + if ( $flip === 'flip' && $this->getLanguage()->isRTL() ) { # If wanted, and the interface is right-to-left, flip the CSS $style_css = CSSJanus::transform( $style_css, true, false ); } @@ -3416,7 +3394,7 @@ $templates if ( $wgUseSiteCss ) { $moduleStyles[] = 'site'; $moduleStyles[] = 'noscript'; - if( $this->getUser()->isLoggedIn() ) { + if ( $this->getUser()->isLoggedIn() ) { $moduleStyles[] = 'user.groups'; } } @@ -3497,9 +3475,9 @@ $templates } $this->mExtStyles = array(); - foreach( $this->styles as $file => $options ) { + foreach ( $this->styles as $file => $options ) { $link = $this->styleLink( $file, $options ); - if( $link ) { + if ( $link ) { $links[$file] = $link; } } @@ -3515,22 +3493,22 @@ $templates * @return String: HTML fragment */ protected function styleLink( $style, $options ) { - if( isset( $options['dir'] ) ) { - if( $this->getLanguage()->getDir() != $options['dir'] ) { + if ( isset( $options['dir'] ) ) { + if ( $this->getLanguage()->getDir() != $options['dir'] ) { return ''; } } - if( isset( $options['media'] ) ) { + if ( isset( $options['media'] ) ) { $media = self::transformCssMedia( $options['media'] ); - if( is_null( $media ) ) { + if ( is_null( $media ) ) { return ''; } } else { $media = 'all'; } - if( substr( $style, 0, 1 ) == '/' || + if ( substr( $style, 0, 1 ) == '/' || substr( $style, 0, 5 ) == 'http:' || substr( $style, 0, 6 ) == 'https:' ) { $url = $style; @@ -3541,7 +3519,7 @@ $templates $link = Html::linkedStyle( $url, $media ); - if( isset( $options['condition'] ) ) { + if ( isset( $options['condition'] ) ) { $condition = htmlspecialchars( $options['condition'] ); $link = "<!--[if $condition]>$link<![endif]-->"; } @@ -3556,7 +3534,7 @@ $templates * this stylesheet */ public static function transformCssMedia( $media ) { - global $wgRequest, $wgHandheldForIPhone; + global $wgRequest; // http://www.w3.org/TR/css3-mediaqueries/#syntax $screenMediaQueryRegex = '/^(?:only\s+)?screen\b/i'; @@ -3566,11 +3544,11 @@ $templates 'printable' => 'print', 'handheld' => 'handheld', ); - foreach( $switches as $switch => $targetMedia ) { - if( $wgRequest->getBool( $switch ) ) { - if( $media == $targetMedia ) { + foreach ( $switches as $switch => $targetMedia ) { + if ( $wgRequest->getBool( $switch ) ) { + if ( $media == $targetMedia ) { $media = ''; - } elseif( preg_match( $screenMediaQueryRegex, $media ) === 1 ) { + } elseif ( preg_match( $screenMediaQueryRegex, $media ) === 1 ) { // This regex will not attempt to understand a comma-separated media_query_list // // Example supported values for $media: 'screen', 'only screen', 'screen and (min-width: 982px)' ), @@ -3581,25 +3559,13 @@ $templates // we don't want simple 'screen' but we might want screen queries that // have a max-width or something, so we'll pass all others on and let the // client do the query. - if( $targetMedia == 'print' || $media == 'screen' ) { + if ( $targetMedia == 'print' || $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; } @@ -3688,4 +3654,20 @@ $templates return array(); } + /** + * Enables/disables TOC, doesn't override __NOTOC__ + * @param bool $flag + * @since 1.22 + */ + public function enableTOC( $flag = true ) { + $this->mEnableTOC = $flag; + } + + /** + * @return bool + * @since 1.22 + */ + public function isTOCEnabled() { + return $this->mEnableTOC; + } } |