diff options
Diffstat (limited to 'includes/Skin.php')
-rw-r--r-- | includes/Skin.php | 878 |
1 files changed, 541 insertions, 337 deletions
diff --git a/includes/Skin.php b/includes/Skin.php index 18867cbe..01b3b4fe 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -40,20 +40,24 @@ class Skin extends Linker { static function getSkinNames() { global $wgValidSkinNames; static $skinsInitialised = false; + if ( !$skinsInitialised ) { # Get a list of available skins # Build using the regular expression '^(.*).php$' # Array keys are all lower case, array value keep the case used by filename # wfProfileIn( __METHOD__ . '-init' ); + global $wgStyleDirectory; + $skinDir = dir( $wgStyleDirectory ); # while code from www.php.net - while( false !== ( $file = $skinDir->read() ) ) { + while ( false !== ( $file = $skinDir->read() ) ) { // Skip non-PHP files, hidden files, and '.dep' includes $matches = array(); - if( preg_match( '/^([^.]*)\.php$/', $file, $matches ) ) { + + if ( preg_match( '/^([^.]*)\.php$/', $file, $matches ) ) { $aSkin = $matches[1]; $wgValidSkinNames[strtolower( $aSkin )] = $aSkin; } @@ -73,10 +77,13 @@ class Skin extends Linker { */ public static function getUsableSkins() { global $wgSkipSkins; + $usableSkins = self::getSkinNames(); + foreach ( $wgSkipSkins as $skip ) { unset( $usableSkins[$skip] ); } + return $usableSkins; } @@ -89,15 +96,16 @@ class Skin extends Linker { */ static function normalizeKey( $key ) { global $wgDefaultSkin; + $skinNames = Skin::getSkinNames(); - if( $key == '' ) { + if ( $key == '' ) { // Don't return the default immediately; // in a misconfiguration we need to fall back. $key = $wgDefaultSkin; } - if( isset( $skinNames[$key] ) ) { + if ( isset( $skinNames[$key] ) ) { return $key; } @@ -109,14 +117,16 @@ class Skin extends Linker { 2 => 'cologneblue' ); - if( isset( $fallback[$key] ) ) { + if ( isset( $fallback[$key] ) ) { $key = $fallback[$key]; } - if( isset( $skinNames[$key] ) ) { + if ( isset( $skinNames[$key] ) ) { return $key; + } else if ( isset( $skinNames[$wgDefaultSkin] ) ) { + return $wgDefaultSkin; } else { - return 'monobook'; + return 'vector'; } } @@ -138,20 +148,21 @@ class Skin extends Linker { if ( !class_exists( $className ) ) { // Preload base classes to work around APC/PHP5 bug $deps = "{$wgStyleDirectory}/{$skinName}.deps.php"; - if( file_exists( $deps ) ) { + + if ( file_exists( $deps ) ) { include_once( $deps ); } require_once( "{$wgStyleDirectory}/{$skinName}.php" ); # Check if we got if not failback to default skin - if( !class_exists( $className ) ) { + 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 = 'SkinMonobook'; - require_once( "{$wgStyleDirectory}/MonoBook.php" ); + $className = 'SkinVector'; + require_once( "{$wgStyleDirectory}/Vector.php" ); } } $skin = new $className; @@ -174,12 +185,14 @@ class Skin extends Linker { if ( $wgOut->isQuickbarSuppressed() ) { return 0; } + $q = $wgUser->getOption( 'quickbar', 0 ); + return $q; } function initPage( OutputPage $out ) { - global $wgFavicon, $wgAppleTouchIcon; + global $wgFavicon, $wgAppleTouchIcon, $wgEnableAPI; wfProfileIn( __METHOD__ ); @@ -187,11 +200,11 @@ class Skin extends Linker { # should not matter, but Konqueror (3.5.9 at least) incorrectly # uses whichever one appears later in the HTML source. Make sure # apple-touch-icon is specified first to avoid this. - if( false !== $wgAppleTouchIcon ) { + if ( false !== $wgAppleTouchIcon ) { $out->addLink( array( 'rel' => 'apple-touch-icon', 'href' => $wgAppleTouchIcon ) ); } - if( false !== $wgFavicon ) { + if ( false !== $wgFavicon ) { $out->addLink( array( 'rel' => 'shortcut icon', 'href' => $wgFavicon ) ); } @@ -201,7 +214,19 @@ class Skin extends Linker { 'type' => 'application/opensearchdescription+xml', 'href' => wfScript( 'opensearch_desc' ), 'title' => wfMsgForContent( 'opensearch-desc' ), - )); + ) ); + + if ( $wgEnableAPI ) { + # Real Simple Discovery link, provides auto-discovery information + # for the MediaWiki API (and potentially additional custom API + # support such as WordPress or Twitter-compatible APIs for a + # blogging extension, etc) + $out->addLink( array( + 'rel' => 'EditURI', + 'type' => 'application/rsd+xml', + 'href' => wfExpandUrl( wfAppendQuery( wfScript( 'api' ), array( 'action' => 'rsd' ) ) ), + ) ); + } $this->addMetadataLinks( $out ); @@ -231,28 +256,41 @@ class Skin extends Linker { } $lb = new LinkBatch( $titles ); + $lb->setCaller( __METHOD__ ); $lb->execute(); } /** - * Adds metadata links (Creative Commons/Dublin Core/copyright) to the HTML - * output. + * Adds metadata links below to the HTML output. + * <ol> + * <li>Creative Commons + * <br />See http://wiki.creativecommons.org/Extend_Metadata. + * </li> + * <li>Dublin Core</li> + * <li>Use hreflang to specify canonical and alternate links + * <br />See http://www.google.com/support/webmasters/bin/answer.py?answer=189077 + * </li> + * <li>Copyright</li> + * <ol> + * * @param $out Object: instance of OutputPage */ function addMetadataLinks( OutputPage $out ) { global $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf; + global $wgDisableLangConversion, $wgCanonicalLanguageLinks, $wgContLang; global $wgRightsPage, $wgRightsUrl; - if( $out->isArticleRelated() ) { + if ( $out->isArticleRelated() ) { # note: buggy CC software only reads first "meta" link - if( $wgEnableCreativeCommonsRdf ) { + if ( $wgEnableCreativeCommonsRdf ) { $out->addMetadataLink( array( 'title' => 'Creative Commons', 'type' => 'application/rdf+xml', 'href' => $this->mTitle->getLocalURL( 'action=creativecommons' ) ) ); } - if( $wgEnableDublinCoreRdf ) { + + if ( $wgEnableDublinCoreRdf ) { $out->addMetadataLink( array( 'title' => 'Dublin Core', 'type' => 'application/rdf+xml', @@ -260,17 +298,43 @@ class Skin extends Linker { ); } } + + if ( !$wgDisableLangConversion && $wgCanonicalLanguageLinks + && $wgContLang->hasVariants() ) { + + $urlvar = $wgContLang->getURLVariant(); + + if ( !$urlvar ) { + $variants = $wgContLang->getVariants(); + foreach ( $variants as $_v ) { + $out->addLink( array( + 'rel' => 'alternate', + 'hreflang' => $_v, + 'href' => $this->mTitle->getLocalURL( '', $_v ) ) + ); + } + } else { + $out->addLink( array( + 'rel' => 'canonical', + 'href' => $this->mTitle->getFullURL() ) + ); + } + } + $copyright = ''; - if( $wgRightsPage ) { + if ( $wgRightsPage ) { $copy = Title::newFromText( $wgRightsPage ); - if( $copy ) { + + if ( $copy ) { $copyright = $copy->getLocalURL(); } } - if( !$copyright && $wgRightsUrl ) { + + if ( !$copyright && $wgRightsUrl ) { $copyright = $wgRightsUrl; } - if( $copyright ) { + + if ( $copyright ) { $out->addLink( array( 'rel' => 'copyright', 'href' => $copyright ) @@ -290,7 +354,7 @@ class Skin extends Linker { /** * Set the title - * @param Title $t The title to use + * @param $t Title object to use */ public function setTitle( $t ) { $this->mTitle = $t; @@ -330,7 +394,7 @@ class Skin extends Linker { $out->out( $afterContent ); - $out->out( $this->bottomScripts() ); + $out->out( $this->bottomScripts( $out ) ); $out->out( wfReportTime() ); @@ -339,67 +403,30 @@ class Skin extends Linker { } static function makeVariablesScript( $data ) { - if( $data ) { - $r = array(); - foreach ( $data as $name => $value ) { - $encValue = Xml::encodeJsVar( $value ); - $r[] = "$name=$encValue"; - } - $js = 'var ' . implode( ",\n", $r ) . ';'; - return Html::inlineScript( "\n$js\n" ); + if ( $data ) { + return Html::inlineScript( + ResourceLoader::makeLoaderConditionalScript( ResourceLoader::makeConfigSetScript( $data ) ) + ); } else { return ''; - } + } } /** * Make a <script> tag containing global variables * @param $skinName string Name of the skin * The odd calling convention is for backwards compatibility - * @TODO @FIXME Make this not depend on $wgTitle! + * @todo FIXME: Make this not depend on $wgTitle! + * + * Do not add things here which can be evaluated in ResourceLoaderStartupScript - in other words, without state. + * You will only be adding bloat to the page and causing page caches to have to be purged on configuration changes. */ static function makeGlobalVariablesScript( $skinName ) { - if ( is_array( $skinName ) ) { - # Weird back-compat stuff. - $skinName = $skinName['skinname']; - } - global $wgScript, $wgTitle, $wgStylePath, $wgUser, $wgScriptExtension; - global $wgArticlePath, $wgScriptPath, $wgServer, $wgContLang, $wgLang; - global $wgOut, $wgArticle; - global $wgBreakFrames, $wgRequest, $wgVariantArticlePath, $wgActionPaths; - global $wgUseAjax, $wgAjaxWatch; - global $wgVersion, $wgEnableAPI, $wgEnableWriteAPI; - global $wgRestrictionTypes; - global $wgMWSuggestTemplate, $wgDBname, $wgEnableMWSuggest; - global $wgSitename; - + global $wgTitle, $wgUser, $wgRequest, $wgArticle, $wgOut, $wgUseAjax, $wgEnableMWSuggest; + $ns = $wgTitle->getNamespace(); $nsname = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $wgTitle->getNsText(); - $separatorTransTable = $wgContLang->separatorTransformTable(); - $separatorTransTable = $separatorTransTable ? $separatorTransTable : array(); - $compactSeparatorTransTable = array( - implode( "\t", array_keys( $separatorTransTable ) ), - implode( "\t", $separatorTransTable ), - ); - $digitTransTable = $wgContLang->digitTransformTable(); - $digitTransTable = $digitTransTable ? $digitTransTable : array(); - $compactDigitTransTable = array( - implode( "\t", array_keys( $digitTransTable ) ), - implode( "\t", $digitTransTable ), - ); - - $mainPage = Title::newFromText( wfMsgForContent( 'mainpage' ) ); $vars = array( - 'skin' => $skinName, - 'stylepath' => $wgStylePath, - 'wgUrlProtocols' => wfUrlProtocols(), - 'wgArticlePath' => $wgArticlePath, - 'wgScriptPath' => $wgScriptPath, - 'wgScriptExtension' => $wgScriptExtension, - 'wgScript' => $wgScript, - 'wgVariantArticlePath' => $wgVariantArticlePath, - 'wgActionPaths' => (object)$wgActionPaths, - 'wgServer' => $wgServer, 'wgCanonicalNamespace' => $nsname, 'wgCanonicalSpecialPageName' => $ns == NS_SPECIAL ? SpecialPage::resolveAlias( $wgTitle->getDBkey() ) : false, # bug 21115 @@ -410,55 +437,21 @@ class Skin extends Linker { 'wgArticleId' => $wgTitle->getArticleId(), 'wgIsArticle' => $wgOut->isArticle(), 'wgUserName' => $wgUser->isAnon() ? null : $wgUser->getName(), - 'wgUserGroups' => $wgUser->isAnon() ? null : $wgUser->getEffectiveGroups(), - 'wgUserLanguage' => $wgLang->getCode(), - 'wgContentLanguage' => $wgContLang->getCode(), - 'wgBreakFrames' => $wgOut->getFrameOptions() == 'DENY', + 'wgUserGroups' => $wgUser->getEffectiveGroups(), 'wgCurRevisionId' => isset( $wgArticle ) ? $wgArticle->getLatest() : 0, - 'wgVersion' => $wgVersion, - 'wgEnableAPI' => $wgEnableAPI, - 'wgEnableWriteAPI' => $wgEnableWriteAPI, - 'wgSeparatorTransformTable' => $compactSeparatorTransTable, - 'wgDigitTransformTable' => $compactDigitTransTable, - 'wgMainPageTitle' => $mainPage ? $mainPage->getPrefixedText() : null, - 'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(), - 'wgNamespaceIds' => $wgContLang->getNamespaceIds(), - 'wgSiteName' => $wgSitename, 'wgCategories' => $wgOut->getCategories(), + 'wgBreakFrames' => $wgOut->getFrameOptions() == 'DENY', ); - if ( $wgContLang->hasVariants() ) { - $vars['wgUserVariant'] = $wgContLang->getPreferredVariant(); - } - - // if on upload page output the extension list & js_upload - if( SpecialPage::resolveAlias( $wgTitle->getDBkey() ) == 'Upload' ) { - global $wgFileExtensions, $wgAjaxUploadInterface; - $vars['wgFileExtensions'] = $wgFileExtensions; - } - - if( $wgUseAjax && $wgEnableMWSuggest && !$wgUser->getOption( 'disablesuggest', false ) ) { - $vars['wgMWSuggestTemplate'] = SearchEngine::getMWSuggestTemplate(); - $vars['wgDBname'] = $wgDBname; - $vars['wgSearchNamespaces'] = SearchEngine::userNamespaces( $wgUser ); - $vars['wgMWSuggestMessages'] = array( wfMsg( 'search-mwsuggest-enabled' ), wfMsg( 'search-mwsuggest-disabled' ) ); - } - - foreach( $wgRestrictionTypes as $type ) { + foreach ( $wgTitle->getRestrictionTypes() as $type ) { $vars['wgRestriction' . ucfirst( $type )] = $wgTitle->getRestrictions( $type ); } - - if ( $wgOut->isArticleRelated() && $wgUseAjax && $wgAjaxWatch && $wgUser->isLoggedIn() ) { - $msgs = (object)array(); - foreach ( array( 'watch', 'unwatch', 'watching', 'unwatching', - 'tooltip-ca-watch', 'tooltip-ca-unwatch' ) as $msgName ) { - $msgs->{$msgName . 'Msg'} = wfMsg( $msgName ); - } - $vars['wgAjaxWatch'] = $msgs; + if ( $wgUseAjax && $wgEnableMWSuggest && !$wgUser->getOption( 'disablesuggest', false ) ) { + $vars['wgSearchNamespaces'] = SearchEngine::userNamespaces( $wgUser ); } - + // Allow extensions to add their custom variables to the global JS variables wfRunHooks( 'MakeGlobalVariablesScript', array( &$vars ) ); - + return self::makeVariablesScript( $vars ); } @@ -475,18 +468,19 @@ class Skin extends Linker { public function userCanPreview( $action ) { global $wgRequest, $wgUser; - if( $action != 'submit' ) { + if ( $action != 'submit' ) { return false; } - if( !$wgRequest->wasPosted() ) { + if ( !$wgRequest->wasPosted() ) { return false; } - if( !$this->mTitle->userCanEditCssSubpage() ) { + if ( !$this->mTitle->userCanEditCssSubpage() ) { return false; } - if( !$this->mTitle->userCanEditJsSubpage() ) { + if ( !$this->mTitle->userCanEditJsSubpage() ) { return false; } + return $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ); } @@ -506,185 +500,126 @@ class Skin extends Linker { * @return string */ public function generateUserJs( $skinName = null ) { - global $wgStylePath; - - wfProfileIn( __METHOD__ ); - if( !$skinName ) { - $skinName = $this->getSkinName(); - } - - $s = "/* generated javascript */\n"; - $s .= "var skin = '" . Xml::escapeJsString( $skinName ) . "';\n"; - $s .= "var stylepath = '" . Xml::escapeJsString( $wgStylePath ) . "';"; - $s .= "\n\n/* MediaWiki:Common.js */\n"; - $commonJs = wfMsgExt( 'common.js', 'content' ); - if ( !wfEmptyMsg( 'common.js', $commonJs ) ) { - $s .= $commonJs; - } - - $s .= "\n\n/* MediaWiki:" . ucfirst( $skinName ) . ".js */\n"; - // avoid inclusion of non defined user JavaScript (with custom skins only) - // by checking for default message content - $msgKey = ucfirst( $skinName ) . '.js'; - $userJS = wfMsgExt( $msgKey, 'content' ); - if ( !wfEmptyMsg( $msgKey, $userJS ) ) { - $s .= $userJS; - } - - wfProfileOut( __METHOD__ ); - return $s; + + // Stub - see ResourceLoaderSiteModule, CologneBlue, Simple and Standard skins override this + + return ''; } /** * Generate user stylesheet for action=raw&gen=css */ public function generateUserStylesheet() { - wfProfileIn( __METHOD__ ); - $s = "/* generated user stylesheet */\n" . - $this->reallyGenerateUserStylesheet(); - wfProfileOut( __METHOD__ ); - return $s; + + // Stub - see ResourceLoaderUserModule, CologneBlue, Simple and Standard skins override this + + return ''; } /** * Split for easier subclassing in SkinSimple, SkinStandard and SkinCologneBlue + * Anything in here won't be generated if $wgAllowUserCssPrefs is false. */ protected function reallyGenerateUserStylesheet() { - global $wgUser; - $s = ''; - if( ( $undopt = $wgUser->getOption( 'underline' ) ) < 2 ) { - $underline = $undopt ? 'underline' : 'none'; - $s .= "a { text-decoration: $underline; }\n"; - } - if( $wgUser->getOption( 'highlightbroken' ) ) { - $s .= "a.new, #quickbar a.new { color: #CC2200; }\n"; - } else { - $s .= <<<CSS -a.new, #quickbar a.new, -a.stub, #quickbar a.stub { - color: inherit; -} -a.new:after, #quickbar a.new:after { - content: "?"; - color: #CC2200; -} -a.stub:after, #quickbar a.stub:after { - content: "!"; - color: #772233; -} -CSS; - } - if( $wgUser->getOption( 'justify' ) ) { - $s .= "#article, #bodyContent, #mw_content { text-align: justify; }\n"; - } - if( !$wgUser->getOption( 'showtoc' ) ) { - $s .= "#toc { display: none; }\n"; - } - if( !$wgUser->getOption( 'editsection' ) ) { - $s .= ".editsection { display: none; }\n"; - } - $fontstyle = $wgUser->getOption( 'editfont' ); - if ( $fontstyle !== 'default' ) { - $s .= "textarea { font-family: $fontstyle; }\n"; - } - return $s; + + // Stub - see ResourceLoaderUserModule, CologneBlue, Simple and Standard skins override this + + return ''; } /** * @private */ function setupUserCss( OutputPage $out ) { - global $wgRequest, $wgContLang, $wgUser; - global $wgAllowUserCss, $wgUseSiteCss, $wgSquidMaxage, $wgStylePath; + global $wgRequest; + global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs; wfProfileIn( __METHOD__ ); $this->setupSkinUserCss( $out ); - - $siteargs = array( - 'action' => 'raw', - 'maxage' => $wgSquidMaxage, - ); - // Add any extension CSS foreach ( $out->getExtStyle() as $url ) { $out->addStyle( $url ); } - // If we use the site's dynamic CSS, throw that in, too // Per-site custom styles - if( $wgUseSiteCss ) { - global $wgHandheldStyle; - $query = wfArrayToCGI( array( - 'usemsgcache' => 'yes', - 'ctype' => 'text/css', - 'smaxage' => $wgSquidMaxage - ) + $siteargs ); - # Site settings must override extension css! (bug 15025) - $out->addStyle( self::makeNSUrl( 'Common.css', $query, NS_MEDIAWIKI ) ); - $out->addStyle( self::makeNSUrl( 'Print.css', $query, NS_MEDIAWIKI ), 'print' ); - if( $wgHandheldStyle ) { - $out->addStyle( self::makeNSUrl( 'Handheld.css', $query, NS_MEDIAWIKI ), 'handheld' ); - } - $out->addStyle( self::makeNSUrl( $this->getSkinName() . '.css', $query, NS_MEDIAWIKI ) ); + if ( $wgUseSiteCss ) { + $out->addModuleStyles( 'site' ); } - if( $wgUser->isLoggedIn() ) { - // Ensure that logged-in users' generated CSS isn't clobbered - // by anons' publicly cacheable generated CSS. - $siteargs['smaxage'] = '0'; - $siteargs['ts'] = $wgUser->mTouched; - } - // Per-user styles based on preferences - $siteargs['gen'] = 'css'; - if( ( $us = $wgRequest->getVal( 'useskin', '' ) ) !== '' ) { - $siteargs['useskin'] = $us; - } - $out->addStyle( self::makeUrl( '-', wfArrayToCGI( $siteargs ) ) ); - - // Per-user custom style pages - if( $wgAllowUserCss && $wgUser->isLoggedIn() ) { - $action = $wgRequest->getVal( 'action' ); - # If we're previewing the CSS page, use it - if( $this->mTitle->isCssSubpage() && $this->userCanPreview( $action ) ) { + // Per-user custom styles + if ( $wgAllowUserCss ) { + if ( $this->mTitle->isCssSubpage() && $this->userCanPreview( $wgRequest->getVal( 'action' ) ) ) { // @FIXME: properly escape the cdata! $out->addInlineStyle( $wgRequest->getText( 'wpTextbox1' ) ); } else { - $out->addStyle( self::makeUrl( - $this->userpage . '/' . $this->getSkinName() . '.css', - 'action=raw&ctype=text/css' ) - ); + $out->addModuleStyles( 'user' ); } } + // Per-user preference styles + if ( $wgAllowUserCssPrefs ) { + $out->addModuleStyles( 'user.options' ); + } + wfProfileOut( __METHOD__ ); } /** + * Get the query to generate a dynamic stylesheet + * + * @return array + */ + public static function getDynamicStylesheetQuery() { + global $wgSquidMaxage; + + return array( + 'action' => 'raw', + 'maxage' => $wgSquidMaxage, + 'usemsgcache' => 'yes', + 'ctype' => 'text/css', + 'smaxage' => $wgSquidMaxage, + ); + } + + /** * Add skin specific stylesheets * @param $out OutputPage */ function setupSkinUserCss( OutputPage $out ) { - $out->addStyle( 'common/shared.css' ); - $out->addStyle( 'common/oldshared.css' ); + $out->addModuleStyles( 'mediawiki.legacy.shared' ); + $out->addModuleStyles( 'mediawiki.legacy.oldshared' ); + // TODO: When converting old skins to use ResourceLoader (or removing them) the following should be reconsidered $out->addStyle( $this->getStylesheet() ); $out->addStyle( 'common/common_rtl.css', '', '', 'rtl' ); } function getPageClasses( $title ) { $numeric = 'ns-' . $title->getNamespace(); - if( $title->getNamespace() == NS_SPECIAL ) { + + if ( $title->getNamespace() == NS_SPECIAL ) { $type = 'ns-special'; - } elseif( $title->isTalkPage() ) { + } elseif ( $title->isTalkPage() ) { $type = 'ns-talk'; } else { $type = 'ns-subject'; } + $name = Sanitizer::escapeClass( 'page-' . $title->getPrefixedText() ); + return "$numeric $type $name"; } /** + * This will be called by OutputPage::headElement when it is creating the + * <body> tag, skins can override it if they have a need to add in any + * body attributes or classes of their own. + */ + function addToBodyAttributes( $out, &$bodyAttrs ) { + // does nothing by default + } + + /** * URL to the logo */ function getLogo() { @@ -708,7 +643,7 @@ CSS; $qb = $this->qbSetting(); $langlinks = $this->otherLanguages(); - if( $langlinks ) { + if ( $langlinks ) { $rows = 2; $borderhack = ''; } else { @@ -722,16 +657,18 @@ CSS; $shove = ( $qb != 0 ); $left = ( $qb == 1 || $qb == 3 ); - if( $wgContLang->isRTL() ) { + + if ( $wgContLang->isRTL() ) { $left = !$left; } - if( !$shove ) { + if ( !$shove ) { $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" . $this->logoText() . '</td>'; - } elseif( $left ) { + } elseif ( $left ) { $s .= $this->getQuickbarCompensator( $rows ); } + $l = $wgContLang->alignStart(); $s .= "<td {$borderhack} align='$l' valign='top'>\n"; @@ -750,16 +687,19 @@ CSS; if ( $shove && !$left ) { # Right $s .= $this->getQuickbarCompensator( $rows ); } + $s .= "</tr>\n</table>\n</div>\n"; $s .= "\n<div id='article'>\n"; $notice = wfGetSiteNotice(); - if( $notice ) { + + if ( $notice ) { $s .= "\n<div id='siteNotice'>$notice</div>\n"; } $s .= $this->pageTitle(); $s .= $this->pageSubtitle(); $s .= $this->getCategories(); + wfProfileOut( __METHOD__ ); return $s; } @@ -768,7 +708,7 @@ CSS; global $wgOut, $wgUseCategoryBrowser; global $wgContLang, $wgUser; - if( count( $wgOut->mCategoryLinks ) == 0 ) { + if ( count( $wgOut->mCategoryLinks ) == 0 ) { return ''; } @@ -784,6 +724,7 @@ CSS; $allCats = $wgOut->getCategoryLinks(); $s = ''; $colon = wfMsgExt( 'colon-separator', 'escapenoentities' ); + if ( !empty( $allCats['normal'] ) ) { $t = $embed . implode( "{$pop} {$sep} {$embed}" , $allCats['normal'] ) . $pop; @@ -796,12 +737,13 @@ CSS; # Hidden categories if ( isset( $allCats['hidden'] ) ) { if ( $wgUser->getBoolOption( 'showhiddencats' ) ) { - $class ='mw-hidden-cats-user-shown'; + $class = 'mw-hidden-cats-user-shown'; } elseif ( $this->mTitle->getNamespace() == NS_CATEGORY ) { $class = 'mw-hidden-cats-ns-shown'; } else { $class = 'mw-hidden-cats-hidden'; } + $s .= "<div id=\"mw-hidden-catlinks\" class=\"$class\">" . wfMsgExt( 'hidden-categories', array( 'parsemag', 'escapenoentities' ), count( $allCats['hidden'] ) ) . $colon . $embed . implode( "$pop $sep $embed", $allCats['hidden'] ) . $pop . @@ -810,14 +752,14 @@ CSS; # optional 'dmoz-like' category browser. Will be shown under the list # of categories an article belong to - if( $wgUseCategoryBrowser ) { + if ( $wgUseCategoryBrowser ) { $s .= '<br /><hr />'; # get a big array of the parents tree $parenttree = $this->mTitle->getParentCategoryTree(); # Skin object passed by reference cause it can not be # accessed under the method subfunction drawCategoryBrowser - $tempout = explode( "\n", Skin::drawCategoryBrowser( $parenttree, $this ) ); + $tempout = explode( "\n", $this->drawCategoryBrowser( $parenttree, $this ) ); # Clean out bogus first entry and sort them unset( $tempout[0] ); asort( $tempout ); @@ -836,18 +778,21 @@ CSS; */ function drawCategoryBrowser( $tree, &$skin ) { $return = ''; - foreach( $tree as $element => $parent ) { - if( empty( $parent ) ) { + + foreach ( $tree as $element => $parent ) { + if ( empty( $parent ) ) { # element start a new list $return .= "\n"; } else { # grab the others elements - $return .= Skin::drawCategoryBrowser( $parent, $skin ) . ' > '; + $return .= $this->drawCategoryBrowser( $parent, $skin ) . ' > '; } + # add our current element to the list $eltitle = Title::newFromText( $element ); $return .= $skin->link( $eltitle, $eltitle->getText() ); } + return $return; } @@ -856,13 +801,14 @@ CSS; $classes = 'catlinks'; - // Check what we're showing global $wgOut, $wgUser; + + // Check what we're showing $allCats = $wgOut->getCategoryLinks(); $showHidden = $wgUser->getBoolOption( 'showhiddencats' ) || $this->mTitle->getNamespace() == NS_CATEGORY; - if( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) { + if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) { $classes .= ' catlinks-allhidden'; } @@ -870,7 +816,7 @@ CSS; } function getQuickbarCompensator( $rows = 1 ) { - return "<td width='152' rowspan='{$rows}'> </td>"; + return "<td width='152' rowspan='{$rows}'> </td>"; } /** @@ -890,10 +836,10 @@ CSS; protected function afterContentHook() { $data = ''; - if( wfRunHooks( 'SkinAfterContent', array( &$data ) ) ) { + if ( wfRunHooks( 'SkinAfterContent', array( &$data, $this ) ) ) { // adding just some spaces shouldn't toggle the output // of the whole <div/>, so we use trim() here - if( trim( $data ) != '' ) { + if ( trim( $data ) != '' ) { // Doing this here instead of in the skins to // ensure that the div has the same ID in all // skins @@ -915,11 +861,13 @@ CSS; */ protected function generateDebugHTML() { global $wgShowDebug, $wgOut; + if ( $wgShowDebug ) { $listInternals = $this->formatDebugHTML( $wgOut->mDebugtext ); return "\n<hr />\n<strong>Debug data:</strong><ul style=\"font-family:monospace;\" id=\"mw-debug-html\">" . $listInternals . "</ul>\n"; } + return ''; } @@ -927,8 +875,8 @@ CSS; $lines = explode( "\n", $debugText ); $curIdent = 0; $ret = '<li>'; - foreach( $lines as $line ) { - $m = array(); + + foreach ( $lines as $line ) { $display = ltrim( $line ); $ident = strlen( $line ) - strlen( $display ); $diff = $ident - $curIdent; @@ -956,7 +904,9 @@ CSS; $curIdent = $ident; } + $ret .= str_repeat( '</li></ul>', $curIdent ) . '</li>'; + return $ret; } @@ -971,11 +921,13 @@ CSS; /** * This gets called shortly before the </body> tag. + * @param $out OutputPage object * @return String HTML-wrapped JS code to be put before </body> */ - function bottomScripts() { - $bottomScriptText = "\n" . Html::inlineScript( 'if (window.runOnloadHook) runOnloadHook();' ) . "\n"; + function bottomScripts( $out ) { + $bottomScriptText = "\n" . $out->getHeadScripts( $this ); wfRunHooks( 'SkinAfterBottomScripts', array( $this, &$bottomScriptText ) ); + return $bottomScriptText; } @@ -1004,11 +956,14 @@ CSS; $s[] = $this->printableLink(); $disclaimer = $this->disclaimerLink(); # may be empty - if( $disclaimer ) { + + if ( $disclaimer ) { $s[] = $disclaimer; } + $privacy = $this->privacyLink(); # may be empty too - if( $privacy ) { + + if ( $privacy ) { $s[] = $privacy; } @@ -1016,13 +971,15 @@ CSS; if ( $this->mTitle->getNamespace() == NS_FILE ) { $name = $this->mTitle->getDBkey(); $image = wfFindFile( $this->mTitle ); - if( $image ) { + + if ( $image ) { $link = htmlspecialchars( $image->getURL() ); $style = $this->getInternalLinkAttributes( $link, $name ); $s[] = "<a href=\"{$link}\"{$style}>{$name}</a>"; } } } + if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) { $s[] .= $this->link( $this->mTitle, @@ -1036,7 +993,7 @@ CSS; if ( $wgUser->getNewtalk() ) { # do not show "You have new messages" text when we are viewing our # own talk page - if( !$this->mTitle->equals( $wgUser->getTalkPage() ) ) { + if ( !$this->mTitle->equals( $wgUser->getTalkPage() ) ) { $tl = $this->link( $wgUser->getTalkPage(), wfMsgHtml( 'newmessageslink' ), @@ -1052,7 +1009,7 @@ CSS; array( 'diff' => 'cur' ), array( 'known', 'noclasses' ) ); - $s[] = '<strong>'. wfMsg( 'youhavenewmessages', $tl, $dl ) . '</strong>'; + $s[] = '<strong>' . wfMsg( 'youhavenewmessages', $tl, $dl ) . '</strong>'; # disable caching $wgOut->setSquidMaxage( 0 ); $wgOut->enableClientCache( false ); @@ -1060,26 +1017,30 @@ CSS; } $undelete = $this->getUndeleteLink(); - if( !empty( $undelete ) ) { + + if ( !empty( $undelete ) ) { $s[] = $undelete; } + return $wgLang->pipeList( $s ); } function getUndeleteLink() { - global $wgUser, $wgContLang, $wgLang, $wgRequest; + global $wgUser, $wgLang, $wgRequest; $action = $wgRequest->getVal( 'action', 'view' ); if ( $wgUser->isAllowed( 'deletedhistory' ) && ( $this->mTitle->getArticleId() == 0 || $action == 'history' ) ) { $n = $this->mTitle->isDeleted(); + if ( $n ) { if ( $wgUser->isAllowed( 'undelete' ) ) { $msg = 'thisisdeleted'; } else { $msg = 'viewdeleted'; } + return wfMsg( $msg, $this->link( @@ -1092,6 +1053,7 @@ CSS; ); } } + return ''; } @@ -1105,8 +1067,8 @@ CSS; $s[] = "<a href=\"$printurl\" rel=\"alternate\">" . wfMsg( 'printableversion' ) . '</a>'; } - if( $wgOut->isSyndicated() ) { - foreach( $wgFeedClasses as $format => $class ) { + if ( $wgOut->isSyndicated() ) { + foreach ( $wgFeedClasses as $format => $class ) { $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" ); $s[] = "<a href=\"$feedurl\" rel=\"alternate\" type=\"application/{$format}+xml\"" . " class=\"feedlink\">" . wfMsgHtml( "feed-$format" ) . "</a>"; @@ -1129,36 +1091,43 @@ CSS; global $wgOut; $sub = $wgOut->getSubtitle(); + if ( $sub == '' ) { global $wgExtraSubtitle; $sub = wfMsgExt( 'tagline', 'parsemag' ) . $wgExtraSubtitle; } + $subpages = $this->subPageSubtitle(); $sub .= !empty( $subpages ) ? "</p><p class='subpages'>$subpages" : ''; $s = "<p class='subtitle'>{$sub}</p>\n"; + return $s; } function subPageSubtitle() { $subpages = ''; - if( !wfRunHooks( 'SkinSubPageSubtitle', array( &$subpages ) ) ) { + + if ( !wfRunHooks( 'SkinSubPageSubtitle', array( &$subpages, $this ) ) ) { return $subpages; } global $wgOut; - if( $wgOut->isArticle() && MWNamespace::hasSubpages( $this->mTitle->getNamespace() ) ) { + + if ( $wgOut->isArticle() && MWNamespace::hasSubpages( $this->mTitle->getNamespace() ) ) { $ptext = $this->mTitle->getPrefixedText(); - if( preg_match( '/\//', $ptext ) ) { + if ( preg_match( '/\//', $ptext ) ) { $links = explode( '/', $ptext ); array_pop( $links ); $c = 0; $growinglink = ''; $display = ''; - foreach( $links as $link ) { + + foreach ( $links as $link ) { $growinglink .= $link; $display .= $link; $linkObj = Title::newFromText( $growinglink ); - if( is_object( $linkObj ) && $linkObj->exists() ) { + + if ( is_object( $linkObj ) && $linkObj->exists() ) { $getlink = $this->link( $linkObj, htmlspecialchars( $display ), @@ -1166,12 +1135,15 @@ CSS; array(), array( 'known', 'noclasses' ) ); + $c++; - if( $c > 1 ) { + + if ( $c > 1 ) { $subpages .= wfMsgExt( 'pipe-separator', 'escapenoentities' ); } else { $subpages .= '< '; } + $subpages .= $getlink; $display = ''; } else { @@ -1181,6 +1153,7 @@ CSS; } } } + return $subpages; } @@ -1198,8 +1171,9 @@ CSS; $logoutPage = $wgContLang->specialPage( 'Userlogout' ); $ret = ''; + if ( $wgUser->isAnon() ) { - if( $this->showIPinHeader() ) { + if ( $this->showIPinHeader() ) { $name = wfGetIP(); $talkLink = $this->link( $wgUser->getTalkPage(), @@ -1212,6 +1186,7 @@ CSS; $returnTo = $this->mTitle->getPrefixedDBkey(); $query = array(); + if ( $logoutPage != $returnTo ) { $query['returnto'] = $returnTo; } @@ -1236,9 +1211,10 @@ CSS; SpecialPage::getTitleFor( 'Userlogout' ), wfMsg( 'logout' ), array(), array( 'returnto' => $returnTo ) ), - $this->specialLink( 'preferences' ), + $this->specialLink( 'Preferences' ), ) ); } + $ret = $wgLang->pipeList( array( $ret, $this->link( @@ -1261,6 +1237,7 @@ CSS; function searchForm() { global $wgRequest, $wgUseTwoButtonsSearchForm; + $search = $wgRequest->getText( 'search' ); $s = '<form id="searchform' . $this->searchboxes . '" name="search" class="inline" method="post" action="' @@ -1269,8 +1246,8 @@ CSS; . htmlspecialchars( substr( $search, 0, 256 ) ) . "\" />\n" . '<input type="submit" name="go" value="' . wfMsg( 'searcharticle' ) . '" />'; - if( $wgUseTwoButtonsSearchForm ) { - $s .= ' <input type="submit" name="fulltext" value="' . wfMsg( 'searchbutton' ) . "\" />\n"; + if ( $wgUseTwoButtonsSearchForm ) { + $s .= ' <input type="submit" name="fulltext" value="' . wfMsg( 'searchbutton' ) . "\" />\n"; } else { $s .= ' <a href="' . $this->escapeSearchLink() . '" rel="search">' . wfMsg( 'powersearch-legend' ) . "</a>\n"; } @@ -1288,25 +1265,26 @@ CSS; $s = array( $this->mainPageLink(), - $this->specialLink( 'recentchanges' ) + $this->specialLink( 'Recentchanges' ) ); if ( $wgOut->isArticleRelated() ) { $s[] = $this->editThisPage(); $s[] = $this->historyLink(); } + # Many people don't like this dropdown box - #$s[] = $this->specialPagesList(); + # $s[] = $this->specialPagesList(); - if( $this->variantLinks() ) { + if ( $this->variantLinks() ) { $s[] = $this->variantLinks(); } - if( $this->extensionTabLinks() ) { + if ( $this->extensionTabLinks() ) { $s[] = $this->extensionTabLinks(); } - // FIXME: Is using Language::pipeList impossible here? Do not quite understand the use of the newline + // @todo FIXME: Is using Language::pipeList impossible here? Do not quite understand the use of the newline return implode( $s, wfMsgExt( 'pipe-separator', 'escapenoentities' ) . "\n" ); } @@ -1321,13 +1299,13 @@ CSS; $out = ''; $s = array(); wfRunHooks( 'SkinTemplateTabs', array( $this, &$tabs ) ); - foreach( $tabs as $tab ) { + foreach ( $tabs as $tab ) { $s[] = Xml::element( 'a', array( 'href' => $tab['href'] ), $tab['text'] ); } - if( count( $s ) ) { + if ( count( $s ) ) { global $wgLang; $out = wfMsgExt( 'pipe-separator' , 'escapenoentities' ); @@ -1343,13 +1321,17 @@ CSS; */ function variantLinks() { $s = ''; + /* show links to different language variants */ global $wgDisableLangConversion, $wgLang, $wgContLang; + $variants = $wgContLang->getVariants(); - if( !$wgDisableLangConversion && sizeof( $variants ) > 1 ) { - foreach( $variants as $code ) { + + if ( !$wgDisableLangConversion && sizeof( $variants ) > 1 ) { + foreach ( $variants as $code ) { $varname = $wgContLang->getVariantname( $code ); - if( $varname == 'disable' ) { + + if ( $varname == 'disable' ) { continue; } $s = $wgLang->pipeList( array( @@ -1358,6 +1340,7 @@ CSS; ) ); } } + return $s; } @@ -1368,31 +1351,33 @@ CSS; $s = ''; if ( $wgOut->isArticleRelated() ) { $element[] = '<strong>' . $this->editThisPage() . '</strong>'; + if ( $wgUser->isLoggedIn() ) { $element[] = $this->watchThisPage(); } + $element[] = $this->talkLink(); $element[] = $this->historyLink(); $element[] = $this->whatLinksHere(); $element[] = $this->watchPageLinksLink(); - if( $wgUseTrackbacks ) { + if ( $wgUseTrackbacks ) { $element[] = $this->trackbackLink(); } if ( $this->mTitle->getNamespace() == NS_USER || $this->mTitle->getNamespace() == NS_USER_TALK - ) - { + ) { $id = User::idFromName( $this->mTitle->getText() ); $ip = User::isIP( $this->mTitle->getText() ); # Both anons and non-anons have contributions list - if( $id || $ip ) { + if ( $id || $ip ) { $element[] = $this->userContribsLink(); } - if( $this->showEmailUser( $id ) ) { + + if ( $this->showEmailUser( $id ) ) { $element[] = $this->emailUserLink(); } } @@ -1401,17 +1386,21 @@ CSS; if ( $this->mTitle->getArticleId() ) { $s .= "\n<br />"; + // Delete/protect/move links for privileged users - if( $wgUser->isAllowed( 'delete' ) ) { + if ( $wgUser->isAllowed( 'delete' ) ) { $s .= $this->deleteThisPage(); } - if( $wgUser->isAllowed( 'protect' ) ) { + + if ( $wgUser->isAllowed( 'protect' ) ) { $s .= $sep . $this->protectThisPage(); } - if( $wgUser->isAllowed( 'move' ) ) { + + if ( $wgUser->isAllowed( 'move' ) ) { $s .= $sep . $this->moveThisPage(); } } + $s .= "<br />\n" . $this->otherLanguages(); } @@ -1424,34 +1413,40 @@ CSS; $oldid = $wgRequest->getVal( 'oldid' ); $diff = $wgRequest->getVal( 'diff' ); + if ( !$wgOut->isArticle() ) { return ''; } - if( !$wgArticle instanceof Article ) { + + if ( !$wgArticle instanceof Article ) { return ''; } + if ( isset( $oldid ) || isset( $diff ) ) { return ''; } + if ( 0 == $wgArticle->getID() ) { return ''; } $s = ''; + if ( !$wgDisableCounters ) { $count = $wgLang->formatNum( $wgArticle->getCount() ); + if ( $count ) { $s = wfMsgExt( 'viewcount', array( 'parseinline' ), $count ); } } - if( $wgMaxCredits != 0 ) { + if ( $wgMaxCredits != 0 ) { $s .= ' ' . Credits::getCredits( $wgArticle, $wgMaxCredits, $wgShowCreditsIfMax ); } else { $s .= $this->lastModified(); } - if( $wgPageShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' ) ) { + if ( $wgPageShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' ) ) { $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'watchlist', @@ -1478,6 +1473,7 @@ CSS; if ( $type == 'detect' ) { $diff = $wgRequest->getVal( 'diff' ); $isCur = $wgArticle && $wgArticle->isCurrent(); + if ( is_null( $diff ) && !$isCur && wfMsgForContent( 'history_copyright' ) !== '-' ) { $type = 'history'; } else { @@ -1492,43 +1488,58 @@ CSS; } $out = ''; - if( $wgRightsPage ) { + + if ( $wgRightsPage ) { $title = Title::newFromText( $wgRightsPage ); $link = $this->linkKnown( $title, $wgRightsText ); - } elseif( $wgRightsUrl ) { + } elseif ( $wgRightsUrl ) { $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText ); - } elseif( $wgRightsText ) { + } elseif ( $wgRightsText ) { $link = $wgRightsText; } else { # Give up now return $out; } + // Allow for site and per-namespace customization of copyright notice. - if( isset( $wgArticle ) ) { - wfRunHooks( 'SkinCopyrightFooter', array( $wgArticle->getTitle(), $type, &$msg, &$link ) ); + $forContent = true; + + if ( isset( $wgArticle ) ) { + wfRunHooks( 'SkinCopyrightFooter', array( $wgArticle->getTitle(), $type, &$msg, &$link, &$forContent ) ); + } + + if ( $forContent ) { + $out .= wfMsgForContent( $msg, $link ); + } else { + $out .= wfMsg( $msg, $link ); } - $out .= wfMsgForContent( $msg, $link ); return $out; } function getCopyrightIcon() { global $wgRightsUrl, $wgRightsText, $wgRightsIcon, $wgCopyrightIcon; + $out = ''; + if ( isset( $wgCopyrightIcon ) && $wgCopyrightIcon ) { $out = $wgCopyrightIcon; } elseif ( $wgRightsIcon ) { $icon = htmlspecialchars( $wgRightsIcon ); + if ( $wgRightsUrl ) { $url = htmlspecialchars( $wgRightsUrl ); - $out .= '<a href="'.$url.'">'; + $out .= '<a href="' . $url . '">'; } + $text = htmlspecialchars( $wgRightsText ); $out .= "<img src=\"$icon\" alt=\"$text\" width=\"88\" height=\"31\" />"; + if ( $wgRightsUrl ) { $out .= '</a>'; } } + return $out; } @@ -1538,18 +1549,22 @@ CSS; */ function getPoweredBy() { global $wgStylePath; + $url = htmlspecialchars( "$wgStylePath/common/images/poweredby_mediawiki_88x31.png" ); - $img = '<a href="http://www.mediawiki.org/"><img src="' . $url . '" height="31" width="88" alt="Powered by MediaWiki" /></a>'; - return $img; + $text = '<a href="http://www.mediawiki.org/"><img src="' . $url . '" height="31" width="88" alt="Powered by MediaWiki" /></a>'; + wfRunHooks( 'SkinGetPoweredBy', array( &$text, $this ) ); + return $text; } function lastModified() { global $wgLang, $wgArticle; - if( $this->mRevisionId && $this->mRevisionId != $wgArticle->getLatest() ) { + + if ( $this->mRevisionId && $this->mRevisionId != $wgArticle->getLatest() ) { $timestamp = Revision::getTimestampFromId( $wgArticle->getTitle(), $this->mRevisionId ); } else { $timestamp = $wgArticle->getTimestamp(); } + if ( $timestamp ) { $d = $wgLang->date( $timestamp, true ); $t = $wgLang->time( $timestamp, true ); @@ -1557,9 +1572,11 @@ CSS; } else { $s = ''; } + if ( wfGetLB()->getLaggedSlaveMode() ) { $s .= ' <strong>' . wfMsg( 'laggedslavemode' ) . '</strong>'; } + return $s; } @@ -1576,6 +1593,7 @@ CSS; $logourl = $this->getLogo(); $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>"; + return $s; } @@ -1583,8 +1601,10 @@ CSS; * Show a drop-down box of special pages */ function specialPagesList() { - global $wgUser, $wgContLang, $wgServer, $wgRedirectScript; + global $wgContLang, $wgServer, $wgRedirectScript; + $pages = array_merge( SpecialPage::getRegularPages(), SpecialPage::getRestrictedPages() ); + foreach ( $pages as $name => $page ) { $pages[$name] = $page->getDescription(); } @@ -1603,13 +1623,38 @@ CSS; $p = $wgContLang->specialPage( $name ); $s .= "<option value=\"{$p}\">{$desc}</option>\n"; } + $s .= "</select>\n"; $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n"; $s .= "</form>\n"; + return $s; } /** + * 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 Boolean: Whether to use the icon's image or output a text-only footericon + */ + function makeFooterIcon( $icon, $withImage = 'withImage' ) { + if ( is_string( $icon ) ) { + $html = $icon; + } else { // Assuming array + $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 + } else { + $html = htmlspecialchars( $icon["alt"] ); + } + if ( $url ) { + $html = Html::rawElement( 'a', array( "href" => $url ), $html ); + } + } + return $html; + } + + /** * Gets the link to the wiki's main page. * @return string */ @@ -1621,12 +1666,13 @@ CSS; array(), array( 'known', 'noclasses' ) ); + return $s; } - private function footerLink( $desc, $page ) { + public function footerLink( $desc, $page ) { // if the link description has been set to "-" in the default language, - if ( wfMsgForContent( $desc ) == '-') { + if ( wfMsgForContent( $desc ) == '-' ) { // then it is disabled, for all languages. return ''; } else { @@ -1634,6 +1680,7 @@ CSS; // language (which may or may not be the same as the default language), // but we make the link target be the one site-wide page. $title = Title::newFromText( wfMsgForContent( $page ) ); + return $this->linkKnown( $title, wfMsgExt( $desc, array( 'parsemag', 'escapenoentities' ) ) @@ -1668,9 +1715,9 @@ CSS; if ( !$wgOut->isArticleRelated() ) { $s = wfMsg( 'protectedpage' ); } else { - if( $this->mTitle->quickUserCan( 'edit' ) && $this->mTitle->exists() ) { + if ( $this->mTitle->quickUserCan( 'edit' ) && $this->mTitle->exists() ) { $t = wfMsg( 'editthispage' ); - } elseif( $this->mTitle->quickUserCan( 'create' ) && !$this->mTitle->exists() ) { + } elseif ( $this->mTitle->quickUserCan( 'create' ) && !$this->mTitle->exists() ) { $t = wfMsg( 'create-this-page' ); } else { $t = wfMsg( 'viewsource' ); @@ -1684,6 +1731,7 @@ CSS; array( 'known', 'noclasses' ) ); } + return $s; } @@ -1699,7 +1747,7 @@ CSS; $options = array( 'action' => 'edit' ); - if( $this->mRevisionId && ! $wgArticle->isCurrent() ) { + if ( $this->mRevisionId && ! $wgArticle->isCurrent() ) { $options['oldid'] = intval( $this->mRevisionId ); } @@ -1710,6 +1758,7 @@ CSS; global $wgUser, $wgRequest; $diff = $wgRequest->getVal( 'diff' ); + if ( $this->mTitle->getArticleId() && ( !$diff ) && $wgUser->isAllowed( 'delete' ) ) { $t = wfMsg( 'deletethispage' ); @@ -1723,6 +1772,7 @@ CSS; } else { $s = ''; } + return $s; } @@ -1730,7 +1780,8 @@ CSS; global $wgUser, $wgRequest; $diff = $wgRequest->getVal( 'diff' ); - if ( $this->mTitle->getArticleId() && ( ! $diff ) && $wgUser->isAllowed('protect') ) { + + if ( $this->mTitle->getArticleId() && ( ! $diff ) && $wgUser->isAllowed( 'protect' ) ) { if ( $this->mTitle->isProtected() ) { $text = wfMsg( 'unprotectthispage' ); $query = array( 'action' => 'unprotect' ); @@ -1749,6 +1800,7 @@ CSS; } else { $s = ''; } + return $s; } @@ -1777,6 +1829,7 @@ CSS; } else { $s = wfMsg( 'notanarticle' ); } + return $s; } @@ -1843,6 +1896,7 @@ CSS; function watchPageLinksLink() { global $wgOut; + if ( !$wgOut->isArticleRelated() ) { return '(' . wfMsg( 'notanarticle' ) . ')'; } else { @@ -1869,34 +1923,42 @@ CSS; } $a = $wgOut->getLanguageLinks(); + if ( 0 == count( $a ) ) { return ''; } $s = wfMsg( 'otherlanguages' ) . wfMsg( 'colon-separator' ); $first = true; - if( $wgContLang->isRTL() ) { + + if ( $wgContLang->isRTL() ) { $s .= '<span dir="LTR">'; } - foreach( $a as $l ) { + + foreach ( $a as $l ) { if ( !$first ) { $s .= wfMsgExt( 'pipe-separator', 'escapenoentities' ); } + $first = false; $nt = Title::newFromText( $l ); $url = $nt->escapeFullURL(); $text = $wgContLang->getLanguageName( $nt->getInterwiki() ); + $title = htmlspecialchars( $nt->getText() ); if ( $text == '' ) { $text = $l; } + $style = $this->getExternalLinkAttributes(); - $s .= "<a href=\"{$url}\"{$style}>{$text}</a>"; + $s .= "<a href=\"{$url}\" title=\"{$title}\"{$style}>{$text}</a>"; } - if( $wgContLang->isRTL() ) { + + if ( $wgContLang->isRTL() ) { $s .= '</span>'; } + return $s; } @@ -1908,7 +1970,7 @@ CSS; $linkOptions = array(); - if( $this->mTitle->isTalkPage() ) { + if ( $this->mTitle->isTalkPage() ) { $link = $this->mTitle->getSubjectPage(); switch( $link->getNamespace() ) { case NS_MAIN: @@ -1923,7 +1985,7 @@ CSS; case NS_FILE: $text = wfMsg( 'imagepage' ); # Make link known if image exists, even if the desc. page doesn't. - if( wfFindFile( $link ) ) + if ( wfFindFile( $link ) ) $linkOptions[] = 'known'; break; case NS_MEDIAWIKI: @@ -1961,9 +2023,9 @@ CSS; # __NEWSECTIONLINK___ changes behaviour here # If it is present, the link points to this page, otherwise # it points to the talk page - if( $this->mTitle->isTalkPage() ) { + if ( $this->mTitle->isTalkPage() ) { $title = $this->mTitle; - } elseif( $wgOut->showNewSectionLink() ) { + } elseif ( $wgOut->showNewSectionLink() ) { $title = $this->mTitle; } else { $title = $this->mTitle->getTalkPage(); @@ -1981,10 +2043,52 @@ CSS; ); } + function getUploadLink() { + global $wgUploadNavigationUrl; + + if ( $wgUploadNavigationUrl ) { + # Using an empty class attribute to avoid automatic setting of "external" class + return $this->makeExternalLink( $wgUploadNavigationUrl, wfMsgHtml( 'upload' ), false, null, array( 'class' => '' ) ); + } else { + return $this->link( + SpecialPage::getTitleFor( 'Upload' ), + wfMsgHtml( 'upload' ), + array(), + array(), + array( 'known', 'noclasses' ) + ); + } + } + + /** + * 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 the common file to return the full path for. + * @return String The fully resolved style path url including styleversion + */ + function getCommonStylePath( $name ) { + global $wgStylePath, $wgStyleVersion; + return "{$wgStylePath}/common/$name?{$wgStyleVersion}"; + } + + /** + * Return a fully resolved style path url to images or styles stored in the curent 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 the skin resource file to return the full path for. + * @return String The fully resolved style path url including styleversion + */ + function getSkinStylePath( $name ) { + global $wgStylePath, $wgStyleVersion; + return "{$wgStylePath}/{$this->stylename}/$name?{$wgStyleVersion}"; + } + /* these are used extensively in SkinTemplate, but also some other places */ static function makeMainPageUrl( $urlaction = '' ) { $title = Title::newMainPage(); self::checkTitle( $title, '' ); + return $title->getLocalURL( $urlaction ); } @@ -2007,6 +2111,7 @@ CSS; static function makeUrl( $name, $urlaction = '' ) { $title = Title::newFromText( $name ); self::checkTitle( $title, $name ); + return $title->getLocalURL( $urlaction ); } @@ -2026,6 +2131,7 @@ CSS; static function makeNSUrl( $name, $urlaction = '', $namespace = NS_MAIN ) { $title = Title::makeTitleSafe( $namespace, $name ); self::checkTitle( $title, $name ); + return $title->getLocalURL( $urlaction ); } @@ -2033,9 +2139,10 @@ CSS; static function makeUrlDetails( $name, $urlaction = '' ) { $title = Title::newFromText( $name ); self::checkTitle( $title, $name ); + return array( 'href' => $title->getLocalURL( $urlaction ), - 'exists' => $title->getArticleID() != 0 ? true : false + 'exists' => $title->getArticleID() != 0, ); } @@ -2045,6 +2152,7 @@ CSS; static function makeKnownUrlDetails( $name, $urlaction = '' ) { $title = Title::newFromText( $name ); self::checkTitle( $title, $name ); + return array( 'href' => $title->getLocalURL( $urlaction ), 'exists' => true @@ -2053,9 +2161,9 @@ CSS; # make sure we have some title to operate on static function checkTitle( &$title, $name ) { - if( !is_object( $title ) ) { + if ( !is_object( $title ) ) { $title = Title::newFromText( $name ); - if( !is_object( $title ) ) { + if ( !is_object( $title ) ) { $title = Title::newFromText( '--error: link target missing--' ); } } @@ -2088,6 +2196,7 @@ CSS; if ( $wgEnableSidebarCache ) { $parserMemc->set( $key, $bar, $wgSidebarCacheExpiry ); } + wfProfileOut( __METHOD__ ); return $bar; } @@ -2095,34 +2204,55 @@ CSS; * Add content from a sidebar system message * Currently only used for MediaWiki:Sidebar (but may be used by Extensions) * + * This is just a wrapper around addToSidebarPlain() for backwards compatibility + * * @param &$bar array * @param $message String */ function addToSidebar( &$bar, $message ) { - $lines = explode( "\n", wfMsgForContent( $message ) ); + $this->addToSidebarPlain( $bar, wfMsgForContent( $message ) ); + } + + /** + * Add content from plain text + * @since 1.17 + * @param &$bar array + * @param $text string + */ + function addToSidebarPlain( &$bar, $text ) { + $lines = explode( "\n", $text ); + $wikiBar = array(); # We need to handle the wikitext on a different variable, to avoid trying to do an array operation on text, which would be a fatal error. + $heading = ''; - foreach( $lines as $line ) { - if( strpos( $line, '*' ) !== 0 ) { + + foreach ( $lines as $line ) { + if ( strpos( $line, '*' ) !== 0 ) { continue; } - if( strpos( $line, '**') !== 0 ) { + + if ( strpos( $line, '**' ) !== 0 ) { $heading = trim( $line, '* ' ); - if( !array_key_exists( $heading, $bar ) ) { + if ( !array_key_exists( $heading, $bar ) ) { $bar[$heading] = array(); } } else { - if( strpos( $line, '|' ) !== false ) { // sanity check - $line = array_map( 'trim', explode( '|', trim( $line, '* ' ), 2 ) ); + $line = trim( $line, '* ' ); + + if ( strpos( $line, '|' ) !== false ) { // sanity check + $line = array_map( 'trim', explode( '|', $line, 2 ) ); $link = wfMsgForContent( $line[0] ); - if( $link == '-' ) { + + if ( $link == '-' ) { continue; } $text = wfMsgExt( $line[1], 'parsemag' ); - if( wfEmptyMsg( $line[1], $text ) ) { + + if ( wfEmptyMsg( $line[1], $text ) ) { $text = $line[1]; } - if( wfEmptyMsg( $line[0], $link ) ) { + + if ( wfEmptyMsg( $line[0], $link ) ) { $link = $line[0]; } @@ -2130,6 +2260,7 @@ CSS; $href = $link; } else { $title = Title::newFromText( $link ); + if ( $title ) { $title = $title->fixSpecialName(); $href = $title->getLocalURL(); @@ -2144,11 +2275,26 @@ CSS; 'id' => 'n-' . strtr( $line[1], ' ', '-' ), 'active' => false ); + } else if ( ( substr( $line, 0, 2 ) == '{{' ) && ( substr( $line, -2 ) == '}}' ) ) { + global $wgParser, $wgTitle; + + $line = substr( $line, 2, strlen( $line ) - 4 ); + + $options = new ParserOptions(); + $options->setEditSection( false ); + $options->setInterfaceMessage( true ); + $wikiBar[$heading] = $wgParser->parse( wfMsgForContentNoTrans( $line ) , $wgTitle, $options )->getText(); } else { continue; } } } + + if ( count( $wikiBar ) > 0 ) { + $bar = array_merge( $bar, $wikiBar ); + } + + return $bar; } /** @@ -2162,4 +2308,62 @@ CSS; public function commonPrintStylesheet() { return true; } + + /** + * Gets new talk page messages for the current user. + * @return MediaWiki message or if no new talk page messages, nothing + */ + function getNewtalks() { + global $wgUser, $wgOut; + + $newtalks = $wgUser->getNewMessageLinks(); + $ntl = ''; + + if ( count( $newtalks ) == 1 && $newtalks[0]['wiki'] === wfWikiID() ) { + $userTitle = $this->mUser->getUserPage(); + $userTalkTitle = $userTitle->getTalkPage(); + + if ( !$userTalkTitle->equals( $this->mTitle ) ) { + $newMessagesLink = $this->link( + $userTalkTitle, + wfMsgHtml( 'newmessageslink' ), + array(), + array( 'redirect' => 'no' ), + array( 'known', 'noclasses' ) + ); + + $newMessagesDiffLink = $this->link( + $userTalkTitle, + wfMsgHtml( 'newmessagesdifflink' ), + array(), + array( 'diff' => 'cur' ), + array( 'known', 'noclasses' ) + ); + + $ntl = wfMsg( + 'youhavenewmessages', + $newMessagesLink, + $newMessagesDiffLink + ); + # Disable Squid cache + $wgOut->setSquidMaxage( 0 ); + } + } elseif ( count( $newtalks ) ) { + // _>" " for BC <= 1.16 + $sep = str_replace( '_', ' ', wfMsgHtml( 'newtalkseparator' ) ); + $msgs = array(); + + foreach ( $newtalks as $newtalk ) { + $msgs[] = Xml::element( + 'a', + array( 'href' => $newtalk['link'] ), $newtalk['wiki'] + ); + } + $parts = implode( $sep, $msgs ); + $ntl = wfMsgHtml( 'youhavenewmessagesmulti', $parts ); + $wgOut->setSquidMaxage( 0 ); + } + + return $ntl; + } } |