diff options
Diffstat (limited to 'includes/Skin.php')
-rw-r--r-- | includes/Skin.php | 276 |
1 files changed, 174 insertions, 102 deletions
diff --git a/includes/Skin.php b/includes/Skin.php index 968f215e..5801806c 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -25,7 +25,7 @@ */ /** - * The main skin class that provide methods and properties for all other skins. + * The main skin class which provides methods and properties for all other skins. * This base class is also the "Standard" skin. * * See docs/skin.txt for more information. @@ -56,37 +56,40 @@ abstract class Skin extends ContextSource { $skinDir = dir( $wgStyleDirectory ); - # while code from www.php.net - while ( false !== ( $file = $skinDir->read() ) ) { - // Skip non-PHP files, hidden files, and '.dep' includes - $matches = array(); + if ( $skinDir !== false && $skinDir !== null ) { + # while code from www.php.net + while ( false !== ( $file = $skinDir->read() ) ) { + // Skip non-PHP files, hidden files, and '.dep' includes + $matches = array(); - if ( preg_match( '/^([^.]*)\.php$/', $file, $matches ) ) { - $aSkin = $matches[1]; - $wgValidSkinNames[strtolower( $aSkin )] = $aSkin; + if ( preg_match( '/^([^.]*)\.php$/', $file, $matches ) ) { + $aSkin = $matches[1]; + $wgValidSkinNames[strtolower( $aSkin )] = $aSkin; + } } + $skinDir->close(); } - $skinDir->close(); $skinsInitialised = true; wfProfileOut( __METHOD__ . '-init' ); } return $wgValidSkinNames; } - /** + /** * Fetch the skinname messages for available skins. * @return array of strings */ static function getSkinNameMessages() { $messages = array(); - foreach( self::getSkinNames() as $skinKey => $skinName ) { + foreach ( self::getSkinNames() as $skinKey => $skinName ) { + // Messages: skinname-cologneblue, skinname-monobook, skinname-modern, skinname-vector $messages[] = "skinname-$skinKey"; } return $messages; } /** - * Fetch the list of usable skins in regards to $wgSkipSkins. + * Fetch the list of user-selectable skins in regards to $wgSkipSkins. * Useful for Special:Preferences and other places where you * only want to show skins users _can_ use. * @return array of strings @@ -94,20 +97,20 @@ abstract class Skin extends ContextSource { public static function getUsableSkins() { global $wgSkipSkins; - $usableSkins = self::getSkinNames(); + $allowedSkins = self::getSkinNames(); foreach ( $wgSkipSkins as $skip ) { - unset( $usableSkins[$skip] ); + unset( $allowedSkins[$skip] ); } - return $usableSkins; + return $allowedSkins; } /** * Normalize a skin preference value to a form that can be loaded. * If a skin can't be found, it will fall back to the configured * default (or the old 'Classic' skin if that's broken). - * @param $key String: 'monobook', 'standard', etc. + * @param string $key 'monobook', 'standard', etc. * @return string */ static function normalizeKey( $key ) { @@ -129,7 +132,6 @@ abstract class Skin extends ContextSource { // in the user preferences. $fallback = array( 0 => $wgDefaultSkin, - 1 => 'nostalgia', 2 => 'cologneblue' ); @@ -148,7 +150,7 @@ abstract class Skin extends ContextSource { /** * Factory method for loading a skin of a given type - * @param $key String: 'monobook', 'standard', etc. + * @param string $key 'monobook', 'standard', etc. * @return Skin */ static function &newFromKey( $key ) { @@ -161,23 +163,19 @@ abstract class Skin extends ContextSource { $className = "Skin{$skinName}"; # Grab the skin class and initialise it. - if ( !MWInit::classExists( $className ) ) { + if ( !class_exists( $className ) ) { - if ( !defined( 'MW_COMPILED' ) ) { - require_once( "{$wgStyleDirectory}/{$skinName}.php" ); - } + require_once "{$wgStyleDirectory}/{$skinName}.php"; - # Check if we got if not failback to default skin - if ( !MWInit::classExists( $className ) ) { + # Check if we got if not fallback to default skin + if ( !class_exists( $className ) ) { # DO NOT die if the class isn't found. This breaks maintenance # scripts and can cause a user account to be unrecoverable # except by SQL manipulation if a previously valid skin name # is no longer valid. wfDebug( "Skin class does not exist: $className\n" ); $className = 'SkinVector'; - if ( !defined( 'MW_COMPILED' ) ) { - require_once( "{$wgStyleDirectory}/Vector.php" ); - } + require_once "{$wgStyleDirectory}/Vector.php"; } } $skin = new $className( $key ); @@ -201,6 +199,68 @@ abstract class Skin extends ContextSource { } /** + * Defines the ResourceLoader modules that should be added to the skin + * It is recommended that skins wishing to override call parent::getDefaultModules() + * and substitute out any modules they wish to change by using a key to look them up + * @return Array of modules with helper keys for easy overriding + */ + public function getDefaultModules() { + global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax, + $wgAjaxWatch, $wgEnableAPI, $wgEnableWriteAPI; + + $out = $this->getOutput(); + $user = $out->getUser(); + $modules = array( + // modules that enhance the page content in some way + 'content' => array( + 'mediawiki.page.ready', + ), + // modules that exist for legacy reasons + 'legacy' => array(), + // modules relating to search functionality + 'search' => array(), + // modules relating to functionality relating to watching an article + 'watch' => array(), + // modules which relate to the current users preferences + 'user' => array(), + ); + if ( $wgIncludeLegacyJavaScript ) { + $modules['legacy'][] = 'mediawiki.legacy.wikibits'; + } + + if ( $wgPreloadJavaScriptMwUtil ) { + $modules['legacy'][] = 'mediawiki.util'; + } + + // Add various resources if required + if ( $wgUseAjax ) { + $modules['legacy'][] = 'mediawiki.legacy.ajax'; + + if ( $wgEnableAPI ) { + if ( $wgEnableWriteAPI && $wgAjaxWatch && $user->isLoggedIn() + && $user->isAllowed( 'writeapi' ) + ) { + $modules['watch'][] = 'mediawiki.page.watch.ajax'; + } + + if ( !$user->getOption( 'disablesuggest', false ) ) { + $modules['search'][] = 'mediawiki.searchSuggest'; + } + } + } + + if ( $user->getBoolOption( 'editsectiononrightclick' ) ) { + $modules['user'][] = 'mediawiki.action.view.rightClickEdit'; + } + + // Crazy edit-on-double-click stuff + if ( $out->isArticle() && $user->getOption( 'editondblclick' ) ) { + $modules['user'][] = 'mediawiki.action.view.dblClickEdit'; + } + return $modules; + } + + /** * Preload the existence of three commonly-requested pages in a single query */ function preloadExistence() { @@ -262,7 +322,7 @@ abstract class Skin extends ContextSource { * @return Title */ public function getRelevantTitle() { - if ( isset($this->mRelevantTitle) ) { + if ( isset( $this->mRelevantTitle ) ) { return $this->mRelevantTitle; } return $this->getTitle(); @@ -286,12 +346,12 @@ abstract class Skin extends ContextSource { * @return User */ public function getRelevantUser() { - if ( isset($this->mRelevantUser) ) { + if ( isset( $this->mRelevantUser ) ) { return $this->mRelevantUser; } $title = $this->getRelevantTitle(); - if( $title->getNamespace() == NS_USER || $title->getNamespace() == NS_USER_TALK ) { - $rootUser = strtok( $title->getText(), '/' ); + if ( $title->hasSubjectNamespace( NS_USER ) ) { + $rootUser = $title->getRootText(); if ( User::isIP( $rootUser ) ) { $this->mRelevantUser = User::newFromName( $rootUser, false ); } else { @@ -435,7 +495,7 @@ abstract class Skin extends ContextSource { $colon = $this->msg( 'colon-separator' )->escaped(); if ( !empty( $allCats['normal'] ) ) { - $t = $embed . implode( "{$pop}{$embed}" , $allCats['normal'] ) . $pop; + $t = $embed . implode( "{$pop}{$embed}", $allCats['normal'] ) . $pop; $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) )->escaped(); $linkPage = wfMessage( 'pagecategorieslink' )->inContentLanguage()->text(); @@ -456,7 +516,7 @@ abstract class Skin extends ContextSource { $s .= "<div id=\"mw-hidden-catlinks\" class=\"mw-hidden-catlinks$class\">" . $this->msg( 'hidden-categories' )->numParams( count( $allCats['hidden'] ) )->escaped() . - $colon . '<ul>' . $embed . implode( "{$pop}{$embed}" , $allCats['hidden'] ) . $pop . '</ul>' . + $colon . '<ul>' . $embed . implode( "{$pop}{$embed}", $allCats['hidden'] ) . $pop . '</ul>' . '</div>'; } @@ -481,8 +541,8 @@ abstract class Skin extends ContextSource { } /** - * Render the array as a serie of links. - * @param $tree Array: categories tree returned by Title::getParentCategoryTree + * Render the array as a series of links. + * @param array $tree categories tree returned by Title::getParentCategoryTree * @return String separated by >, terminate with "\n" */ function drawCategoryBrowser( $tree ) { @@ -499,7 +559,7 @@ abstract class Skin extends ContextSource { # add our current element to the list $eltitle = Title::newFromText( $element ); - $return .= Linker::link( $eltitle, htmlspecialchars( $eltitle->getText() ) ); + $return .= Linker::link( $eltitle, htmlspecialchars( $eltitle->getText() ) ); } return $return; @@ -613,7 +673,6 @@ abstract class Skin extends ContextSource { ( $this->getTitle()->getArticleID() == 0 || $action == 'history' ) ) { $n = $this->getTitle()->isDeleted(); - if ( $n ) { if ( $this->getUser()->isAllowed( 'undelete' ) ) { $msg = 'thisisdeleted'; @@ -668,7 +727,7 @@ abstract class Skin extends ContextSource { if ( $c > 1 ) { $subpages .= $wgLang->getDirMarkEntity() . $this->msg( 'pipe-separator' )->escaped(); - } else { + } else { $subpages .= '< '; } @@ -851,16 +910,16 @@ abstract class Skin extends ContextSource { } /** - * Renders a $wgFooterIcons icon acording to the method's arguments - * @param $icon Array: The icon to build the html for, see $wgFooterIcons for the format of this array - * @param $withImage Bool|String: Whether to use the icon's image or output a text-only footericon + * Renders a $wgFooterIcons icon according to the method's arguments + * @param array $icon The icon to build the html for, see $wgFooterIcons for the format of this array + * @param bool|String $withImage Whether to use the icon's image or output a text-only footericon * @return String HTML */ function makeFooterIcon( $icon, $withImage = 'withImage' ) { if ( is_string( $icon ) ) { $html = $icon; } else { // Assuming array - $url = isset($icon["url"]) ? $icon["url"] : null; + $url = isset( $icon["url"] ) ? $icon["url"] : null; unset( $icon["url"] ); if ( isset( $icon["src"] ) && $withImage === 'withImage' ) { $html = Html::element( 'img', $icon ); // do this the lazy way, just pass icon data as an attribute array @@ -969,7 +1028,7 @@ abstract class Skin extends ContextSource { * Return a fully resolved style path url to images or styles stored in the common folder. * This method returns a url resolved using the configured skin style path * and includes the style version inside of the url. - * @param $name String: The name or path of a skin resource file + * @param string $name The name or path of a skin resource file * @return String The fully resolved style path url including styleversion */ function getCommonStylePath( $name ) { @@ -978,10 +1037,10 @@ abstract class Skin extends ContextSource { } /** - * Return a fully resolved style path url to images or styles stored in the curent skins's folder. + * Return a fully resolved style path url to images or styles stored in the current skins's folder. * This method returns a url resolved using the configured skin style path * and includes the style version inside of the url. - * @param $name String: The name or path of a skin resource file + * @param string $name The name or path of a skin resource file * @return String The fully resolved style path url including styleversion */ function getSkinStylePath( $name ) { @@ -1008,14 +1067,14 @@ abstract class Skin extends ContextSource { * If $proto is set to null, make a local URL. Otherwise, make a full * URL with the protocol specified. * - * @param $name string Name of the Special page - * @param $urlaction string Query to append + * @param string $name Name of the Special page + * @param string $urlaction Query to append * @param $proto Protocol to use or null for a local URL * @return String */ static function makeSpecialUrl( $name, $urlaction = '', $proto = null ) { $title = SpecialPage::getSafeTitleFor( $name ); - if( is_null( $proto ) ) { + if ( is_null( $proto ) ) { return $title->getLocalURL( $urlaction ); } else { return $title->getFullURL( $urlaction, false, $proto ); @@ -1102,7 +1161,7 @@ abstract class Skin extends ContextSource { /** * Make URL details where the article exists (or at least it's convenient to think so) - * @param $name String Article name + * @param string $name Article name * @param $urlaction String * @return Array */ @@ -1132,7 +1191,23 @@ abstract class Skin extends ContextSource { } /** - * Build an array that represents the sidebar(s), the navigation bar among them + * Build an array that represents the sidebar(s), the navigation bar among them. + * + * BaseTemplate::getSidebar can be used to simplify the format and id generation in new skins. + * + * The format of the returned array is array( heading => content, ... ), where: + * - heading is the heading of a navigation portlet. It is either: + * - magic string to be handled by the skins ('SEARCH' / 'LANGUAGES' / 'TOOLBOX' / ...) + * - a message name (e.g. 'navigation'), the message should be HTML-escaped by the skin + * - plain text, which should be HTML-escaped by the skin + * - content is the contents of the portlet. It is either: + * - HTML text (<ul><li>...</li>...</ul>) + * - array of link data in a format accepted by BaseTemplate::makeListItem() + * - (for a magic string as a key, any value) + * + * Note that extensions can control the sidebar contents using the SkinBuildSidebar hook + * and can technically insert anything in here; skin creators are expected to handle + * values described above. * * @return array */ @@ -1237,7 +1312,7 @@ abstract class Skin extends ContextSource { } global $wgExternalLinkTarget; - if ( $wgExternalLinkTarget) { + if ( $wgExternalLinkTarget ) { $extraAttribs['target'] = $wgExternalLinkTarget; } } else { @@ -1267,28 +1342,43 @@ abstract class Skin extends ContextSource { } /** - * Should we load mediawiki.legacy.wikiprintable? Skins that have their own - * print stylesheet should override this and return false. (This is an - * ugly hack to get Monobook to play nicely with OutputPage::headElement().) + * This function previously controlled whether the 'mediawiki.legacy.wikiprintable' module + * should be loaded by OutputPage. That module no longer exists and the return value of this + * method is ignored. * + * If your skin doesn't provide its own print styles, the 'mediawiki.legacy.commonPrint' module + * can be used instead (SkinTemplate-based skins do it automatically). + * + * @deprecated since 1.22 * @return bool */ public function commonPrintStylesheet() { - return true; + wfDeprecated( __METHOD__, '1.22' ); + return false; } /** - * Gets new talk page messages for the current user. - * @return MediaWiki message or if no new talk page messages, nothing + * Gets new talk page messages for the current user and returns an + * appropriate alert message (or an empty string if there are no messages) + * @return String */ function getNewtalks() { + + $newMessagesAlert = ''; + $user = $this->getUser(); + $newtalks = $user->getNewMessageLinks(); $out = $this->getOutput(); - $newtalks = $this->getUser()->getNewMessageLinks(); - $ntl = ''; + // Allow extensions to disable or modify the new messages alert + if ( !wfRunHooks( 'GetNewMessagesAlert', array( &$newMessagesAlert, $newtalks, $user, $out ) ) ) { + return ''; + } + if ( $newMessagesAlert ) { + return $newMessagesAlert; + } if ( count( $newtalks ) == 1 && $newtalks[0]['wiki'] === wfWikiID() ) { - $uTalkTitle = $this->getUser()->getTalkPage(); + $uTalkTitle = $user->getTalkPage(); if ( !$uTalkTitle->equals( $out->getTitle() ) ) { $lastSeenRev = isset( $newtalks[0]['rev'] ) ? $newtalks[0]['rev'] : null; @@ -1327,26 +1417,25 @@ abstract class Skin extends ContextSource { ); if ( $nofAuthors >= 1 && $nofAuthors <= 10 ) { - $ntl = $this->msg( + $newMessagesAlert = $this->msg( 'youhavenewmessagesfromusers', $newMessagesLink, $newMessagesDiffLink )->numParams( $nofAuthors ); } else { // $nofAuthors === 11 signifies "11 or more" ("more than 10") - $ntl = $this->msg( + $newMessagesAlert = $this->msg( $nofAuthors > 10 ? 'youhavenewmessagesmanyusers' : 'youhavenewmessages', $newMessagesLink, $newMessagesDiffLink ); } - $ntl = $ntl->text(); + $newMessagesAlert = $newMessagesAlert->text(); # Disable Squid cache $out->setSquidMaxage( 0 ); } } elseif ( count( $newtalks ) ) { - // _>" " for BC <= 1.16 - $sep = str_replace( '_', ' ', $this->msg( 'newtalkseparator' )->escaped() ); + $sep = $this->msg( 'newtalkseparator' )->escaped(); $msgs = array(); foreach ( $newtalks as $newtalk ) { @@ -1356,17 +1445,17 @@ abstract class Skin extends ContextSource { ); } $parts = implode( $sep, $msgs ); - $ntl = $this->msg( 'youhavenewmessagesmulti' )->rawParams( $parts )->escaped(); + $newMessagesAlert = $this->msg( 'youhavenewmessagesmulti' )->rawParams( $parts )->escaped(); $out->setSquidMaxage( 0 ); } - return $ntl; + return $newMessagesAlert; } /** * Get a cached notice * - * @param $name String: message name, or 'default' for $wgSiteNotice + * @param string $name message name, or 'default' for $wgSiteNotice * @return String: HTML fragment */ private function getCachedNotice( $name ) { @@ -1376,17 +1465,17 @@ abstract class Skin extends ContextSource { $needParse = false; - if( $name === 'default' ) { + if ( $name === 'default' ) { // special case global $wgSiteNotice; $notice = $wgSiteNotice; - if( empty( $notice ) ) { + if ( empty( $notice ) ) { wfProfileOut( __METHOD__ ); return false; } } else { $msg = $this->msg( $name )->inContentLanguage(); - if( $msg->isDisabled() ) { + if ( $msg->isDisabled() ) { wfProfileOut( __METHOD__ ); return false; } @@ -1396,8 +1485,8 @@ abstract class Skin extends ContextSource { // Use the extra hash appender to let eg SSL variants separately cache. $key = wfMemcKey( $name . $wgRenderHashAppend ); $cachedNotice = $parserMemc->get( $key ); - if( is_array( $cachedNotice ) ) { - if( md5( $notice ) == $cachedNotice['hash'] ) { + if ( is_array( $cachedNotice ) ) { + if ( md5( $notice ) == $cachedNotice['hash'] ) { $notice = $cachedNotice['html']; } else { $needParse = true; @@ -1474,9 +1563,9 @@ abstract class Skin extends ContextSource { * * @param $nt Title The title being linked to (may not be the same as * $wgTitle, if the section is included from a template) - * @param $section string The designation of the section being pointed to, + * @param string $section The designation of the section being pointed to, * to be included in the link, like "§ion=$section" - * @param $tooltip string The tooltip to use for the link: will be escaped + * @param string $tooltip The tooltip to use for the link: will be escaped * and wrapped in the 'editsectionhint' message * @param $lang string Language code * @return string HTML to use for edit link @@ -1500,31 +1589,12 @@ abstract class Skin extends ContextSource { array( 'noclasses', 'known' ) ); - # Run the old hook. This takes up half of the function . . . hopefully - # we can rid of it someday. - $attribs = ''; - if ( $tooltip ) { - $attribs = wfMessage( 'editsectionhint' )->rawParams( $tooltip ) - ->inLanguage( $lang )->escaped(); - $attribs = " title=\"$attribs\""; - } - $result = null; - wfRunHooks( 'EditSectionLink', array( &$this, $nt, $section, $attribs, $link, &$result, $lang ) ); - if ( !is_null( $result ) ) { - # For reverse compatibility, add the brackets *after* the hook is - # run, and even add them to hook-provided text. (This is the main - # reason that the EditSectionLink hook is deprecated in favor of - # DoEditSectionLink: it can't change the brackets or the span.) - $result = wfMessage( 'editsection-brackets' )->rawParams( $result ) - ->inLanguage( $lang )->escaped(); - return "<span class=\"editsection\">$result</span>"; - } - - # Add the brackets and the span, and *then* run the nice new hook, with - # clean and non-redundant arguments. - $result = wfMessage( 'editsection-brackets' )->rawParams( $link ) - ->inLanguage( $lang )->escaped(); - $result = "<span class=\"editsection\">$result</span>"; + # Add the brackets and the span and run the hook. + $result = '<span class="mw-editsection">' + . '<span class="mw-editsection-bracket">[</span>' + . $link + . '<span class="mw-editsection-bracket">]</span>' + . '</span>'; wfRunHooks( 'DoEditSectionLink', array( $this, $nt, $section, $tooltip, &$result, $lang ) ); return $result; @@ -1534,13 +1604,15 @@ abstract class Skin extends ContextSource { * Use PHP's magic __call handler to intercept legacy calls to the linker * for backwards compatibility. * - * @param $fname String Name of called method - * @param $args Array Arguments to the method + * @param string $fname Name of called method + * @param array $args Arguments to the method + * @throws MWException * @return mixed */ function __call( $fname, $args ) { $realFunction = array( 'Linker', $fname ); if ( is_callable( $realFunction ) ) { + wfDeprecated( get_class( $this ) . '::' . $fname, '1.21' ); return call_user_func_array( $realFunction, $args ); } else { $className = get_class( $this ); |