private $mProperties = array();
/**
- * @var string|null: ResourceLoader target for load.php links. If null, will be omitted
+ * @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
+ * @var bool Whether parser output should contain table of contents
*/
private $mEnableTOC = true;
+ /**
+ * @var bool Whether parser output should contain section edit links
+ */
+ private $mEnableSectionEditLinks = true;
+
/**
* Constructor for OutputPage. This should not be called directly.
* Instead a new RequestContext should be created and it will implicitly create
* through this function will be loaded by the resource loader when the
* page loads.
*
- * @param $modules Mixed: module name (string) or array of module names
+ * @param string|array $modules Module name (string) or array of module names
*/
public function addModules( $modules ) {
$this->mModules = array_merge( $this->mModules, (array)$modules );
* scripts added through this function will be loaded by the resource loader when
* the page loads.
*
- * @param $modules Mixed: module name (string) or array of module names
+ * @param string|array $modules Module name (string) or array of module names
*/
public function addModuleScripts( $modules ) {
$this->mModuleScripts = array_merge( $this->mModuleScripts, (array)$modules );
* tags, rather than as a combined Javascript and CSS package. Thus, they will
* load when JavaScript is disabled (unless CSS also happens to be disabled).
*
- * @param $modules Mixed: module name (string) or array of module names
+ * @param string|array $modules Module name (string) or array of module names
*/
public function addModuleStyles( $modules ) {
$this->mModuleStyles = array_merge( $this->mModuleStyles, (array)$modules );
* Module messages added through this function will be loaded by the resource
* loader when the page loads.
*
- * @param $modules Mixed: module name (string) or array of module names
+ * @param string|array $modules Module name (string) or array of module names
*/
public function addModuleMessages( $modules ) {
$this->mModuleMessages = array_merge( $this->mModuleMessages, (array)$modules );
}
/**
- * @return null|string: ResourceLoader target
+ * @return null|string ResourceLoader target
*/
public function getTarget() {
return $this->mTarget;
* without any skin, sidebar, etc.
* Used e.g. when calling with "action=render".
*
- * @param $only Boolean: whether to output only the body of the article
+ * @param bool $only Whether to output only the body of the article
*/
public function setArticleBodyOnly( $only ) {
$this->mArticleBodyOnly = $only;
* Get an additional output property
* @since 1.21
*
- * @param $name
- * @return mixed: Property value or null if not found
+ * @param string $name
+ * @return mixed Property value or null if not found
*/
public function getProperty( $name ) {
if ( isset( $this->mProperties[$name] ) ) {
*
* Side effect: sets mLastModified for Last-Modified header
*
- * @param $timestamp string
+ * @param string $timestamp
*
- * @return Boolean: true if cache-ok headers was sent.
+ * @return bool True if cache-ok headers was sent.
*/
public function checkLastModified( $timestamp ) {
global $wgCachePages, $wgCacheEpoch, $wgUseSquid, $wgSquidMaxage;
* for the new version
* @see addFeedLink()
*
- * @param $show Boolean: 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 ) {
/**
* Set the highest level of CSS/JS untrustworthiness allowed
- * @param $type String ResourceLoaderModule TYPE_ constant
- * @param $level Int ResourceLoaderModule class constant
+ * @param $type String ResourceLoaderModule TYPE_ constant
+ * @param $level Int ResourceLoaderModule class constant
*/
public function setAllowedModules( $type, $level ) {
$this->mAllowedModules[$type] = $level;
/**
* As for setAllowedModules(), but don't inadvertently make the page more accessible
- * @param $type String
- * @param $level Int ResourceLoaderModule class constant
+ * @param $type String
+ * @param $level Int ResourceLoaderModule class constant
*/
public function reduceAllowedModules( $type, $level ) {
$this->mAllowedModules[$type] = min( $this->getAllowedModules( $type ), $level );
/**
* Get the body HTML
*
- * @return String: HTML
+ * @return string HTML
*/
public function getHTML() {
return $this->mBodytext;
* Set the revision ID which will be seen by the wiki text parser
* for things such as embedded {{REVISIONID}} variable use.
*
- * @param $revid Mixed: an positive integer, or null
- * @return Mixed: previous value
+ * @param int|null $revid An positive integer, or null
+ * @return mixed Previous value
*/
public function setRevisionId( $revid ) {
$val = is_null( $revid ) ? null : intval( $revid );
* Set the timestamp of the revision which will be displayed. This is used
* to avoid a extra DB call in Skin::lastModified().
*
- * @param $timestamp Mixed: string, or null
- * @return Mixed: previous value
+ * @param string|null $timestamp
+ * @return mixed Previous value
*/
public function setRevisionTimestamp( $timestamp ) {
return wfSetVar( $this->mRevisionTimestamp, $timestamp );
/**
* Set the displayed file version
*
- * @param $file File|bool
- * @return Mixed: previous value
+ * @param File|bool $file
+ * @return mixed Previous value
*/
public function setFileVersion( $file ) {
$val = null;
* Convert wikitext to HTML and add it to the buffer
* Default assumes that the current page title will be used.
*
- * @param $text String
- * @param $linestart Boolean: is this the start of a line?
- * @param $interface Boolean: is this text in the user interface language?
+ * @param string $text
+ * @param bool $linestart Is this the start of a line?
+ * @param bool $interface Is this text in the user interface language?
*/
public function addWikiText( $text, $linestart = true, $interface = true ) {
$title = $this->getTitle(); // Work around E_STRICT
/**
* Add wikitext with a custom Title object
*
- * @param string $text wikitext
- * @param $title Title object
- * @param $linestart Boolean: is this the start of a line?
+ * @param string $text Wikitext
+ * @param Title $title
+ * @param bool $linestart Is this the start of a line?
*/
public function addWikiTextWithTitle( $text, &$title, $linestart = true ) {
$this->addWikiTextTitle( $text, $title, $linestart );
/**
* Add wikitext with a custom Title object and tidy enabled.
*
- * @param string $text wikitext
- * @param $title Title object
- * @param $linestart Boolean: is this the start of a line?
+ * @param string $text Wikitext
+ * @param Title $title
+ * @param bool $linestart Is this the start of a line?
*/
function addWikiTextTitleTidy( $text, &$title, $linestart = true ) {
$this->addWikiTextTitle( $text, $title, $linestart, true );
/**
* Add wikitext with tidy enabled
*
- * @param string $text wikitext
- * @param $linestart Boolean: is this the start of a line?
+ * @param string $text Wikitext
+ * @param bool $linestart Is this the start of a line?
*/
public function addWikiTextTidy( $text, $linestart = true ) {
$title = $this->getTitle();
/**
* Add wikitext with a custom Title object
*
- * @param string $text wikitext
- * @param $title Title object
- * @param $linestart Boolean: is this the start of a line?
- * @param $tidy Boolean: whether to use tidy
- * @param $interface Boolean: whether it is an interface message
- * (for example disables conversion)
+ * @param string $text Wikitext
+ * @param Title $title
+ * @param bool $linestart Is this the start of a line?
+ * @param bool $tidy Whether to use tidy
+ * @param bool $interface Whether it is an interface message
+ * (for example disables conversion)
*/
public function addWikiTextTitle( $text, Title $title, $linestart, $tidy = false, $interface = false ) {
global $wgParser;
function addParserOutput( &$parserOutput ) {
$this->addParserOutputNoText( $parserOutput );
$parserOutput->setTOCEnabled( $this->mEnableTOC );
+
+ // Touch section edit links only if not previously disabled
+ if ( $parserOutput->getEditSectionTokens() ) {
+ $parserOutput->setEditSectionTokens( $this->mEnableSectionEditLinks );
+ }
$text = $parserOutput->getText();
wfRunHooks( 'OutputPageBeforeHTML', array( &$this, &$text ) );
$this->addHTML( $text );
/**
* Parse wikitext and return the HTML.
*
- * @param $text String
- * @param $linestart Boolean: is this the start of a line?
- * @param $interface Boolean: use interface language ($wgLang instead of
- * $wgContLang) while parsing language sensitive magic
- * words like GRAMMAR and PLURAL. This also disables
- * LanguageConverter.
- * @param $language Language object: target language object, will override
- * $interface
+ * @param String $text
+ * @param bool $linestart Is this the start of a line?
+ * @param bool $interface Use interface language ($wgLang instead of
+ * $wgContLang) while parsing language sensitive magic words like GRAMMAR and PLURAL.
+ * This also disables LanguageConverter.
+ * @param Language $language Target language object, will override $interface
* @throws MWException
- * @return String: HTML
+ * @return string HTML
*/
public function parse( $text, $linestart = true, $interface = false, $language = null ) {
global $wgParser;
/**
* Parse wikitext, strip paragraphs, and return the HTML.
*
- * @param $text String
- * @param $linestart Boolean: is this the start of a line?
- * @param $interface Boolean: use interface language ($wgLang instead of
- * $wgContLang) while parsing language sensitive magic
- * words like GRAMMAR and PLURAL
- * @return String: HTML
+ * @param string $text
+ * @param bool $linestart Is this the start of a line?
+ * @param bool $interface Use interface language ($wgLang instead of
+ * $wgContLang) while parsing language sensitive magic
+ * words like GRAMMAR and PLURAL
+ * @return string HTML
*/
public function parseInline( $text, $linestart = true, $interface = false ) {
$parsed = $this->parse( $text, $linestart, $interface );
/**
* Set the value of the "s-maxage" part of the "Cache-control" HTTP header
*
- * @param $maxage Integer: maximum cache time on the Squid, in seconds.
+ * @param int $maxage Maximum cache time on the Squid, in seconds.
*/
public function setSquidMaxage( $maxage ) {
$this->mSquidMaxage = $maxage;
/**
* Get the message associated with the HTTP response code $code
*
- * @param $code Integer: status code
- * @return String or null: message or null if $code is not in the list of
- * messages
+ * @param int $code Status code
+ * @return string|null Message or null if $code is not in the list of messages
*
* @deprecated since 1.18 Use HttpStatus::getMessage() instead.
*/
* showErrorPage( 'titlemsg', $messageObject );
* showErrorPage( $titleMessageObject, $messageObject );
*
- * @param $title Mixed: message key (string) for page title, or a Message object
- * @param $msg Mixed: message key (string) for page text, or a Message object
- * @param array $params message parameters; ignored if $msg is a Message object
+ * @param string|Message $title Message key (string) for page title, or a Message object
+ * @param string|Message $msg Message key (string) for page text, or a Message object
+ * @param array $params Message parameters; ignored if $msg is a Message object
*/
public function showErrorPage( $title, $msg, $params = array() ) {
if ( !$title instanceof Message ) {
* Display an error page indicating that a given version of MediaWiki is
* required to use it
*
- * @param $version Mixed: the version of MediaWiki needed to use the page
+ * @param mixed $version The version of MediaWiki needed to use the page
*/
public function versionRequired( $version ) {
$this->prepareErrorPage( $this->msg( 'versionrequired', $version ) );
/**
* Format a list of error messages
*
- * @param array $errors of arrays returned by Title::getUserPermissionsErrors
- * @param string $action action that was denied or null if unknown
- * @return String: the wikitext error-messages, formatted into a list.
+ * @param array $errors Array of arrays returned by Title::getUserPermissionsErrors
+ * @param string $action Action that was denied or null if unknown
+ * @return string The wikitext error-messages, formatted into a list.
*/
public function formatPermissionsErrorMessage( $errors, $action = null ) {
if ( $action == null ) {
*
* @todo Needs to be split into multiple functions.
*
- * @param $source String: source code to show (or null).
- * @param $protected Boolean: is this a permissions error?
- * @param $reasons Array: list of reasons for this error, as returned by Title::getUserPermissionsErrors().
- * @param $action String: action that was denied or null if unknown
+ * @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().
+ * @param string $action Action that was denied or null if unknown
* @throws ReadOnlyError
*/
public function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) {
* then the warning is a bit more obvious. If the lag is
* lower than $wgSlaveLagWarning, then no warning is shown.
*
- * @param $lag Integer: slave lag
+ * @param int $lag Slave lag
*/
public function showLagWarning( $lag ) {
global $wgSlaveLagWarning, $wgSlaveLagCritical;
}
/**
- * @param $sk Skin The given Skin
- * @param $includeStyle Boolean: unused
- * @return String: The doctype, opening "<html>", and head element.
+ * @param Skin $sk The given Skin
+ * @param bool $includeStyle Unused
+ * @return string The doctype, opening "<html>", and head element.
*/
public function headElement( Skin $sk, $includeStyle = true ) {
global $wgContLang, $wgMimeType;
// jQuery can work correctly.
$ret .= Html::element( 'meta', array( 'http-equiv' => 'X-UA-Compatible', 'content' => 'IE=EDGE' ) ) . "\n";
- $ret .= implode( "\n", array(
- $this->getHeadLinks(),
- $this->buildCssLinks(),
- $this->getHeadScripts(),
+ $ret .= (
+ $this->getHeadLinks() .
+ "\n" .
+ $this->buildCssLinks() .
+ // No newline after buildCssLinks since makeResourceLoaderLink did that already
+ $this->getHeadScripts() .
+ "\n" .
$this->getHeadItems()
- ) );
+ );
$closeHead = Html::closeElement( 'head' );
if ( $closeHead ) {
/**
* TODO: Document
- * @param $modules Array/string with the module name(s)
+ * @param array|string $modules One or more module names
* @param string $only ResourceLoaderModule TYPE_ class constant
- * @param $useESI boolean
+ * @param boolean $useESI
* @param array $extraQuery with extra query parameters to add to each request. array( param => value )
- * @param $loadCall boolean If true, output an (asynchronous) mw.loader.load() call rather than a "<script src='...'>" tag
- * @return string html "<script>" and "<style>" tags
+ * @param boolean $loadCall If true, output an (asynchronous) mw.loader.load() call rather than a "<script src='...'>" tag
+ * @return string The html "<script>", "<link>" and "<style>" tags
*/
protected function makeResourceLoaderLink( $modules, $only, $useESI = false, array $extraQuery = array(), $loadCall = false ) {
global $wgResourceLoaderUseESI;
$modules = (array)$modules;
+ $links = array(
+ 'html' => '',
+ 'states' => array(),
+ );
+
if ( !count( $modules ) ) {
- return '';
+ return $links;
}
+
if ( count( $modules ) > 1 ) {
// Remove duplicate module requests
$modules = array_unique( $modules );
if ( ResourceLoader::inDebugMode() ) {
// Recursively call us for every item
- $links = '';
foreach ( $modules as $name ) {
- $links .= $this->makeResourceLoaderLink( $name, $only, $useESI );
+ $link = $this->makeResourceLoaderLink( $name, $only, $useESI );
+ $links['html'] .= $link['html'];
+ $links['states'] += $link['states'];
}
return $links;
}
}
+
if ( !is_null( $this->mTarget ) ) {
$extraQuery['target'] = $this->mTarget;
}
$groups[$group][$name] = $module;
}
- $links = '';
foreach ( $groups as $group => $grpModules ) {
// Special handling for user-specific groups
$user = null;
$extraQuery
);
$context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
+
// Extract modules that know they're empty
- $emptyModules = array();
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 ) ) {
- $emptyModules[$key] = 'ready';
unset( $grpModules[$key] );
+ if ( $only !== ResourceLoaderModule::TYPE_STYLES ) {
+ $links['states'][$key] = 'ready';
+ }
}
}
- // Inline empty modules: since they're empty, just mark them as 'ready'
- 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";
- }
- // If there are no modules left, skip this group
+ // If there are no non-empty modules, skip this group
if ( count( $grpModules ) === 0 ) {
continue;
}
// properly use them as dependencies (bug 30914)
if ( $group === 'private' ) {
if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
- $links .= Html::inlineStyle(
+ $links['html'] .= Html::inlineStyle(
$resourceLoader->makeModuleResponse( $context, $grpModules )
);
} else {
- $links .= Html::inlineScript(
+ $links['html'] .= Html::inlineScript(
ResourceLoader::makeLoaderConditionalScript(
$resourceLoader->makeModuleResponse( $context, $grpModules )
)
);
}
- $links .= "\n";
+ $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
);
} 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::rawElement( 'noscript', array(), $link ) . "\n";
+ $links['html'] .= Html::rawElement( 'noscript', array(), $link ) . "\n";
} else {
- $links .= $link . "\n";
+ $links['html'] .= $link . "\n";
}
}
+
return $links;
}
+ /**
+ * Build html output from an array of links from makeResourceLoaderLink.
+ * @param array $links
+ * @return string HTML
+ */
+ protected static function getHtmlFromLoaderLinks( Array $links ) {
+ $html = '';
+ $states = array();
+ foreach ( $links as $link ) {
+ if ( !is_array( $link ) ) {
+ $html .= $link;
+ } else {
+ $html .= $link['html'];
+ $states += $link['states'];
+ }
+ }
+
+ if ( count( $states ) ) {
+ $html = Html::inlineScript(
+ ResourceLoader::makeLoaderConditionalScript(
+ ResourceLoader::makeLoaderStateScript( $states )
+ )
+ ) . "\n" . $html;
+ }
+
+ return $html;
+ }
+
/**
* JS stuff to put in the "<head>". This is the startup module, config
* vars and modules marked with position 'top'
*
- * @return String: HTML fragment
+ * @return string HTML fragment
*/
function getHeadScripts() {
global $wgResourceLoaderExperimentalAsyncLoading;
// Startup - this will immediately load jquery and mediawiki modules
- $scripts = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS, true );
+ $links = array();
+ $links[] = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS, true );
// Load config before anything else
- $scripts .= Html::inlineScript(
+ $links[] = Html::inlineScript(
ResourceLoader::makeLoaderConditionalScript(
ResourceLoader::makeConfigSetScript( $this->getJSVars() )
)
// This needs to be TYPE_COMBINED so these modules are properly wrapped
// in mw.loader.implement() calls and deferred until mw.user is available
$embedScripts = array( 'user.options', 'user.tokens' );
- $scripts .= $this->makeResourceLoaderLink( $embedScripts, ResourceLoaderModule::TYPE_COMBINED );
+ $links[] = $this->makeResourceLoaderLink( $embedScripts, ResourceLoaderModule::TYPE_COMBINED );
- // Script and Messages "only" requests marked for top inclusion
+ // Scripts and messages "only" requests marked for top inclusion
// Messages should go first
- $scripts .= $this->makeResourceLoaderLink( $this->getModuleMessages( true, 'top' ), ResourceLoaderModule::TYPE_MESSAGES );
- $scripts .= $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'top' ), ResourceLoaderModule::TYPE_SCRIPTS );
+ $links[] = $this->makeResourceLoaderLink( $this->getModuleMessages( true, 'top' ), ResourceLoaderModule::TYPE_MESSAGES );
+ $links[] = $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'top' ), ResourceLoaderModule::TYPE_SCRIPTS );
// Modules requests - let the client calculate dependencies and batch requests as it likes
// Only load modules that have marked themselves for loading at the top
$modules = $this->getModules( true, 'top' );
if ( $modules ) {
- $scripts .= Html::inlineScript(
+ $links[] = Html::inlineScript(
ResourceLoader::makeLoaderConditionalScript(
Xml::encodeJsCall( 'mw.loader.load', array( $modules ) )
)
}
if ( $wgResourceLoaderExperimentalAsyncLoading ) {
- $scripts .= $this->getScriptsForBottomQueue( true );
+ $links[] = $this->getScriptsForBottomQueue( true );
}
- return $scripts;
+ return self::getHtmlFromLoaderLinks( $links );
}
/**
* JS stuff to put at the 'bottom', which can either be the bottom of the "<body>"
* or the bottom of the "<head>" depending on $wgResourceLoaderExperimentalAsyncLoading:
* modules marked with position 'bottom', legacy scripts ($this->mScripts),
- * user preferences, site JS and user JS
+ * user preferences, site JS and user JS.
*
* @param $inHead boolean If true, this HTML goes into the "<head>", if false it goes into the "<body>"
* @return string
function getScriptsForBottomQueue( $inHead ) {
global $wgUseSiteJs, $wgAllowUserJs;
- // Script and Messages "only" requests marked for bottom inclusion
+ // Scripts and messages "only" requests marked for bottom inclusion
// If we're in the <head>, use load() calls rather than <script src="..."> tags
// Messages should go first
- $scripts = $this->makeResourceLoaderLink( $this->getModuleMessages( true, 'bottom' ),
+ $links = array();
+ $links[] = $this->makeResourceLoaderLink( $this->getModuleMessages( true, 'bottom' ),
ResourceLoaderModule::TYPE_MESSAGES, /* $useESI = */ false, /* $extraQuery = */ array(),
/* $loadCall = */ $inHead
);
- $scripts .= $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'bottom' ),
+ $links[] = $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'bottom' ),
ResourceLoaderModule::TYPE_SCRIPTS, /* $useESI = */ false, /* $extraQuery = */ array(),
/* $loadCall = */ $inHead
);
// Only load modules that have marked themselves for loading at the bottom
$modules = $this->getModules( true, 'bottom' );
if ( $modules ) {
- $scripts .= Html::inlineScript(
+ $links[] = Html::inlineScript(
ResourceLoader::makeLoaderConditionalScript(
Xml::encodeJsCall( 'mw.loader.load', array( $modules, null, true ) )
)
}
// Legacy Scripts
- $scripts .= "\n" . $this->mScripts;
-
- $defaultModules = array();
+ $links[] = "\n" . $this->mScripts;
// Add site JS if enabled
- if ( $wgUseSiteJs ) {
- $scripts .= $this->makeResourceLoaderLink( 'site', ResourceLoaderModule::TYPE_SCRIPTS,
- /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
- );
- $defaultModules['site'] = 'loading';
- } else {
- // Site module is empty, save request by marking ready in advance (bug 46857)
- $defaultModules['site'] = 'ready';
- }
+ $links[] = $this->makeResourceLoaderLink( 'site', ResourceLoaderModule::TYPE_SCRIPTS,
+ /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
+ );
// Add user JS if enabled
- if ( $wgAllowUserJs ) {
- if ( $this->getUser()->isLoggedIn() ) {
- 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)
- $scripts .= $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS, false,
- array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() ), $inHead
- );
- // Load the previewed JS
- $scripts .= Html::inlineScript( "\n" . $this->getRequest()->getText( 'wpTextbox1' ) . "\n" ) . "\n";
- // FIXME: If the user is previewing, say, ./vector.js, his ./common.js will be loaded
- // asynchronously and may arrive *after* the inline script here. So the previewed code
- // may execute before ./common.js runs. Normally, ./common.js runs before ./vector.js...
- } else {
- // Include the user module normally, i.e., raw to avoid it being wrapped in a closure.
- $scripts .= $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS,
- /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
- );
- }
- $defaultModules['user'] = 'loading';
- } else {
- // Non-logged-in users have an empty user module.
- // Save request by marking ready in advance (bug 46857)
- $defaultModules['user'] = 'ready';
- }
+ if ( $wgAllowUserJs && $this->getUser()->isLoggedIn() && $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)
+ $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS, false,
+ array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() ), $inHead
+ );
+ // Load the previewed JS
+ $links[] = Html::inlineScript( "\n" . $this->getRequest()->getText( 'wpTextbox1' ) . "\n" ) . "\n";
+
+ // FIXME: If the user is previewing, say, ./vector.js, his ./common.js will be loaded
+ // asynchronously and may arrive *after* the inline script here. So the previewed code
+ // may execute before ./common.js runs. Normally, ./common.js runs before ./vector.js...
} else {
- // User modules are disabled on this wiki.
- // Save request by marking ready in advance (bug 46857)
- $defaultModules['user'] = 'ready';
+ // Include the user module normally, i.e., raw to avoid it being wrapped in a closure.
+ $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS,
+ /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
+ );
}
// Group JS is only enabled if site JS is enabled.
- if ( $wgUseSiteJs ) {
- if ( $this->getUser()->isLoggedIn() ) {
- $scripts .= $this->makeResourceLoaderLink( 'user.groups', ResourceLoaderModule::TYPE_COMBINED,
- /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
- );
- $defaultModules['user.groups'] = 'loading';
- } else {
- // 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'] = 'ready';
- }
+ $links[] = $this->makeResourceLoaderLink( 'user.groups', ResourceLoaderModule::TYPE_COMBINED,
+ /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
+ );
- $loaderInit = '';
- if ( $inHead ) {
- // We generate loader calls anyway, so no need to fix the client-side loader's state to 'loading'.
- foreach ( $defaultModules as $m => $state ) {
- if ( $state == 'loading' ) {
- unset( $defaultModules[$m] );
- }
- }
- }
- if ( count( $defaultModules ) > 0 ) {
- $loaderInit = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- ResourceLoader::makeLoaderStateScript( $defaultModules )
- )
- ) . "\n";
- }
- return $loaderInit . $scripts;
+ return self::getHtmlFromLoaderLinks( $links );
}
/**
/**
* Generate a "<link rel/>" for a feed.
*
- * @param string $type feed type
+ * @param string $type Feed type
* @param string $url URL to the feed
- * @param string $text value of the "title" attribute
- * @return String: HTML fragment
+ * @param string $text Value of the "title" attribute
+ * @return string HTML fragment
*/
private function feedLink( $type, $url, $text ) {
return Html::element( 'link', array(
/**
* Adds inline CSS styles
- * @param $style_css Mixed: inline CSS
+ * @param mixed $style_css Inline CSS
* @param string $flip Set to 'flip' to flip the CSS if needed
*/
public function addInlineStyle( $style_css, $flip = 'noflip' ) {
# If wanted, and the interface is right-to-left, flip the CSS
$style_css = CSSJanus::transform( $style_css, true, false );
}
- $this->mInlineStyles .= Html::inlineStyle( $style_css );
+ $this->mInlineStyles .= Html::inlineStyle( $style_css ) . "\n";
}
/**
$this->getSkin()->setupSkinUserCss( $this );
// Add ResourceLoader styles
- // Split the styles into four groups
+ // Split the styles into these groups
$styles = array( 'other' => array(), 'user' => array(), 'site' => array(), 'private' => array(), 'noscript' => array() );
+ $links = array();
$otherTags = ''; // Tags to append after the normal <link> tags
$resourceLoader = $this->getResourceLoader();
$moduleStyles = $this->getModuleStyles();
// Per-site custom styles
- if ( $wgUseSiteCss ) {
- $moduleStyles[] = 'site';
- $moduleStyles[] = 'noscript';
- if ( $this->getUser()->isLoggedIn() ) {
- $moduleStyles[] = 'user.groups';
- }
- }
+ $moduleStyles[] = 'site';
+ $moduleStyles[] = 'noscript';
+ $moduleStyles[] = 'user.groups';
// Per-user custom styles
- if ( $wgAllowUserCss ) {
- if ( $this->getTitle()->isCssSubpage() && $this->userCanPreview() ) {
- // We're on a preview of a CSS subpage
- // Exclude this page from the user module in case it's in there (bug 26283)
- $otherTags .= $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_STYLES, false,
- array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() )
- );
-
- // Load the previewed CSS
- // If needed, Janus it first. This is user-supplied CSS, so it's
- // assumed to be right for the content language directionality.
- $previewedCSS = $this->getRequest()->getText( 'wpTextbox1' );
- if ( $this->getLanguage()->getDir() !== $wgContLang->getDir() ) {
- $previewedCSS = CSSJanus::transform( $previewedCSS, true, false );
- }
- $otherTags .= Html::inlineStyle( $previewedCSS );
- } else {
- // Load the user styles normally
- $moduleStyles[] = 'user';
+ if ( $wgAllowUserCss && $this->getTitle()->isCssSubpage() && $this->userCanPreview() ) {
+ // We're on a preview of a CSS subpage
+ // Exclude this page from the user module in case it's in there (bug 26283)
+ $link = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_STYLES, false,
+ array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() )
+ );
+ $otherTags .= $link['html'];
+
+ // Load the previewed CSS
+ // If needed, Janus it first. This is user-supplied CSS, so it's
+ // assumed to be right for the content language directionality.
+ $previewedCSS = $this->getRequest()->getText( 'wpTextbox1' );
+ if ( $this->getLanguage()->getDir() !== $wgContLang->getDir() ) {
+ $previewedCSS = CSSJanus::transform( $previewedCSS, true, false );
}
+ $otherTags .= Html::inlineStyle( $previewedCSS ) . "\n";
+ } else {
+ // Load the user styles normally
+ $moduleStyles[] = 'user';
}
// Per-user preference styles
- if ( $wgAllowUserCssPrefs ) {
- $moduleStyles[] = 'user.cssprefs';
- }
+ $moduleStyles[] = 'user.cssprefs';
foreach ( $moduleStyles as $name ) {
$module = $resourceLoader->getModule( $name );
continue;
}
$group = $module->getGroup();
- // Modules in groups named "other" or anything different than "user", "site" or "private"
+ // 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 styles from modules, but we want
// dynamically added styles to override statically added styles from other modules. So the order
// has to be other, dynamic, site, private, user
// Add statically added styles for other modules
- $ret = $this->makeResourceLoaderLink( $styles['other'], ResourceLoaderModule::TYPE_STYLES );
+ $links[] = $this->makeResourceLoaderLink( $styles['other'], ResourceLoaderModule::TYPE_STYLES );
// Add normal styles added through addStyle()/addInlineStyle() here
- $ret .= implode( "\n", $this->buildCssLinksArray() ) . $this->mInlineStyles;
+ $links[] = implode( "\n", $this->buildCssLinksArray() ) . $this->mInlineStyles;
// Add marker tag to mark the place where the client-side loader should inject dynamic styles
// We use a <meta> tag with a made-up name for this because that's valid HTML
- $ret .= Html::element( 'meta', array( 'name' => 'ResourceLoaderDynamicStyles', 'content' => '' ) ) . "\n";
+ $links[] = Html::element( 'meta', array( 'name' => 'ResourceLoaderDynamicStyles', 'content' => '' ) ) . "\n";
// Add site, private and user styles
// 'private' at present only contains user.options, so put that before 'user'
// Any future private modules will likely have a similar user-specific character
foreach ( array( 'site', 'noscript', 'private', 'user' ) as $group ) {
- $ret .= $this->makeResourceLoaderLink( $styles[$group],
- ResourceLoaderModule::TYPE_STYLES
+ $links[] = $this->makeResourceLoaderLink( $styles[$group],
+ ResourceLoaderModule::TYPE_STYLES
);
}
// Add stuff in $otherTags (previewed user CSS if applicable)
- $ret .= $otherTags;
- return $ret;
+ return self::getHtmlFromLoaderLinks( $links ) . $otherTags;
}
/**
* Generate \<link\> tags for stylesheets
*
* @param string $style URL to the file
- * @param array $options option, can contain 'condition', 'dir', 'media'
- * keys
- * @return String: HTML fragment
+ * @param array $options Option, can contain 'condition', 'dir', 'media' keys
+ * @return string HTML fragment
*/
protected function styleLink( $style, $options ) {
if ( isset( $options['dir'] ) ) {
/**
* Transform "media" attribute based on request parameters
*
- * @param string $media current value of the "media" attribute
- * @return String: modified value of the "media" attribute, or null to skip
+ * @param string $media Current value of the "media" attribute
+ * @return string Modified value of the "media" attribute, or null to skip
* this stylesheet
*/
public static function transformCssMedia( $media ) {
* Include jQuery core. Use this to avoid loading it multiple times
* before we get a usable script loader.
*
- * @param array $modules list of jQuery modules which should be loaded
- * @return Array: the list of modules which were not loaded.
+ * @param array $modules List of jQuery modules which should be loaded
+ * @return array The list of modules which were not loaded.
* @since 1.16
* @deprecated since 1.17
*/
public function isTOCEnabled() {
return $this->mEnableTOC;
}
+
+ /**
+ * Enables/disables section edit links, doesn't override __NOEDITSECTION__
+ * @param bool $flag
+ * @since 1.23
+ */
+ public function enableSectionEditLinks( $flag = true ) {
+ $this->mEnableSectionEditLinks = $flag;
+ }
+
+ /**
+ * @return bool
+ * @since 1.23
+ */
+ public function sectionEditLinksEnabled() {
+ return $this->mEnableSectionEditLinks;
+ }
}