protected $mStatusCode;
/**
- * @ var string mLastModified and mEtag are used for sending cache control.
+ * @var string Variable mLastModified and mEtag are used for sending cache control.
* The whole caching system should probably be moved into its own class.
*/
protected $mLastModified = '';
* Add a new "<meta>" tag
* To add an http-equiv meta tag, precede the name with "http:"
*
- * @param string $name tag name
- * @param string $val tag value
+ * @param string $name Tag name
+ * @param string $val Tag value
*/
function addMeta( $name, $val ) {
array_push( $this->mMetatags, array( $name, $val ) );
*
* Note: use setCanonicalUrl() for rel=canonical.
*
- * @param array $linkarr associative array of attributes.
+ * @param array $linkarr Associative array of attributes.
*/
function addLink( $linkarr ) {
array_push( $this->mLinktags, $linkarr );
/**
* Add a new \<link\> with "rel" attribute set to "meta"
*
- * @param array $linkarr associative array mapping attribute names to their
+ * @param array $linkarr Associative array mapping attribute names to their
* values, both keys and values will be escaped, and the
* "rel" attribute will be automatically added
*/
/**
* Add raw HTML to the list of scripts (including \<script\> tag, etc.)
*
- * @param string $script raw HTML
+ * @param string $script Raw HTML
*/
function addScript( $script ) {
$this->mScripts .= $script . "\n";
/**
* Register and add a stylesheet from an extension directory.
*
- * @param string $url path to sheet. Provide either a full url (beginning
+ * @param string $url Path to sheet. Provide either a full url (beginning
* with 'http', etc) or a relative path from the document root
* (beginning with '/'). Otherwise it behaves identically to
* addStyle() and draws from the /skins folder.
/**
* Add a JavaScript file out of skins/common, or a given relative path.
*
- * @param string $file filename in skins/common or complete on-server path
+ * @param string $file Filename in skins/common or complete on-server path
* (/foo/bar.js)
- * @param string $version style version of the file. Defaults to $wgStyleVersion
+ * @param string $version Style version of the file. Defaults to $wgStyleVersion
*/
public function addScriptFile( $file, $version = null ) {
global $wgStylePath, $wgStyleVersion;
* Filter an array of modules to remove insufficiently trustworthy members, and modules
* which are no longer registered (eg a page is cached before an extension is disabled)
* @param array $modules
- * @param string|null $position if not null, only return modules with this position
+ * @param string|null $position If not null, only return modules with this position
* @param string $type
* @return array
*/
/**
* Add or replace an header item to the output
*
- * @param string $name item name
- * @param string $value raw HTML
+ * @param string $name Item name
+ * @param string $value Raw HTML
*/
public function addHeadItem( $name, $value ) {
$this->mHeadItems[$name] = $value;
/**
* Set the value of the ETag HTTP header, only used if $wgUseETag is true
*
- * @param string $tag value of "ETag" header
+ * @param string $tag Value of "ETag" header
*/
function setETag( $tag ) {
$this->mETag = $tag;
/**
* Override the last modified timestamp
*
- * @param string $timestamp new timestamp, in a format readable by
+ * @param string $timestamp New timestamp, in a format readable by
* wfTimestamp()
*/
public function setLastModified( $timestamp ) {
/**
* Set the robot policy for the page: <http://www.robotstxt.org/meta.html>
*
- * @param string $policy the literal string to output as the contents of
+ * @param string $policy The literal string to output as the contents of
* the meta tag. Will be parsed according to the spec and output in
* standardized form.
* @return null
* Set the follow policy for the page, but leave the index policy un-
* touched.
*
- * @param string $policy either 'follow' or 'nofollow'.
+ * @param string $policy Either 'follow' or 'nofollow'.
* @return null
*/
public function setFollowPolicy( $policy ) {
* Set the new value of the "action text", this will be added to the
* "HTML title", separated from it with " - ".
*
- * @param string $text new value of the "action text"
+ * @param string $text New value of the "action text"
*/
public function setPageTitleActionText( $text ) {
$this->mPageTitleActionText = $text;
* "HTML title" means the contents of "<title>".
* It is stored as plain, unescaped text and will be run through htmlspecialchars in the skin file.
*
- * @param string $name
+ * @param string|Message $name
*/
public function setHTMLTitle( $name ) {
if ( $name instanceof Message ) {
/**
* Replace the subtitle with $str
*
- * @param string|Message $str new value of the subtitle. String should be safe HTML.
+ * @param string|Message $str New value of the subtitle. String should be safe HTML.
*/
public function setSubtitle( $str ) {
$this->clearSubtitle();
* Add $str to the subtitle
*
* @deprecated since 1.19; use addSubtitle() instead
- * @param string|Message $str to add to the subtitle
+ * @param string|Message $str String or Message to add to the subtitle
*/
public function appendSubtitle( $str ) {
$this->addSubtitle( $str );
/**
* Add $str to the subtitle
*
- * @param string|Message $str to add to the subtitle. String should be safe HTML.
+ * @param string|Message $str String or Message to add to the subtitle. String should be safe HTML.
*/
public function addSubtitle( $str ) {
if ( $str instanceof Message ) {
* for the new version
* @see addFeedLink()
*
- * @param bool $show true: add default feeds, false: remove all feeds
+ * @param bool $show True: add default feeds, false: remove all feeds
*/
public function setSyndicated( $show = true ) {
if ( $show ) {
* for the new version
* @see addFeedLink()
*
- * @param string $val query to append to feed links or false to output
+ * @param string $val Query to append to feed links or false to output
* default links
*/
public function setFeedAppendQuery( $val ) {
/**
* Add a feed link to the page header
*
- * @param string $format feed type, should be a key of $wgFeedClasses
+ * @param string $format Feed type, should be a key of $wgFeedClasses
* @param string $href URL
*/
public function addFeedLink( $format, $href ) {
/**
* Return URLs for each supported syndication format for this page.
- * @return array associating format keys with URLs
+ * @return array Associating format keys with URLs
*/
public function getSyndicationLinks() {
return $this->mFeedLinks;
/**
* Add an array of categories, with names in the keys
*
- * @param array $categories mapping category name => sort key
+ * @param array $categories Mapping category name => sort key
*/
public function addCategoryLinks( $categories ) {
global $wgContLang;
# Add the results to the link cache
$lb->addResultToCache( LinkCache::singleton(), $res );
- # Set all the values to 'normal'. This can be done with array_fill_keys in PHP 5.2.0+
- $categories = array_combine(
- array_keys( $categories ),
- array_fill( 0, count( $categories ), 'normal' )
- );
+ # Set all the values to 'normal'.
+ $categories = array_fill_keys( array_keys( $categories ), 'normal' );
# Mark hidden categories
foreach ( $res as $row ) {
foreach ( $categories as $category => $type ) {
$origcategory = $category;
$title = Title::makeTitleSafe( NS_CATEGORY, $category );
+ if ( !$title ) {
+ continue;
+ }
$wgContLang->findVariantLink( $category, $title, true );
- if ( $category != $origcategory ) {
- if ( array_key_exists( $category, $categories ) ) {
- continue;
- }
+ if ( $category != $origcategory && array_key_exists( $category, $categories ) ) {
+ continue;
}
$text = $wgContLang->convertHtml( $title->getText() );
$this->mCategories[] = $title->getText();
/**
* Reset the category links (but not the category list) and add $categories
*
- * @param array $categories mapping category name => sort key
+ * @param array $categories Mapping category name => sort key
*/
public function setCategoryLinks( $categories ) {
$this->mCategoryLinks = array();
$this->addModuleStyles( $parserOutput->getModuleStyles() );
$this->addModuleMessages( $parserOutput->getModuleMessages() );
$this->addJsConfigVars( $parserOutput->getJsConfigVars() );
+ $this->mPreventClickjacking = $this->mPreventClickjacking
+ || $parserOutput->preventClickjacking();
// Template versioning...
foreach ( (array)$parserOutput->getTemplateIds() as $ns => $dbks ) {
/**
* Add an HTTP header that will influence on the cache
*
- * @param string $header header name
+ * @param string $header Header name
* @param array|null $option
* @todo FIXME: Document the $option parameter; it appears to be for
* X-Vary-Options but what format is acceptable?
$this->mPreventClickjacking = false;
}
+ /**
+ * Get the prevent-clickjacking flag
+ *
+ * @since 1.24
+ * @return boolean
+ */
+ public function getPreventClickjacking() {
+ return $this->mPreventClickjacking;
+ }
+
/**
* Get the X-Frame-Options header value (without the name part), or false
* if there isn't one. This is used by Skin to determine whether to enable
/**
* Actually output something with print.
*
- * @param string $ins the string to output
+ * @param string $ins The string to output
* @deprecated since 1.22 Use echo yourself.
*/
public function out( $ins ) {
* indexing, clear the current text and redirect, set the page's title
* and optionally an custom HTML title (content of the "<title>" tag).
*
- * @param string|Message $pageTitle will be passed directly to setPageTitle()
- * @param string|Message $htmlTitle will be passed directly to setHTMLTitle();
+ * @param string|Message $pageTitle Will be passed directly to setPageTitle()
+ * @param string|Message $htmlTitle Will be passed directly to setHTMLTitle();
* optional, if not passed the "<title>" attribute will be
* based on $pageTitle
*/
/**
* Output a standard permission error page
*
- * @param array $errors error message keys
- * @param string $action action that was denied or null if unknown
+ * @param array $errors Error message keys
+ * @param string $action Action that was denied or null if unknown
*/
public function showPermissionsErrorPage( $errors, $action = null ) {
// For some action (read, edit, create and upload), display a "login to do this action"
/**
* Display an error page noting that a given permission bit is required.
* @deprecated since 1.18, just throw the exception directly
- * @param string $permission key required
+ * @param string $permission Key required
* @throws PermissionsError
*/
public function permissionRequired( $permission ) {
$extraQuery['target'] = $this->mTarget;
}
- // Create keyed-by-group list of module objects from modules list
- $groups = array();
+ // Create keyed-by-source and then keyed-by-group list of module objects from modules list
+ $sortedModules = array();
$resourceLoader = $this->getResourceLoader();
foreach ( $modules as $name ) {
$module = $resourceLoader->getModule( $name );
&& $only == ResourceLoaderModule::TYPE_SCRIPTS )
|| ( $module->getOrigin() > $this->getAllowedModules( ResourceLoaderModule::TYPE_STYLES )
&& $only == ResourceLoaderModule::TYPE_STYLES )
+ || ( $module->getOrigin() > $this->getAllowedModules( ResourceLoaderModule::TYPE_COMBINED )
+ && $only == ResourceLoaderModule::TYPE_COMBINED )
|| ( $this->mTarget && !in_array( $this->mTarget, $module->getTargets() ) )
) {
continue;
}
- $group = $module->getGroup();
- if ( !isset( $groups[$group] ) ) {
- $groups[$group] = array();
- }
- $groups[$group][$name] = $module;
+ $sortedModules[$module->getSource()][$module->getGroup()][$name] = $module;
}
- foreach ( $groups as $group => $grpModules ) {
- // Special handling for user-specific groups
- $user = null;
- if ( ( $group === 'user' || $group === 'private' ) && $this->getUser()->isLoggedIn() ) {
- $user = $this->getUser()->getName();
- }
+ foreach ( $sortedModules as $source => $groups ) {
+ foreach ( $groups as $group => $grpModules ) {
+ // Special handling for user-specific groups
+ $user = null;
+ if ( ( $group === 'user' || $group === 'private' ) && $this->getUser()->isLoggedIn() ) {
+ $user = $this->getUser()->getName();
+ }
- // Create a fake request based on the one we are about to make so modules return
- // correct timestamp and emptiness data
- $query = ResourceLoader::makeLoaderQuery(
- array(), // modules; not determined yet
- $this->getLanguage()->getCode(),
- $this->getSkin()->getSkinName(),
- $user,
- null, // version; not determined yet
- ResourceLoader::inDebugMode(),
- $only === ResourceLoaderModule::TYPE_COMBINED ? null : $only,
- $this->isPrintable(),
- $this->getRequest()->getBool( 'handheld' ),
- $extraQuery
- );
- $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
-
- // Extract modules that know they're empty
- foreach ( $grpModules as $key => $module ) {
- // Inline empty modules: since they're empty, just mark them as 'ready' (bug 46857)
- // If we're only getting the styles, we don't need to do anything for empty modules.
- if ( $module->isKnownEmpty( $context ) ) {
- unset( $grpModules[$key] );
- if ( $only !== ResourceLoaderModule::TYPE_STYLES ) {
- $links['states'][$key] = 'ready';
+ // Create a fake request based on the one we are about to make so modules return
+ // correct timestamp and emptiness data
+ $query = ResourceLoader::makeLoaderQuery(
+ array(), // modules; not determined yet
+ $this->getLanguage()->getCode(),
+ $this->getSkin()->getSkinName(),
+ $user,
+ null, // version; not determined yet
+ ResourceLoader::inDebugMode(),
+ $only === ResourceLoaderModule::TYPE_COMBINED ? null : $only,
+ $this->isPrintable(),
+ $this->getRequest()->getBool( 'handheld' ),
+ $extraQuery
+ );
+ $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
+
+ // Extract modules that know they're empty
+ foreach ( $grpModules as $key => $module ) {
+ // Inline empty modules: since they're empty, just mark them as 'ready' (bug 46857)
+ // If we're only getting the styles, we don't need to do anything for empty modules.
+ if ( $module->isKnownEmpty( $context ) ) {
+ unset( $grpModules[$key] );
+ if ( $only !== ResourceLoaderModule::TYPE_STYLES ) {
+ $links['states'][$key] = 'ready';
+ }
}
}
- }
- // If there are no non-empty modules, skip this group
- if ( count( $grpModules ) === 0 ) {
- continue;
- }
+ // If there are no non-empty modules, skip this group
+ if ( count( $grpModules ) === 0 ) {
+ continue;
+ }
- // Inline private modules. These can't be loaded through load.php for security
- // reasons, see bug 34907. Note that these modules should be loaded from
- // getHeadScripts() before the first loader call. Otherwise other modules can't
- // properly use them as dependencies (bug 30914)
- if ( $group === 'private' ) {
- if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
- $links['html'] .= Html::inlineStyle(
- $resourceLoader->makeModuleResponse( $context, $grpModules )
- );
- } else {
- $links['html'] .= Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
+ // Inline private modules. These can't be loaded through load.php for security
+ // reasons, see bug 34907. Note that these modules should be loaded from
+ // getHeadScripts() before the first loader call. Otherwise other modules can't
+ // properly use them as dependencies (bug 30914)
+ if ( $group === 'private' ) {
+ if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
+ $links['html'] .= Html::inlineStyle(
$resourceLoader->makeModuleResponse( $context, $grpModules )
- )
- );
+ );
+ } else {
+ $links['html'] .= Html::inlineScript(
+ ResourceLoader::makeLoaderConditionalScript(
+ $resourceLoader->makeModuleResponse( $context, $grpModules )
+ )
+ );
+ }
+ $links['html'] .= "\n";
+ continue;
}
- $links['html'] .= "\n";
- continue;
- }
- // Special handling for the user group; because users might change their stuff
- // on-wiki like user pages, or user preferences; we need to find the highest
- // timestamp of these user-changeable modules so we can ensure cache misses on change
- // This should NOT be done for the site group (bug 27564) because anons get that too
- // and we shouldn't be putting timestamps in Squid-cached HTML
- $version = null;
- if ( $group === 'user' ) {
- // Get the maximum timestamp
- $timestamp = 1;
- foreach ( $grpModules as $module ) {
- $timestamp = max( $timestamp, $module->getModifiedTime( $context ) );
+ // Special handling for the user group; because users might change their stuff
+ // on-wiki like user pages, or user preferences; we need to find the highest
+ // timestamp of these user-changeable modules so we can ensure cache misses on change
+ // This should NOT be done for the site group (bug 27564) because anons get that too
+ // and we shouldn't be putting timestamps in Squid-cached HTML
+ $version = null;
+ if ( $group === 'user' ) {
+ // Get the maximum timestamp
+ $timestamp = 1;
+ foreach ( $grpModules as $module ) {
+ $timestamp = max( $timestamp, $module->getModifiedTime( $context ) );
+ }
+ // Add a version parameter so cache will break when things change
+ $query['version'] = wfTimestamp( TS_ISO_8601_BASIC, $timestamp );
}
- // Add a version parameter so cache will break when things change
- $version = wfTimestamp( TS_ISO_8601_BASIC, $timestamp );
- }
- $url = ResourceLoader::makeLoaderURL(
- array_keys( $grpModules ),
- $this->getLanguage()->getCode(),
- $this->getSkin()->getSkinName(),
- $user,
- $version,
- ResourceLoader::inDebugMode(),
- $only === ResourceLoaderModule::TYPE_COMBINED ? null : $only,
- $this->isPrintable(),
- $this->getRequest()->getBool( 'handheld' ),
- $extraQuery
- );
- if ( $useESI && $wgResourceLoaderUseESI ) {
- $esi = Xml::element( 'esi:include', array( 'src' => $url ) );
- if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
- $link = Html::inlineStyle( $esi );
- } else {
- $link = Html::inlineScript( $esi );
- }
- } else {
- // Automatically select style/script elements
- if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
- $link = Html::linkedStyle( $url );
- } elseif ( $loadCall ) {
- $link = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) )
- )
- );
+ $query['modules'] = ResourceLoader::makePackedModulesString( array_keys( $grpModules ) );
+ $moduleContext = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
+ $url = $resourceLoader->createLoaderURL( $source, $moduleContext, $extraQuery );
+
+ if ( $useESI && $wgResourceLoaderUseESI ) {
+ $esi = Xml::element( 'esi:include', array( 'src' => $url ) );
+ if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
+ $link = Html::inlineStyle( $esi );
+ } else {
+ $link = Html::inlineScript( $esi );
+ }
} else {
- $link = Html::linkedScript( $url );
-
- // For modules requested directly in the html via <link> or <script>,
- // tell mw.loader they are being loading to prevent duplicate requests.
- foreach ( $grpModules as $key => $module ) {
- // Don't output state=loading for the startup module..
- if ( $key !== 'startup' ) {
- $links['states'][$key] = 'loading';
+ // Automatically select style/script elements
+ if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
+ $link = Html::linkedStyle( $url );
+ } elseif ( $loadCall ) {
+ $link = Html::inlineScript(
+ ResourceLoader::makeLoaderConditionalScript(
+ Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) )
+ )
+ );
+ } else {
+ $link = Html::linkedScript( $url );
+
+ // For modules requested directly in the html via <link> or <script>,
+ // tell mw.loader they are being loading to prevent duplicate requests.
+ foreach ( $grpModules as $key => $module ) {
+ // Don't output state=loading for the startup module..
+ if ( $key !== 'startup' ) {
+ $links['states'][$key] = 'loading';
+ }
}
}
}
- }
- if ( $group == 'noscript' ) {
- $links['html'] .= Html::rawElement( 'noscript', array(), $link ) . "\n";
- } else {
- $links['html'] .= $link . "\n";
+ if ( $group == 'noscript' ) {
+ $links['html'] .= Html::rawElement( 'noscript', array(), $link ) . "\n";
+ } else {
+ $links['html'] .= $link . "\n";
+ }
}
}
* @return string
*/
function getScriptsForBottomQueue( $inHead ) {
- global $wgUseSiteJs, $wgAllowUserJs;
+ global $wgAllowUserJs;
// Scripts and messages "only" requests marked for bottom inclusion
// If we're in the <head>, use load() calls rather than <script src="..."> tags
}
/**
- * @return array in format "link name or number => 'link html'".
+ * @return array Array in format "link name or number => 'link html'".
*/
public function getHeadLinksArray() {
global $wgUniversalEditButton, $wgFavicon, $wgAppleTouchIcon, $wgEnableAPI,
* Meant primarily for internal use...
*
* @param string $style URL to the file
- * @param string $media to specify a media type, 'screen', 'printable', 'handheld' or any.
- * @param string $condition for IE conditional comments, specifying an IE version
- * @param string $dir set to 'rtl' or 'ltr' for direction-specific sheets
+ * @param string $media To specify a media type, 'screen', 'printable', 'handheld' or any.
+ * @param string $condition For IE conditional comments, specifying an IE version
+ * @param string $dir Set to 'rtl' or 'ltr' for direction-specific sheets
*/
public function addStyle( $style, $media = '', $condition = '', $dir = '' ) {
$options = array();
* @return string
*/
public function buildCssLinks() {
- global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs, $wgContLang;
+ global $wgAllowUserCss, $wgContLang;
$this->getSkin()->setupSkinUserCss( $this );
$group = $module->getGroup();
// Modules in groups different than the ones listed on top (see $styles assignment)
// will be placed in the "other" group
- $styles[ isset( $styles[$group] ) ? $group : 'other' ][] = $name;
+ $styles[isset( $styles[$group] ) ? $group : 'other'][] = $name;
}
// We want site, private and user styles to override dynamically added