From a3b490d2c4dfc25d7e0594eae8ee27ba69f6afea Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Mon, 30 Oct 2006 06:25:31 +0000 Subject: [PATCH] * Made special page names case-insensitive and localisable. Care has been taken to maintain backwards compatibility. * Used special page subpages in a few more places, instead of query parameters --- RELEASE-NOTES | 3 + includes/Article.php | 4 +- includes/ChangesList.php | 24 +- includes/EditPage.php | 2 +- includes/ImagePage.php | 6 +- includes/Linker.php | 10 +- includes/LogPage.php | 4 +- includes/OutputPage.php | 2 +- includes/PageHistory.php | 4 +- includes/Parser.php | 2 +- includes/ProxyTools.php | 2 +- includes/QueryPage.php | 4 +- includes/SearchEngine.php | 2 +- includes/Skin.php | 43 ++- includes/SkinTemplate.php | 22 +- includes/SpecialAllpages.php | 6 +- includes/SpecialBlockip.php | 4 +- includes/SpecialConfirmemail.php | 8 +- includes/SpecialContributions.php | 8 +- includes/SpecialEmailuser.php | 4 +- includes/SpecialExport.php | 2 +- includes/SpecialIpblocklist.php | 8 +- includes/SpecialLockdb.php | 4 +- includes/SpecialLog.php | 4 +- includes/SpecialMostlinked.php | 4 +- includes/SpecialMovepage.php | 4 +- includes/SpecialNewimages.php | 2 +- includes/SpecialNewpages.php | 2 +- includes/SpecialPage.php | 504 +++++++++++++++++++--------- includes/SpecialPreferences.php | 6 +- includes/SpecialRecentchanges.php | 2 +- includes/SpecialRevisiondelete.php | 2 +- includes/SpecialSearch.php | 4 +- includes/SpecialUndelete.php | 6 +- includes/SpecialUnlockdb.php | 4 +- includes/SpecialUnusedtemplates.php | 2 +- includes/SpecialUpload.php | 6 +- includes/SpecialUserlogin.php | 8 +- includes/SpecialUserrights.php | 2 +- includes/SpecialWantedpages.php | 2 +- includes/SpecialWatchlist.php | 8 +- includes/Title.php | 34 +- includes/User.php | 2 +- includes/UserMailer.php | 2 +- includes/Wiki.php | 8 +- includes/api/ApiFeedWatchlist.php | 4 +- languages/Language.php | 39 ++- languages/messages/MessagesEn.php | 77 +++++ maintenance/dumpHTML.inc | 2 +- opensearch_desc.php | 2 +- skins/CologneBlue.php | 6 +- 51 files changed, 636 insertions(+), 290 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index c592aa2773..aa86281df3 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -107,6 +107,9 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN required. * (bug 5051) Accesskeys no longer require JavaScript. * Correctly detect browser accesskey prefix for all buttons, not just most. +* Made special page names case-insensitive and localisable. Care has been taken + to maintain backwards compatibility. +* Used special page subpages in a few more places, instead of query parameters. == Languages updated == diff --git a/includes/Article.php b/includes/Article.php index c422cc1913..6bc38c56aa 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -85,7 +85,7 @@ class Article { // // This can be hard to reverse, so they may be disabled. - if( $rt->getNamespace() == NS_SPECIAL && $rt->getText() == 'Userlogout' ) { + if( $rt->isSpecial( 'Userlogout' ) ) { // rolleyes } else { return $rt->getFullURL(); @@ -1473,7 +1473,7 @@ class Article { $wgOut->setPagetitle( wfMsg( 'markedaspatrolled' ) ); $wgOut->addWikiText( wfMsg( 'markedaspatrolledtext' ) ); } - $rcTitle = Title::makeTitle( NS_SPECIAL, 'Recentchanges' ); + $rcTitle = SpecialPage::getTitleFor( 'Recentchanges' ); $wgOut->returnToMain( false, $rcTitle->getPrefixedText() ); } else { diff --git a/includes/ChangesList.php b/includes/ChangesList.php index 6797bb41d0..fe3ec1b32d 100644 --- a/includes/ChangesList.php +++ b/includes/ChangesList.php @@ -246,8 +246,13 @@ class OldChangesList extends ChangesList { if( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { $this->insertMove( $s, $rc ); // log entries - } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) { - $this->insertLog($s, $rc->getTitle(), $matches[1]); + } elseif ( $rc_namespace == NS_SPECIAL ) { + list( $specialName, $specialSubpage ) = SpecialPage::resolveAliasWithSubpage( $rc_title ); + if ( $specialName == 'Log' ) { + $this->insertLog( $s, $rc->getTitle(), $specialSubpage ); + } else { + wfDebug( "Unexpected special page in recentchanges\n" ); + } // all other stuff } else { wfProfileIn($fname.'-page'); @@ -321,11 +326,16 @@ class EnhancedChangesList extends ChangesList { $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir"; $clink = wfMsg( $msg, $this->skin->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ), $this->skin->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) ); - } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) { - # Log updates, etc - $logtype = $matches[1]; - $logname = LogPage::logName( $logtype ); - $clink = '(' . $this->skin->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')'; + } elseif( $rc_namespace == NS_SPECIAL ) { + list( $specialName, $logtype ) = SpecialPage::resolveAliasWithSubpage( $rc_title ); + if ( $specialName == 'Log' ) { + # Log updates, etc + $logname = LogPage::logName( $logtype ); + $clink = '(' . $this->skin->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')'; + } else { + wfDebug( "Unexpected special page in recentchanges\n" ); + $clink = ''; + } } elseif( $rc->unpatrolled && $rc_type == RC_NEW ) { # Unpatrolled new page, give rc_id in query $clink = $this->skin->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" ); diff --git a/includes/EditPage.php b/includes/EditPage.php index ef60aee69c..27bcb0e7ce 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -1436,7 +1436,7 @@ END global $wgUser, $wgOut; $skin = $wgUser->getSkin(); - $loginTitle = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); + $loginTitle = SpecialPage::getTitleFor( 'Userlogin' ); $loginLink = $skin->makeKnownLinkObj( $loginTitle, wfMsgHtml( 'loginreqlink' ), 'returnto=' . $this->mTitle->getPrefixedUrl() ); $wgOut->setPageTitle( wfMsg( 'whitelistedittitle' ) ); diff --git a/includes/ImagePage.php b/includes/ImagePage.php index 02c4c2e353..86a15008fb 100644 --- a/includes/ImagePage.php +++ b/includes/ImagePage.php @@ -333,7 +333,7 @@ END } else { # Image does not exist - $title = Title::makeTitle( NS_SPECIAL, 'Upload' ); + $title = SpecialPage::getTitleFor( 'Upload' ); $link = $sk->makeKnownLinkObj($title, wfMsgHtml('noimage-linktext'), 'wpDestFile=' . urlencode( $this->img->getName() ) ); $wgOut->addHTML( wfMsgWikiHtml( 'noimage', $link ) ); @@ -348,7 +348,7 @@ END if ($wgRepositoryBaseUrl && !$wgFetchCommonsDescriptions) { $sk = $wgUser->getSkin(); - $title = Title::makeTitle( NS_SPECIAL, 'Upload' ); + $title = SpecialPage::getTitleFor( 'Upload' ); $link = $sk->makeKnownLinkObj($title, wfMsgHtml('shareduploadwiki-linktext'), array( 'wpDestFile' => urlencode( $this->img->getName() ))); $sharedtext .= " " . wfMsgWikiHtml('shareduploadwiki', $link); @@ -365,7 +365,7 @@ END function getUploadUrl() { global $wgServer; - $uploadTitle = Title::makeTitle( NS_SPECIAL, 'Upload' ); + $uploadTitle = SpecialPage::getTitleFor( 'Upload' ); return $wgServer . $uploadTitle->getLocalUrl( 'wpDestFile=' . urlencode( $this->img->getName() ) ); } diff --git a/includes/Linker.php b/includes/Linker.php index 53deb39f2b..f4a59d6271 100644 --- a/includes/Linker.php +++ b/includes/Linker.php @@ -673,7 +673,7 @@ class Linker { if ( '' != $query ) { $q .= "&$query"; } - $uploadTitle = Title::makeTitle( NS_SPECIAL, 'Upload' ); + $uploadTitle = SpecialPage::getTitleFor( 'Upload' ); $url = $uploadTitle->escapeLocalURL( $q ); if ( '' == $text ) { @@ -716,7 +716,7 @@ class Linker { $url = $img->getURL(); $class = 'internal'; } else { - $upload = Title::makeTitle( NS_SPECIAL, 'Upload' ); + $upload = SpecialPage::getTitleFor( 'Upload' ); $url = $upload->getLocalUrl( 'wpDestFile=' . urlencode( $img->getName() ) ); $class = 'new'; } @@ -763,7 +763,7 @@ class Linker { function userLink( $userId, $userText ) { $encName = htmlspecialchars( $userText ); if( $userId == 0 ) { - $contribsPage = Title::makeTitle( NS_SPECIAL, 'Contributions' ); + $contribsPage = SpecialPage::getTitleFor( 'Contributions' ); return $this->makeKnownLinkObj( $contribsPage, $encName, 'target=' . urlencode( $userText ) ); } else { @@ -788,7 +788,7 @@ class Linker { $items[] = $this->userTalkLink( $userId, $userText ); } if( $userId ) { - $contribsPage = Title::makeTitle( NS_SPECIAL, 'Contributions' ); + $contribsPage = SpecialPage::getTitleFor( 'Contributions' ); $items[] = $this->makeKnownLinkObj( $contribsPage, wfMsgHtml( 'contribslink' ), 'target=' . urlencode( $userText ) ); } @@ -825,7 +825,7 @@ class Linker { * @private */ function blockLink( $userId, $userText ) { - $blockPage = Title::makeTitle( NS_SPECIAL, 'Blockip' ); + $blockPage = SpecialPage::getTitleFor( 'Blockip' ); $blockLink = $this->makeKnownLinkObj( $blockPage, wfMsgHtml( 'blocklink' ), 'ip=' . urlencode( $userText ) ); return $blockLink; diff --git a/includes/LogPage.php b/includes/LogPage.php index 954b178f70..d25b8aa4ce 100644 --- a/includes/LogPage.php +++ b/includes/LogPage.php @@ -74,7 +74,7 @@ class LogPage { # And update recentchanges if ( $this->updateRecentChanges ) { - $titleObj = Title::makeTitle( NS_SPECIAL, 'Log/' . $this->type ); + $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); $rcComment = $this->actionText; if( '' != $this->comment ) { if ($rcComment == '') @@ -150,7 +150,7 @@ class LogPage { $titleLink = $title->getText(); } else { $titleLink = $skin->makeLinkObj( $title, $title->getText() ); - $titleLink .= ' (' . $skin->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Contributions/' . $title->getDBkey() ), wfMsg( 'contribslink' ) ) . ')'; + $titleLink .= ' (' . $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Contributions', $title->getDBkey() ), wfMsg( 'contribslink' ) ) . ')'; } break; case 'rights': diff --git a/includes/OutputPage.php b/includes/OutputPage.php index f560397ae9..7ed49199dd 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -783,7 +783,7 @@ class OutputPage { $this->setRobotPolicy( 'noindex,nofollow' ); $this->setArticleFlag( false ); - $loginTitle = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); + $loginTitle = SpecialPage::getTitleFor( 'Userlogin' ); $loginLink = $skin->makeKnownLinkObj( $loginTitle, wfMsgHtml( 'loginreqlink' ), 'returnto=' . $wgTitle->getPrefixedUrl() ); $this->addHtml( wfMsgWikiHtml( 'loginreqpagetext', $loginLink ) ); $this->addHtml( "\n" ); diff --git a/includes/PageHistory.php b/includes/PageHistory.php index 0f39a99f30..0476931a49 100644 --- a/includes/PageHistory.php +++ b/includes/PageHistory.php @@ -70,7 +70,7 @@ class PageHistory { $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->setSyndicated( true ); - $logPage = Title::makeTitle( NS_SPECIAL, 'Log' ); + $logPage = SpecialPage::getTitleFor( 'Log' ); $logLink = $this->mSkin->makeKnownLinkObj( $logPage, wfMsgHtml( 'viewpagelogs' ), 'page=' . $this->mTitle->getPrefixedUrl() ); $subtitle = wfMsgHtml( 'revhistory' ) . '
' . $logLink; @@ -184,7 +184,7 @@ class PageHistory { $s .= "($curlink) ($lastlink) $arbitrary"; if( $wgUser->isAllowed( 'deleterevision' ) ) { - $revdel = Title::makeTitle( NS_SPECIAL, 'Revisiondelete' ); + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); if( $firstInList ) { // We don't currently handle well changing the top revision's settings $del = wfMsgHtml( 'rev-delundel' ); diff --git a/includes/Parser.php b/includes/Parser.php index 72d24b3536..cfe1d70b2e 100644 --- a/includes/Parser.php +++ b/includes/Parser.php @@ -1018,7 +1018,7 @@ class Parser ' ' => '', 'x' => 'X', )); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Booksources' ); + $titleObj = SpecialPage::getTitleFor( 'Booksources' ); $text = 'ISBN $isbn"; diff --git a/includes/ProxyTools.php b/includes/ProxyTools.php index 7974c88273..fde896595f 100644 --- a/includes/ProxyTools.php +++ b/includes/ProxyTools.php @@ -96,7 +96,7 @@ function wfProxyCheck() { # Fork the processes if ( !$skip ) { - $title = Title::makeTitle( NS_SPECIAL, 'Blockme' ); + $title = SpecialPage::getTitleFor( 'Blockme' ); $iphash = md5( $ip . $wgProxyKey ); $url = $title->getFullURL( 'ip='.$iphash ); diff --git a/includes/QueryPage.php b/includes/QueryPage.php index 7d6dc900f3..3839aae563 100644 --- a/includes/QueryPage.php +++ b/includes/QueryPage.php @@ -92,7 +92,7 @@ class QueryPage { * @return Title */ function getTitle() { - return Title::makeTitle( NS_SPECIAL, $this->getName() ); + return SpecialPage::getTitleFor( $this->getName() ); } /** @@ -459,7 +459,7 @@ class QueryPage { } function feedUrl() { - $title = Title::MakeTitle( NS_SPECIAL, $this->getName() ); + $title = SpecialPage::getTitleFor( $this->getName() ); return $title->getFullURL(); } } diff --git a/includes/SearchEngine.php b/includes/SearchEngine.php index 5e598883fe..32725a5a34 100644 --- a/includes/SearchEngine.php +++ b/includes/SearchEngine.php @@ -116,7 +116,7 @@ class SearchEngine { # Entering an IP address goes to the contributions page if ( ( $title->getNamespace() == NS_USER && User::isIP($title->getText() ) ) || User::isIP( trim( $searchterm ) ) ) { - return Title::makeTitle( NS_SPECIAL, "Contributions/" . $title->getDbkey() ); + return SpecialPage::getTitleFor( 'Contributions', $title->getDbkey() ); } diff --git a/includes/Skin.php b/includes/Skin.php index 9df74b42df..d1d853a7bc 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -579,7 +579,7 @@ END; $t = $embed . implode ( "{$pop} {$sep} {$embed}" , $wgOut->mCategoryLinks ) . $pop; $msg = wfMsgExt( 'pagecategories', array( 'parsemag', 'escape' ), count( $wgOut->mCategoryLinks ) ); - $s = $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Categories' ), + $s = $this->makeKnownLinkObj( SpecialPage::getTitleFor( 'Categories' ), $msg, 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) ) . ': ' . $t; @@ -836,7 +836,7 @@ END; } else { $q = "returnto={$rt}"; } $s .= "\n
" . $this->makeKnownLinkObj( - Title::makeTitle( NS_SPECIAL, 'Userlogin' ), + SpecialPage::getTitleFor( 'Userlogin' ), wfMsg( 'login' ), $q ); } else { $n = $wgUser->getName(); @@ -848,7 +848,7 @@ END; $s .= $this->makeKnownLinkObj( $wgUser->getUserPage(), $n ) . "{$tl}
" . - $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Userlogout' ), wfMsg( 'logout' ), + $this->makeKnownLinkObj( SpecialPage::getTitleFor( 'Userlogout' ), wfMsg( 'logout' ), "returnto={$rt}" ) . ' | ' . $this->specialLink( 'preferences' ); } @@ -859,7 +859,7 @@ END; } function getSearchLink() { - $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' ); + $searchPage =& SpecialPage::getTitleFor( 'Search' ); return $searchPage->getLocalURL(); } @@ -1253,7 +1253,7 @@ END; global $wgTitle; if ( $wgTitle->userCanMove() ) { - return $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Movepage' ), + return $this->makeKnownLinkObj( SpecialPage::getTitleFor( 'Movepage' ), wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() ); } else { // no message if page is protected - would be redundant @@ -1271,15 +1271,17 @@ END; function whatLinksHere() { global $wgTitle; - return $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Whatlinkshere' ), - wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() ); + return $this->makeKnownLinkObj( + SpecialPage::getTitleFor( 'Whatlinkshere', $wgTitle->getPrefixedDBkey() ), + wfMsg( 'whatlinkshere' ) ); } function userContribsLink() { global $wgTitle; - return $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Contributions' ), - wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() ); + return $this->makeKnownLinkObj( + SpecialPage::getTitleFor( 'Contributions', $wgTitle->getDBkey() ), + wfMsg( 'contributions' ) ); } function showEmailUser( $id ) { @@ -1296,8 +1298,9 @@ END; function emailUserLink() { global $wgTitle; - return $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Emailuser' ), - wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() ); + return $this->makeKnownLinkObj( + SpecialPage::getTitleFor( 'Emailuser', $wgTitle->getDBkey() ), + wfMsg( 'emailuser' ) ); } function watchPageLinksLink() { @@ -1306,9 +1309,9 @@ END; if ( ! $wgOut->isArticleRelated() ) { return '(' . wfMsg( 'notanarticle' ) . ')'; } else { - return $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, - 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ), - 'target=' . $wgTitle->getPrefixedURL() ); + return $this->makeKnownLinkObj( + SpecialPage::getTitleFor( 'Recentchangeslinked', $wgTitle->getPrefixedDBkey() ), + wfMsg( 'recentchangeslinked' ) ); } } @@ -1450,7 +1453,7 @@ END; /* these are used extensively in SkinTemplate, but also some other places */ static function makeSpecialUrl( $name, $urlaction = '' ) { - $title = Title::makeTitle( NS_SPECIAL, $name ); + $title = SpecialPage::getTitleFor( $name ); return $title->getLocalURL( $urlaction ); } @@ -1559,7 +1562,15 @@ END; $text = $line[1]; if (wfEmptyMsg($line[0], $link)) $link = $line[0]; - $href = self::makeInternalOrExternalUrl( $link ); + + if ( preg_match( '/^(?:' . wfUrlProtocols() . ')/', $link ) ) { + $href = $link; + } else { + $title = Title::newFromText( $link ); + $title = $title->fixSpecialName(); + $href = $title->getLocalURL(); + } + $bar[$heading][] = array( 'text' => $text, 'href' => $href, diff --git a/includes/SkinTemplate.php b/includes/SkinTemplate.php index 050368432f..a4238cce74 100644 --- a/includes/SkinTemplate.php +++ b/includes/SkinTemplate.php @@ -518,7 +518,7 @@ class SkinTemplate extends Skin { $personal_urls['logout'] = array( 'text' => wfMsg( 'userlogout' ), 'href' => self::makeSpecialUrl( 'Userlogout', - $wgTitle->getNamespace() === NS_SPECIAL && $wgTitle->getText() === 'Preferences' ? '' : "returnto={$this->thisurl}" + $wgTitle->isSpecial( 'Preferences' ) ? '' : "returnto={$this->thisurl}" ) ); } else { @@ -541,14 +541,14 @@ class SkinTemplate extends Skin { $personal_urls['anonlogin'] = array( 'text' => wfMsg('userlogin'), 'href' => self::makeSpecialUrl( 'Userlogin', 'returnto=' . $this->thisurl ), - 'active' => ( NS_SPECIAL == $wgTitle->getNamespace() && 'Userlogin' == $wgTitle->getDBkey() ) + 'active' => $wgTitle->isSpecial( 'Userlogin' ) ); } else { $personal_urls['login'] = array( 'text' => wfMsg('userlogin'), 'href' => self::makeSpecialUrl( 'Userlogin', 'returnto=' . $this->thisurl ), - 'active' => ( NS_SPECIAL == $wgTitle->getNamespace() && 'Userlogin' == $wgTitle->getDBkey() ) + 'active' => $wgTitle->isSpecial( 'Userlogin' ) ); } } @@ -703,18 +703,18 @@ class SkinTemplate extends Skin { ); } if ( $this->mTitle->userCanMove()) { - $moveTitle = Title::makeTitle( NS_SPECIAL, 'Movepage' ); + $moveTitle = SpecialPage::getTitleFor( 'Movepage', $this->thispage ); $content_actions['move'] = array( - 'class' => ($this->mTitle->getDbKey() == 'Movepage' and $this->mTitle->getNamespace == NS_SPECIAL) ? 'selected' : false, + 'class' => $this->mTitle->isSpecial( 'Movepage' ) ? 'selected' : false, 'text' => wfMsg('move'), - 'href' => $moveTitle->getLocalUrl( 'target=' . urlencode( $this->thispage ) ) + 'href' => $moveTitle->getLocalUrl() ); } } else { //article doesn't exist or is deleted if( $wgUser->isAllowed( 'delete' ) ) { if( $n = $this->mTitle->isDeleted() ) { - $undelTitle = Title::makeTitle( NS_SPECIAL, 'Undelete' ); + $undelTitle = SpecialPage::getTitleFor( 'Undelete' ); $content_actions['undelete'] = array( 'class' => false, 'text' => wfMsgExt( 'undelete_short', array( 'parsemag' ), $n ), @@ -849,14 +849,14 @@ class SkinTemplate extends Skin { } if( $this->mTitle->getNamespace() != NS_SPECIAL ) { - $wlhTitle = Title::makeTitle( NS_SPECIAL, 'Whatlinkshere' ); + $wlhTitle = SpecialPage::getTitleFor( 'Whatlinkshere', $this->thispage ); $nav_urls['whatlinkshere'] = array( - 'href' => $wlhTitle->getLocalUrl( 'target=' . urlencode( $this->thispage ) ) + 'href' => $wlhTitle->getLocalUrl() ); if( $this->mTitle->getArticleId() ) { - $rclTitle = Title::makeTitle( NS_SPECIAL, 'Recentchangeslinked' ); + $rclTitle = SpecialPage::getTitleFor( 'Recentchangeslinked', $this->thispage ); $nav_urls['recentchangeslinked'] = array( - 'href' => $rclTitle->getLocalUrl( 'target=' . urlencode( $this->thispage ) ) + 'href' => $rclTitle->getLocalUrl() ); } if ($wgUseTrackbacks) diff --git a/includes/SpecialAllpages.php b/includes/SpecialAllpages.php index 8d41bb376d..e868ec7160 100644 --- a/includes/SpecialAllpages.php +++ b/includes/SpecialAllpages.php @@ -51,7 +51,7 @@ class SpecialAllpages { */ function namespaceForm ( $namespace = NS_MAIN, $from = '' ) { global $wgScript; - $t = Title::makeTitle( NS_SPECIAL, $this->name ); + $t = SpecialPage::getTitleFor( $this->name ); $namespaceselect = HTMLnamespaceselector($namespace, null); @@ -192,7 +192,7 @@ function showline( $inpoint, $outpoint, $namespace = NS_MAIN ) { $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) ); $outpointf = htmlspecialchars( str_replace( '_', ' ', $outpoint ) ); $queryparams = ($namespace ? "namespace=$namespace" : ''); - $special = Title::makeTitle( NS_SPECIAL, $this->name . '/' . $inpoint ); + $special = SpecialPage::getTitleFor( $this->name, $inpoint ); $link = $special->escapeLocalUrl( $queryparams ); $out = wfMsgHtml( @@ -276,7 +276,7 @@ function showChunk( $namespace = NS_MAIN, $from, $including = false ) { $sk->makeKnownLink( $wgContLang->specialPage( "Allpages" ), wfMsgHtml ( 'allpages' ) ); if ( isset($dbr) && $dbr && ($n == $this->maxPerPage) && ($s = $dbr->fetchObject( $res )) ) { - $self = Title::makeTitle( NS_SPECIAL, 'Allpages' ); + $self = SpecialPage::getTitleFor( 'Allpages' ); $q = 'from=' . $t->getPartialUrl() . ( $namespace ? '&namespace=' . $namespace : '' ); $out2 .= ' | ' . $sk->makeKnownLinkObj( $self, wfMsgHtml( 'nextpage', $t->getText() ), $q ); } diff --git a/includes/SpecialBlockip.php b/includes/SpecialBlockip.php index 4eb4957a55..567fd82425 100644 --- a/includes/SpecialBlockip.php +++ b/includes/SpecialBlockip.php @@ -73,7 +73,7 @@ class IPBlockForm { $mIpbothertime = wfMsgHtml( 'ipbotheroption' ); $mIpbreason = wfMsgHtml( 'ipbreason' ); $mIpbsubmit = wfMsgHtml( 'ipbsubmit' ); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Blockip' ); + $titleObj = SpecialPage::getTitleFor( 'Blockip' ); $action = $titleObj->escapeLocalURL( "action=submit" ); if ( "" != $err ) { @@ -260,7 +260,7 @@ class IPBlockForm { $this->BlockReason, $expirestr ); # Report to the user - $titleObj = Title::makeTitle( NS_SPECIAL, 'Blockip' ); + $titleObj = SpecialPage::getTitleFor( 'Blockip' ); $wgOut->redirect( $titleObj->getFullURL( 'action=success&ip=' . urlencode( $this->BlockAddress ) ) ); } diff --git a/includes/SpecialConfirmemail.php b/includes/SpecialConfirmemail.php index 94104f3407..d109eee785 100644 --- a/includes/SpecialConfirmemail.php +++ b/includes/SpecialConfirmemail.php @@ -36,8 +36,8 @@ class EmailConfirmation extends SpecialPage { $wgOut->addWikiText( wfMsg( 'confirmemail_noemail' ) ); } } else { - $title = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); - $self = Title::makeTitle( NS_SPECIAL, 'Confirmemail' ); + $title = SpecialPage::getTitleFor( 'Userlogin' ); + $self = SpecialPage::getTitleFor( 'Confirmemail' ); $skin = $wgUser->getSkin(); $llink = $skin->makeKnownLinkObj( $title, wfMsgHtml( 'loginreqlink' ), 'returnto=' . $self->getPrefixedUrl() ); $wgOut->addHtml( wfMsgWikiHtml( 'confirmemail_needlogin', $llink ) ); @@ -65,7 +65,7 @@ class EmailConfirmation extends SpecialPage { $wgOut->addWikiText( wfMsg( 'emailauthenticated', $time ) ); } $wgOut->addWikiText( wfMsg( 'confirmemail_text' ) ); - $self = Title::makeTitle( NS_SPECIAL, 'Confirmemail' ); + $self = SpecialPage::getTitleFor( 'Confirmemail' ); $form = wfOpenElement( 'form', array( 'method' => 'post', 'action' => $self->getLocalUrl() ) ); $form .= wfHidden( 'token', $wgUser->editToken() ); $form .= wfSubmitButton( wfMsgHtml( 'confirmemail_send' ) ); @@ -88,7 +88,7 @@ class EmailConfirmation extends SpecialPage { $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success'; $wgOut->addWikiText( wfMsg( $message ) ); if( !$wgUser->isLoggedIn() ) { - $title = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); + $title = SpecialPage::getTitleFor( 'Userlogin' ); $wgOut->returnToMain( true, $title->getPrefixedText() ); } } else { diff --git a/includes/SpecialContributions.php b/includes/SpecialContributions.php index 8477b6bcfc..29198bb1af 100644 --- a/includes/SpecialContributions.php +++ b/includes/SpecialContributions.php @@ -190,7 +190,7 @@ function wfSpecialContributions( $par = null ) { if ( !strlen( $options['offset'] ) || !preg_match( '/^[0-9]+$/', $options['offset'] ) ) $options['offset'] = ''; - $title = Title::makeTitle( NS_SPECIAL, 'Contributions' ); + $title = SpecialPage::getTitleFor( 'Contributions' ); $options['target'] = $target; $nt =& Title::makeTitle( NS_USER, $nt->getDBkey() ); @@ -321,12 +321,12 @@ function contributionsSub( $nt ) { if( ( $id != 0 && $wgSysopUserBans ) || ( $id == 0 && User::isIP( $nt->getText() ) ) ) { # Block link if( $wgUser->isAllowed( 'block' ) ) - $tools[] = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Blockip/' . $nt->getDBkey() ), wfMsgHtml( 'blocklink' ) ); + $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ), wfMsgHtml( 'blocklink' ) ); # Block log link - $tools[] = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Log' ), htmlspecialchars( LogPage::logName( 'block' ) ), 'type=block&page=' . $nt->getPrefixedUrl() ); + $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ), htmlspecialchars( LogPage::logName( 'block' ) ), 'type=block&page=' . $nt->getPrefixedUrl() ); } # Other logs link - $tools[] = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Log' ), wfMsgHtml( 'log' ), 'user=' . $nt->getPartialUrl() ); + $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ), wfMsgHtml( 'log' ), 'user=' . $nt->getPartialUrl() ); $ul .= ' (' . implode( ' | ', $tools ) . ')'; } return $ul; diff --git a/includes/SpecialEmailuser.php b/includes/SpecialEmailuser.php index d711947fbe..caf24ff3b7 100644 --- a/includes/SpecialEmailuser.php +++ b/includes/SpecialEmailuser.php @@ -97,7 +97,7 @@ class EmailUserForm { $ems = wfMsg( "emailsend" ); $encSubject = htmlspecialchars( $this->subject ); - $titleObj = Title::makeTitle( NS_SPECIAL, "Emailuser" ); + $titleObj = SpecialPage::getTitleFor( "Emailuser" ); $action = $titleObj->escapeLocalURL( "target=" . urlencode( $this->target->getName() ) . "&action=submit" ); $token = $wgUser->editToken(); @@ -140,7 +140,7 @@ class EmailUserForm { if( WikiError::isError( $mailResult ) ) { $wgOut->addHTML( wfMsg( "usermailererror" ) . $mailResult); } else { - $titleObj = Title::makeTitle( NS_SPECIAL, "Emailuser" ); + $titleObj = SpecialPage::getTitleFor( "Emailuser" ); $encTarget = wfUrlencode( $this->target->getName() ); $wgOut->redirect( $titleObj->getFullURL( "target={$encTarget}&action=success" ) ); wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $this->text ) ); diff --git a/includes/SpecialExport.php b/includes/SpecialExport.php index dc52e00bcd..d387f3d497 100644 --- a/includes/SpecialExport.php +++ b/includes/SpecialExport.php @@ -123,7 +123,7 @@ function wfSpecialExport( $page = '' ) { } $wgOut->addWikiText( wfMsg( "exporttext" ) ); - $titleObj = Title::makeTitle( NS_SPECIAL, "Export" ); + $titleObj = SpecialPage::getTitleFor( "Export" ); $form = wfOpenElement( 'form', array( 'method' => 'post', 'action' => $titleObj->getLocalUrl() ) ); $form .= wfOpenElement( 'textarea', array( 'name' => 'pages', 'cols' => 40, 'rows' => 10 ) ) . '
'; diff --git a/includes/SpecialIpblocklist.php b/includes/SpecialIpblocklist.php index 437fac7ff1..8d0ef1029d 100644 --- a/includes/SpecialIpblocklist.php +++ b/includes/SpecialIpblocklist.php @@ -58,7 +58,7 @@ class IPUnblockForm { $ipa = wfMsgHtml( $wgSysopUserBans ? 'ipadressorusername' : 'ipaddress' ); $ipr = wfMsgHtml( 'ipbreason' ); $ipus = wfMsgHtml( 'ipusubmit' ); - $titleObj = Title::makeTitle( NS_SPECIAL, "Ipblocklist" ); + $titleObj = SpecialPage::getTitleFor( "Ipblocklist" ); $action = $titleObj->escapeLocalURL( "action=submit" ); if ( "" != $err ) { @@ -142,7 +142,7 @@ class IPUnblockForm { if ( $success ) { # Report to the user - $titleObj = Title::makeTitle( NS_SPECIAL, "Ipblocklist" ); + $titleObj = SpecialPage::getTitleFor( "Ipblocklist" ); $success = $titleObj->getFullURL( "action=success&successip=" . urlencode( $this->ip ) ); $wgOut->redirect( $success ); } else { @@ -259,7 +259,7 @@ class IPUnblockForm { $target = $block->getRedactedName(); # Hide the IP addresses of auto-blocks; privacy } else { $target = $sk->makeLinkObj( Title::makeTitle( NS_USER, $block->mAddress ), $block->mAddress ); - $target .= ' (' . $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Contributions' ), $msg['contribslink'], 'target=' . urlencode( $block->mAddress ) ) . ')'; + $target .= ' (' . $sk->makeKnownLinkObj( SpecialPage::getSafeTitleFor( 'Contributions', $block->mAddress ), $msg['contribslink'] ) . ')'; } $formattedTime = $wgLang->timeanddate( $block->mTimestamp, true ); @@ -284,7 +284,7 @@ class IPUnblockForm { $s = "
  • {$line}"; if ( $wgUser->isAllowed('block') ) { - $titleObj = Title::makeTitle( NS_SPECIAL, "Ipblocklist" ); + $titleObj = SpecialPage::getTitleFor( "Ipblocklist" ); $s .= ' (' . $sk->makeKnownLinkObj($titleObj, $msg['unblocklink'], 'action=unblock&id=' . urlencode( $block->mId ) ) . ')'; } $s .= $sk->commentBlock( $block->mReason ); diff --git a/includes/SpecialLockdb.php b/includes/SpecialLockdb.php index 72172e2c6f..f0142e5ca5 100644 --- a/includes/SpecialLockdb.php +++ b/includes/SpecialLockdb.php @@ -62,7 +62,7 @@ class DBLockForm { $lc = htmlspecialchars( wfMsg( 'lockconfirm' ) ); $lb = htmlspecialchars( wfMsg( 'lockbtn' ) ); $elr = htmlspecialchars( wfMsg( 'enterlockreason' ) ); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Lockdb' ); + $titleObj = SpecialPage::getTitleFor( 'Lockdb' ); $action = $titleObj->escapeLocalURL( 'action=submit' ); $reason = htmlspecialchars( $this->reason ); $token = htmlspecialchars( $wgUser->editToken() ); @@ -114,7 +114,7 @@ END $wgLang->timeanddate( wfTimestampNow() ) . ")\n" ); fclose( $fp ); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Lockdb' ); + $titleObj = SpecialPage::getTitleFor( 'Lockdb' ); $wgOut->redirect( $titleObj->getFullURL( 'action=success' ) ); } diff --git a/includes/SpecialLog.php b/includes/SpecialLog.php index e32d224034..81188aa0c1 100644 --- a/includes/SpecialLog.php +++ b/includes/SpecialLog.php @@ -321,7 +321,7 @@ class LogViewer { $paramArray = LogPage::extractParams( $s->log_params ); $revert = ''; if ( $s->log_type == 'move' && isset( $paramArray[0] ) ) { - $specialTitle = Title::makeTitle( NS_SPECIAL, 'Movepage' ); + $specialTitle = SpecialPage::getTitleFor( 'Movepage' ); $destTitle = Title::newFromText( $paramArray[0] ); if ( $destTitle ) { $revert = '(' . $this->skin->makeKnownLinkObj( $specialTitle, wfMsg( 'revertmove' ), @@ -356,7 +356,7 @@ class LogViewer { function showOptions( &$out ) { global $wgScript; $action = htmlspecialchars( $wgScript ); - $title = Title::makeTitle( NS_SPECIAL, 'Log' ); + $title = SpecialPage::getTitleFor( 'Log' ); $special = htmlspecialchars( $title->getPrefixedDBkey() ); $out->addHTML( "
    \n" . "\n" . diff --git a/includes/SpecialMostlinked.php b/includes/SpecialMostlinked.php index 1791228dde..6f5f30dbdd 100644 --- a/includes/SpecialMostlinked.php +++ b/includes/SpecialMostlinked.php @@ -62,8 +62,8 @@ class MostlinkedPage extends QueryPage { * @return string */ function makeWlhLink( &$title, $caption, &$skin ) { - $wlh = Title::makeTitle( NS_SPECIAL, 'Whatlinkshere' ); - return $skin->makeKnownLinkObj( $wlh, $caption, 'target=' . $title->getPrefixedUrl() ); + $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedDBkey() ); + return $skin->makeKnownLinkObj( $wlh, $caption ); } /** diff --git a/includes/SpecialMovepage.php b/includes/SpecialMovepage.php index c1d6833549..1b9e7b2dce 100644 --- a/includes/SpecialMovepage.php +++ b/includes/SpecialMovepage.php @@ -130,7 +130,7 @@ class MovePageForm { $movetalk = wfMsgHtml( 'movetalk' ); $movereason = wfMsgHtml( 'movereason' ); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Movepage' ); + $titleObj = SpecialPage::getTitleFor( 'Movepage' ); $action = $titleObj->escapeLocalURL( 'action=submit' ); $token = htmlspecialchars( $wgUser->editToken() ); @@ -245,7 +245,7 @@ class MovePageForm { } # Give back result to user. - $titleObj = Title::makeTitle( NS_SPECIAL, 'Movepage' ); + $titleObj = SpecialPage::getTitleFor( 'Movepage' ); $success = $titleObj->getFullURL( 'action=success&oldtitle=' . wfUrlencode( $ot->getPrefixedText() ) . '&newtitle=' . wfUrlencode( $nt->getPrefixedText() ) . diff --git a/includes/SpecialNewimages.php b/includes/SpecialNewimages.php index 95c90e42db..66cf42603c 100644 --- a/includes/SpecialNewimages.php +++ b/includes/SpecialNewimages.php @@ -154,7 +154,7 @@ function wfSpecialNewimages( $par, $specialPage ) { } $sub = wfMsg( 'ilsubmit' ); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Newimages' ); + $titleObj = SpecialPage::getTitleFor( 'Newimages' ); $action = $titleObj->escapeLocalURL( $hidebots ? '' : 'hidebots=0' ); if ($shownav) { $wgOut->addHTML( "getName() ); + $self = SpecialPage::getTitleFor( $this->getName() ); $form = wfOpenElement( 'form', array( 'method' => 'post', 'action' => $self->getLocalUrl() ) ); $form .= ''; $form .= ''; diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index 294c05ef6f..73b6233f50 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -36,10 +36,14 @@ class SpecialPage * @access private */ /** - * The name of the class, used in the URL. + * The canonical name of this special page * Also used for the default

    heading, @see getDescription() */ var $mName; + /** + * The local name of this special page + */ + var $mLocalName; /** * Minimum user level required to access this page, or "" for anyone. * Also used to categorise the pages in Special:Specialpages @@ -65,72 +69,82 @@ class SpecialPage * Whether the special page can be included in an article */ var $mIncludable; + /** + * Query parameters that can be passed through redirects + */ + var $mAllowedRedirectParams = array(); static public $mList = array( - 'DoubleRedirects' => array( 'SpecialPage', 'DoubleRedirects' ), - 'BrokenRedirects' => array( 'SpecialPage', 'BrokenRedirects' ), - 'Disambiguations' => array( 'SpecialPage', 'Disambiguations' ), - - 'Userlogin' => array( 'SpecialPage', 'Userlogin' ), - 'Userlogout' => array( 'UnlistedSpecialPage', 'Userlogout' ), - 'Preferences' => array( 'SpecialPage', 'Preferences' ), - 'Watchlist' => array( 'SpecialPage', 'Watchlist' ), - - 'Recentchanges' => array( 'IncludableSpecialPage', 'Recentchanges' ), - 'Upload' => array( 'SpecialPage', 'Upload' ), - 'Imagelist' => array( 'SpecialPage', 'Imagelist' ), - 'Newimages' => array( 'IncludableSpecialPage', 'Newimages' ), - 'Listusers' => array( 'SpecialPage', 'Listusers' ), - 'Statistics' => array( 'SpecialPage', 'Statistics' ), - 'Random' => array( 'SpecialPage', 'Randompage' ), - 'Lonelypages' => array( 'SpecialPage', 'Lonelypages' ), - 'Uncategorizedpages'=> array( 'SpecialPage', 'Uncategorizedpages' ), - 'Uncategorizedcategories'=> array( 'SpecialPage', 'Uncategorizedcategories' ), - 'Uncategorizedimages' => array( 'SpecialPage', 'Uncategorizedimages' ), - 'Unusedcategories' => array( 'SpecialPage', 'Unusedcategories' ), - 'Unusedimages' => array( 'SpecialPage', 'Unusedimages' ), - 'Wantedpages' => array( 'IncludableSpecialPage', 'Wantedpages' ), - 'Wantedcategories' => array( 'SpecialPage', 'Wantedcategories' ), - 'Mostlinked' => array( 'SpecialPage', 'Mostlinked' ), - 'Mostlinkedcategories' => array( 'SpecialPage', 'Mostlinkedcategories' ), - 'Mostcategories' => array( 'SpecialPage', 'Mostcategories' ), - 'Mostimages' => array( 'SpecialPage', 'Mostimages' ), - 'Mostrevisions' => array( 'SpecialPage', 'Mostrevisions' ), - 'Shortpages' => array( 'SpecialPage', 'Shortpages' ), - 'Longpages' => array( 'SpecialPage', 'Longpages' ), - 'Newpages' => array( 'IncludableSpecialPage', 'Newpages' ), - 'Ancientpages' => array( 'SpecialPage', 'Ancientpages' ), - 'Deadendpages' => array( 'SpecialPage', 'Deadendpages' ), - 'Allpages' => array( 'IncludableSpecialPage', 'Allpages' ), - 'Prefixindex' => array( 'IncludableSpecialPage', 'Prefixindex' ) , - 'Ipblocklist' => array( 'SpecialPage', 'Ipblocklist' ), - 'Specialpages' => array( 'UnlistedSpecialPage', 'Specialpages' ), - 'Contributions' => array( 'UnlistedSpecialPage', 'Contributions' ), - 'Emailuser' => array( 'UnlistedSpecialPage', 'Emailuser' ), - 'Whatlinkshere' => array( 'UnlistedSpecialPage', 'Whatlinkshere' ), - 'Recentchangeslinked' => array( 'UnlistedSpecialPage', 'Recentchangeslinked' ), - 'Movepage' => array( 'UnlistedSpecialPage', 'Movepage' ), - 'Blockme' => array( 'UnlistedSpecialPage', 'Blockme' ), - 'Booksources' => array( 'SpecialPage', 'Booksources' ), - 'Categories' => array( 'SpecialPage', 'Categories' ), - 'Export' => array( 'SpecialPage', 'Export' ), - 'Version' => array( 'SpecialPage', 'Version' ), - 'Allmessages' => array( 'SpecialPage', 'Allmessages' ), - 'Log' => array( 'SpecialPage', 'Log' ), - 'Blockip' => array( 'SpecialPage', 'Blockip', 'block' ), - 'Undelete' => array( 'SpecialPage', 'Undelete', 'deletedhistory' ), - "Import" => array( 'SpecialPage', "Import", 'import' ), - 'Lockdb' => array( 'SpecialPage', 'Lockdb', 'siteadmin' ), - 'Unlockdb' => array( 'SpecialPage', 'Unlockdb', 'siteadmin' ), - 'Userrights' => array( 'SpecialPage', 'Userrights', 'userrights' ), - 'MIMEsearch' => array( 'SpecialPage', 'MIMEsearch' ), - 'Unwatchedpages' => array( 'SpecialPage', 'Unwatchedpages', 'unwatchedpages' ), - 'Listredirects' => array( 'SpecialPage', 'Listredirects' ), - 'Revisiondelete' => array( 'SpecialPage', 'Revisiondelete', 'deleterevision' ), - 'Unusedtemplates' => array( 'SpecialPage', 'Unusedtemplates' ), - 'Randomredirect' => array( 'SpecialPage', 'Randomredirect' ), + 'DoubleRedirects' => array( 'SpecialPage', 'DoubleRedirects' ), + 'BrokenRedirects' => array( 'SpecialPage', 'BrokenRedirects' ), + 'Disambiguations' => array( 'SpecialPage', 'Disambiguations' ), + + 'Userlogin' => array( 'SpecialPage', 'Userlogin' ), + 'Userlogout' => array( 'UnlistedSpecialPage', 'Userlogout' ), + 'Preferences' => array( 'SpecialPage', 'Preferences' ), + 'Watchlist' => array( 'SpecialPage', 'Watchlist' ), + + 'Recentchanges' => array( 'IncludableSpecialPage', 'Recentchanges' ), + 'Upload' => array( 'SpecialPage', 'Upload' ), + 'Imagelist' => array( 'SpecialPage', 'Imagelist' ), + 'Newimages' => array( 'IncludableSpecialPage', 'Newimages' ), + 'Listusers' => array( 'SpecialPage', 'Listusers' ), + 'Statistics' => array( 'SpecialPage', 'Statistics' ), + 'Randompage' => array( 'SpecialPage', 'Randompage' ), + 'Lonelypages' => array( 'SpecialPage', 'Lonelypages' ), + 'Uncategorizedpages' => array( 'SpecialPage', 'Uncategorizedpages' ), + 'Uncategorizedcategories' => array( 'SpecialPage', 'Uncategorizedcategories' ), + 'Uncategorizedimages' => array( 'SpecialPage', 'Uncategorizedimages' ), + 'Unusedcategories' => array( 'SpecialPage', 'Unusedcategories' ), + 'Unusedimages' => array( 'SpecialPage', 'Unusedimages' ), + 'Wantedpages' => array( 'IncludableSpecialPage', 'Wantedpages' ), + 'Wantedcategories' => array( 'SpecialPage', 'Wantedcategories' ), + 'Mostlinked' => array( 'SpecialPage', 'Mostlinked' ), + 'Mostlinkedcategories' => array( 'SpecialPage', 'Mostlinkedcategories' ), + 'Mostcategories' => array( 'SpecialPage', 'Mostcategories' ), + 'Mostimages' => array( 'SpecialPage', 'Mostimages' ), + 'Mostrevisions' => array( 'SpecialPage', 'Mostrevisions' ), + 'Shortpages' => array( 'SpecialPage', 'Shortpages' ), + 'Longpages' => array( 'SpecialPage', 'Longpages' ), + 'Newpages' => array( 'IncludableSpecialPage', 'Newpages' ), + 'Ancientpages' => array( 'SpecialPage', 'Ancientpages' ), + 'Deadendpages' => array( 'SpecialPage', 'Deadendpages' ), + 'Allpages' => array( 'IncludableSpecialPage', 'Allpages' ), + 'Prefixindex' => array( 'IncludableSpecialPage', 'Prefixindex' ) , + 'Ipblocklist' => array( 'SpecialPage', 'Ipblocklist' ), + 'Specialpages' => array( 'UnlistedSpecialPage', 'Specialpages' ), + 'Contributions' => array( 'UnlistedSpecialPage', 'Contributions' ), + 'Emailuser' => array( 'UnlistedSpecialPage', 'Emailuser' ), + 'Whatlinkshere' => array( 'UnlistedSpecialPage', 'Whatlinkshere' ), + 'Recentchangeslinked' => array( 'UnlistedSpecialPage', 'Recentchangeslinked' ), + 'Movepage' => array( 'UnlistedSpecialPage', 'Movepage' ), + 'Blockme' => array( 'UnlistedSpecialPage', 'Blockme' ), + 'Booksources' => array( 'SpecialPage', 'Booksources' ), + 'Categories' => array( 'SpecialPage', 'Categories' ), + 'Export' => array( 'SpecialPage', 'Export' ), + 'Version' => array( 'SpecialPage', 'Version' ), + 'Allmessages' => array( 'SpecialPage', 'Allmessages' ), + 'Log' => array( 'SpecialPage', 'Log' ), + 'Blockip' => array( 'SpecialPage', 'Blockip', 'block' ), + 'Undelete' => array( 'SpecialPage', 'Undelete', 'deletedhistory' ), + 'Import' => array( 'SpecialPage', "Import", 'import' ), + 'Lockdb' => array( 'SpecialPage', 'Lockdb', 'siteadmin' ), + 'Unlockdb' => array( 'SpecialPage', 'Unlockdb', 'siteadmin' ), + 'Userrights' => array( 'SpecialPage', 'Userrights', 'userrights' ), + 'MIMEsearch' => array( 'SpecialPage', 'MIMEsearch' ), + 'Unwatchedpages' => array( 'SpecialPage', 'Unwatchedpages', 'unwatchedpages' ), + 'Listredirects' => array( 'SpecialPage', 'Listredirects' ), + 'Revisiondelete' => array( 'SpecialPage', 'Revisiondelete', 'deleterevision' ), + 'Unusedtemplates' => array( 'SpecialPage', 'Unusedtemplates' ), + 'Randomredirect' => array( 'SpecialPage', 'Randomredirect' ), + + 'Mypage' => array( 'SpecialMypage' ), + 'Mytalk' => array( 'SpecialMytalk' ), + 'Mycontributions' => array( 'SpecialMycontributions' ), + 'Listadmins' => array( 'SpecialRedirectToSpecial', 'Listadmins', 'Listusers', 'sysop' ), ); + static public $mAliases; static public $mListInitialised = false; /**#@-*/ @@ -148,6 +162,9 @@ class SpecialPage } wfProfileIn( __METHOD__ ); + # Better to set this now, to avoid infinite recursion in carelessly written hooks + self::$mListInitialised = true; + if( !$wgDisableCounters ) { self::$mList['Popularpages'] = array( 'SpecialPage', 'Popularpages' ); } @@ -163,15 +180,65 @@ class SpecialPage # Add extension special pages self::$mList = array_merge( self::$mList, $wgSpecialPages ); - # Better to set this now, to avoid infinite recursion in carelessly written hooks - self::$mListInitialised = true; - # Run hooks # This hook can be used to remove undesired built-in special pages wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) ); wfProfileOut( __METHOD__ ); } + static function initAliasList() { + if ( !is_null( self::$mAliases ) ) { + return; + } + + global $wgContLang; + $aliases = $wgContLang->getSpecialPageAliases(); + $missingPages = self::$mList; + self::$mAliases = array(); + foreach ( $aliases as $realName => $aliasList ) { + foreach ( $aliasList as $alias ) { + self::$mAliases[$wgContLang->caseFold( $alias )] = $realName; + } + unset( $missingPages[$realName] ); + } + foreach ( $missingPages as $name => $stuff ) { + self::$mAliases[$wgContLang->caseFold( $name )] = $name; + } + } + + /** + * Given a special page alias, return the special page name. + * Returns false if there is no such alias. + */ + static function resolveAlias( $alias ) { + global $wgContLang; + + if ( !self::$mListInitialised ) self::initList(); + if ( is_null( self::$mAliases ) ) self::initAliasList(); + $caseFoldedAlias = $wgContLang->caseFold( $alias ); + if ( isset( self::$mAliases[$caseFoldedAlias] ) ) { + return self::$mAliases[$caseFoldedAlias]; + } else { + return false; + } + } + + /** + * Given a special page name with a possible subpage, return an array + * where the first element is the special page name and the second is the + * subpage. + */ + static function resolveAliasWithSubpage( $alias ) { + $bits = explode( '/', $alias, 2 ); + $name = self::resolveAlias( $bits[0] ); + if( !isset( $bits[1] ) ) { // bug 2087 + $par = NULL; + } else { + $par = $bits[1]; + } + return array( $name, $par ); + } + /** * Add a page to the list of valid special pages. This used to be the preferred * method for adding special pages in extensions. It's now suggested that you add @@ -228,55 +295,18 @@ class SpecialPage } } - /** - * @static - * @param string $name - * @return mixed Title object if the redirect exists, otherwise NULL + * Get a special page with a given localised name, or NULL if there + * is no such special page. */ - static function getRedirect( $name ) { - global $wgUser; - - $redirects = array( - 'Mypage' => Title::makeTitle( NS_USER, $wgUser->getName() ), - 'Mytalk' => Title::makeTitle( NS_USER_TALK, $wgUser->getName() ), - 'Mycontributions' => Title::makeTitle( NS_SPECIAL, 'Contributions/' . $wgUser->getName() ), - 'Listadmins' => Title::makeTitle( NS_SPECIAL, 'Listusers/sysop' ), # @bug 2832 - 'Logs' => Title::makeTitle( NS_SPECIAL, 'Log' ), - 'Randompage' => Title::makeTitle( NS_SPECIAL, 'Random' ), - 'Userlist' => Title::makeTitle( NS_SPECIAL, 'Listusers' ) - ); - wfRunHooks( 'SpecialPageGetRedirect', array( &$redirects ) ); - - return isset( $redirects[$name] ) ? $redirects[$name] : null; - } - - /** - * Return part of the request string for a special redirect page - * This allows passing, e.g. action=history to Special:Mypage, etc. - * - * @param $name Name of the redirect page - * @return string - */ - function getRedirectParams( $name ) { - global $wgRequest; - - $args = array(); - switch( $name ) { - case 'Mypage': - case 'Mytalk': - case 'Randompage': - $args = array( 'action' ); - } - - $params = array(); - foreach( $args as $arg ) { - if( $val = $wgRequest->getVal( $arg, false ) ) - $params[] = $arg . '=' . $val; + static function getPageByAlias( $alias ) { + $realName = self::resolveAlias( $alias ); + if ( $realName ) { + return self::getPage( $realName ); + } else { + return NULL; } - - return count( $params ) ? implode( '&', $params ) : false; - } + } /** * Return categorised listable special pages for all users @@ -333,67 +363,74 @@ class SpecialPage * @param $including output is being captured for use in {{special:whatever}} */ static function executePath( &$title, $including = false ) { - global $wgOut, $wgTitle; - $fname = 'SpecialPage::executePath'; - wfProfileIn( $fname ); + global $wgOut, $wgTitle, $wgRequest; + wfProfileIn( __METHOD__ ); - $bits = split( "/", $title->getDBkey(), 2 ); + # FIXME: redirects broken due to this call + $bits = explode( '/', $title->getDBkey(), 2 ); $name = $bits[0]; if( !isset( $bits[1] ) ) { // bug 2087 $par = NULL; } else { $par = $bits[1]; } - - $page = SpecialPage::getPage( $name ); - if ( is_null( $page ) ) { - if ( $including ) { - wfProfileOut( $fname ); - return false; - } else { - $redir = SpecialPage::getRedirect( $name ); - if ( isset( $redir ) ) { - if( $par ) - $redir = Title::makeTitle( $redir->getNamespace(), $redir->getText() . '/' . $par ); - $params = SpecialPage::getRedirectParams( $name ); - if( $params ) { - $url = $redir->getFullUrl( $params ); - } else { - $url = $redir->getFullUrl(); - } - $wgOut->redirect( $url ); - $retVal = $redir; - $wgOut->redirect( $url ); - $retVal = $redir; - } else { - $wgOut->setArticleRelated( false ); - $wgOut->setRobotpolicy( 'noindex,nofollow' ); - $wgOut->setStatusCode( 404 ); - $wgOut->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' ); - $retVal = false; - } + $page = SpecialPage::getPageByAlias( $name ); + + # Nonexistent? + if ( !$page ) { + if ( !$including ) { + $wgOut->setArticleRelated( false ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); + $wgOut->setStatusCode( 404 ); + $wgOut->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' ); } - } else { - if ( $including && !$page->includable() ) { - wfProfileOut( $fname ); - return false; - } elseif ( !$including ) { - if($par !== NULL) { - $wgTitle = Title::makeTitle( NS_SPECIAL, $name ); - } else { - $wgTitle = $title; - } + wfProfileOut( __METHOD__ ); + return false; + } + + # Check for redirect + if ( !$including ) { + $redirect = $page->getRedirect( $par ); + if ( $redirect ) { + $query = $page->getRedirectQuery(); + $url = $redirect->getFullUrl( $query ); + $wgOut->redirect( $url ); + wfProfileOut( __METHOD__ ); + return $redirect; } - $page->including( $including ); + } - $profName = 'Special:' . $page->getName(); - wfProfileIn( $profName ); - $page->execute( $par ); - wfProfileOut( $profName ); - $retVal = true; + # Redirect to canonical alias for GET commands + # Not for POST, we'd lose the post data, so it's best to just distribute + # the request. Such POST requests are possible for old extensions that + # generate self-links without being aware that their default name has + # changed. + if ( !$including && $name != $page->getLocalName() && !$wgRequest->wasPosted() ) { + $query = $_GET; + unset( $query['title'] ); + $query = wfArrayToCGI( $query ); + $title = $page->getTitle(); + $url = $title->getFullUrl( $query ); + $wgOut->redirect( $url ); + wfProfileOut( __METHOD__ ); + return $redirect; } - wfProfileOut( $fname ); - return $retVal; + + if ( $including && !$page->includable() ) { + wfProfileOut( __METHOD__ ); + return false; + } elseif ( !$including ) { + $wgTitle = $page->getTitle(); + } + $page->including( $including ); + + // Execute special page + $profName = 'Special:' . $page->getName(); + wfProfileIn( $profName ); + $page->execute( $par ); + wfProfileOut( $profName ); + wfProfileOut( __METHOD__ ); + return true; } /** @@ -418,6 +455,45 @@ class SpecialPage return $ret; } + /** + * Get the local name for a specified canonical name + */ + static function getLocalNameFor( $name, $subpage = false ) { + global $wgContLang; + $aliases = $wgContLang->getSpecialPageAliases(); + if ( isset( $aliases[$name][0] ) ) { + $name = $aliases[$name][0]; + } + if ( $subpage !== false && !is_null( $subpage ) ) { + $name = "$name/$subpage"; + } + return $name; + } + + /** + * Get a localised Title object for a specified special page name + */ + static function getTitleFor( $name, $subpage = false ) { + $name = self::getLocalNameFor( $name, $subpage ); + return Title::makeTitle( NS_SPECIAL, $name ); + } + + /** + * Get a localised Title object for a page name with a possibly unvalidated subpage + */ + static function getSafeTitleFor( $name, $subpage = false ) { + $name = self::getLocalNameFor( $name, $subpage ); + return Title::makeTitleSafe( NS_SPECIAL, $name ); + } + + /** + * Get a title for a given alias + */ + static function getTitleForAlias( $alias ) { + $name = self::resolveAlias( $alias ); + return self::getTitleFor( $name ); + } + /** * Default constructor for special pages * Derivative classes should call this from their constructor @@ -474,6 +550,16 @@ class SpecialPage function including( $x = NULL ) { return wfSetVar( $this->mIncluding, $x ); } /**#@-*/ + /** + * Get the localised name of the special page + */ + function getLocalName() { + if ( !isset( $this->mLocalName ) ) { + $this->mLocalName = self::getLocalNameFor( $this->mName ); + } + return $this->mLocalName; + } + /** * Checks if the given user (identified by an object) can execute this * special page (as defined by $mRestriction) @@ -503,6 +589,8 @@ class SpecialPage /** * Default execute method * Checks user permissions, calls the function given in mFunction + * + * This may be overridden by subclasses. */ function execute( $par ) { global $wgUser; @@ -515,6 +603,7 @@ class SpecialPage if(!function_exists($func) and $this->mFile) { require_once( $this->mFile ); } + # FIXME: these hooks are broken for extensions and anything else that subclasses SpecialPage. if ( wfRunHooks( 'SpecialPageExecuteBeforeHeader', array( &$this, &$par, &$func ) ) ) $this->outputHeader(); if ( ! wfRunHooks( 'SpecialPageExecuteBeforePage', array( &$this, &$par, &$func ) ) ) @@ -549,8 +638,8 @@ class SpecialPage /** * Get a self-referential title object */ - function getTitle() { - return Title::makeTitle( NS_SPECIAL, $this->mName ); + function getTitle( $subpage = false) { + return self::getTitleFor( $this->mName, $subpage ); } /** @@ -560,6 +649,30 @@ class SpecialPage return wfSetVar( $this->mListed, $listed ); } + /** + * If the special page is a redirect, then get the Title object it redirects to. + * False otherwise. + */ + function getRedirect( $subpage = false ) { + return false; + } + + /** + * Return part of the request string for a special redirect page + * This allows passing, e.g. action=history to Special:Mypage, etc. + * + * @return string + */ + function getRedirectQuery() { + global $wgRequest; + $params = array(); + foreach( $this->mAllowedRedirectParams as $arg ) { + if( $val = $wgRequest->getVal( $arg, false ) ) + $params[] = $arg . '=' . $val; + } + + return count( $params ) ? implode( '&', $params ) : false; + } } /** @@ -583,4 +696,67 @@ class IncludableSpecialPage extends SpecialPage SpecialPage::SpecialPage( $name, $restriction, $listed, $function, $file, true ); } } + +class SpecialRedirectToSpecial extends UnlistedSpecialPage { + var $redirName, $redirSubpage; + + function __construct( $name, $redirName, $redirSubpage = false, $redirectParams = array() ) { + parent::__construct( $name ); + $this->redirName = $redirName; + $this->redirSubpage = $redirSubpage; + $this->mAllowedRedirectParams = $redirectParams; + } + + function getRedirect( $subpage ) { + if ( $this->redirSubpage === false ) { + return SpecialPage::getTitleFor( $this->redirName, $subpage ); + } else { + return SpecialPage::getTitleFor( $this->redirName, $this->redirSubpage ); + } + } +} + +class SpecialMypage extends UnlistedSpecialPage { + function __construct() { + parent::__construct( 'Mypage' ); + $this->mAllowedRedirectParams = array( 'action' ); + } + + function getRedirect( $subpage ) { + global $wgUser; + if ( strval( $subpage ) !== '' ) { + return Title::makeTitle( NS_USER, $wgUser->getName() . '/' . $subpage ); + } else { + return Title::makeTitle( NS_USER, $wgUser->getName() ); + } + } +} + +class SpecialMytalk extends UnlistedSpecialPage { + function __construct() { + parent::__construct( 'Mytalk' ); + $this->mAllowedRedirectParams = array( 'action' ); + } + + function getRedirect( $subpage ) { + global $wgUser; + if ( strval( $subpage ) !== '' ) { + return Title::makeTitle( NS_USER_TALK, $wgUser->getName() . '/' . $subpage ); + } else { + return Title::makeTitle( NS_USER_TALK, $wgUser->getName() ); + } + } +} + +class SpecialMycontributions extends UnlistedSpecialPage { + function __construct() { + parent::__construct( 'Mycontributions' ); + } + + function getRedirect( $subpage ) { + global $wgUser; + return SpecialPage::getTitleFor( 'Contributions', $wgUser->getName() ); + } +} + ?> diff --git a/includes/SpecialPreferences.php b/includes/SpecialPreferences.php index 2484b32271..497c73204b 100644 --- a/includes/SpecialPreferences.php +++ b/includes/SpecialPreferences.php @@ -328,7 +328,7 @@ class PreferencesForm { } if( $needRedirect && $error === false ) { - $title =& Title::makeTitle( NS_SPECIAL, "Preferences" ); + $title =& SpecialPage::getTitleFor( "Preferences" ); $wgOut->redirect($title->getFullURL('success')); return; } @@ -478,7 +478,7 @@ class PreferencesForm { $dateopts = $wgLang->getDatePreferences(); $togs = User::getToggles(); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Preferences' ); + $titleObj = SpecialPage::getTitleFor( 'Preferences' ); $action = $titleObj->escapeLocalURL(); # Pre-expire some toggles so they won't show if disabled @@ -508,7 +508,7 @@ class PreferencesForm { $disableEmailPrefs = true; $skin = $wgUser->getSkin(); $emailauthenticated = wfMsg('emailnotauthenticated').'
    ' . - $skin->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Confirmemail' ), + $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Confirmemail' ), wfMsg( 'emailconfirmlink' ) ); } } else { diff --git a/includes/SpecialRecentchanges.php b/includes/SpecialRecentchanges.php index 8dfb68a578..35f0d29841 100644 --- a/includes/SpecialRecentchanges.php +++ b/includes/SpecialRecentchanges.php @@ -571,7 +571,7 @@ function rcOptionsPanel( $defaults, $nondefaults ) { */ function rcNamespaceForm( $namespace, $invert, $nondefaults, $categories_any ) { global $wgScript, $wgAllowCategorizedRecentChanges, $wgRequest; - $t = Title::makeTitle( NS_SPECIAL, 'Recentchanges' ); + $t = SpecialPage::getTitleFor( 'Recentchanges' ); $namespaceselect = HTMLnamespaceselector($namespace, ''); $submitbutton = '\n"; diff --git a/includes/SpecialRevisiondelete.php b/includes/SpecialRevisiondelete.php index afbb589c60..1ab505dbf1 100644 --- a/includes/SpecialRevisiondelete.php +++ b/includes/SpecialRevisiondelete.php @@ -89,7 +89,7 @@ class RevisionDeleteForm { $hidden[] = wfHidden( 'oldid[]', $revid ); } - $special = Title::makeTitle( NS_SPECIAL, 'Revisiondelete' ); + $special = SpecialPage::getTitleFor( 'Revisiondelete' ); $wgOut->addHtml( wfElement( 'form', array( 'method' => 'post', 'action' => $special->getLocalUrl( 'action=submit' ) ), diff --git a/includes/SpecialSearch.php b/includes/SpecialSearch.php index 057b487cae..8c2f8aad4d 100644 --- a/includes/SpecialSearch.php +++ b/includes/SpecialSearch.php @@ -177,7 +177,7 @@ class SpecialSearch { if( $num || $this->offset ) { $prevnext = wfViewPrevNext( $this->offset, $this->limit, - 'Special:Search', + SpecialPage::getTitleFor( 'Search' ), wfArrayToCGI( $this->powerSearchOptions(), array( 'search' => $term ) ) ); @@ -404,7 +404,7 @@ class SpecialSearch { '', '', '', '', '', # Dummy placeholders $searchButton ); - $title = Title::makeTitle( NS_SPECIAL, 'Search' ); + $title = SpecialPage::getTitleFor( 'Search' ); $action = $title->escapeLocalURL(); return "

    \n\n{$ret}\n\n"; diff --git a/includes/SpecialUndelete.php b/includes/SpecialUndelete.php index e07fa95c31..299cb232ed 100644 --- a/includes/SpecialUndelete.php +++ b/includes/SpecialUndelete.php @@ -495,7 +495,7 @@ class UndeleteForm { $wgOut->addWikiText( wfMsg( "undeletepagetext" ) ); $sk = $wgUser->getSkin(); - $undelete =& Title::makeTitle( NS_SPECIAL, 'Undelete' ); + $undelete =& SpecialPage::getTitleFor( 'Undelete' ); $wgOut->addHTML( "
      \n" ); while( $row = $result->fetchObject() ) { $title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title ); @@ -533,7 +533,7 @@ class UndeleteForm { $wgOut->addWikiText( $rev->getText() ); } - $self = Title::makeTitle( NS_SPECIAL, "Undelete" ); + $self = SpecialPage::getTitleFor( "Undelete" ); $wgOut->addHtml( wfElement( 'textarea', array( @@ -631,7 +631,7 @@ class UndeleteForm { } if ( $this->mAllowed ) { - $titleObj = Title::makeTitle( NS_SPECIAL, "Undelete" ); + $titleObj = SpecialPage::getTitleFor( "Undelete" ); $action = $titleObj->getLocalURL( "action=submit" ); # Start the form here $top = wfOpenElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'undelete' ) ); diff --git a/includes/SpecialUnlockdb.php b/includes/SpecialUnlockdb.php index 6627f75ff8..1f24d131c0 100644 --- a/includes/SpecialUnlockdb.php +++ b/includes/SpecialUnlockdb.php @@ -54,7 +54,7 @@ class DBUnlockForm { } $lc = htmlspecialchars( wfMsg( "unlockconfirm" ) ); $lb = htmlspecialchars( wfMsg( "unlockbtn" ) ); - $titleObj = Title::makeTitle( NS_SPECIAL, "Unlockdb" ); + $titleObj = SpecialPage::getTitleFor( "Unlockdb" ); $action = $titleObj->escapeLocalURL( "action=submit" ); $token = htmlspecialchars( $wgUser->editToken() ); @@ -94,7 +94,7 @@ END $wgOut->showFileDeleteError( $wgReadOnlyFile ); return; } - $titleObj = Title::makeTitle( NS_SPECIAL, "Unlockdb" ); + $titleObj = SpecialPage::getTitleFor( "Unlockdb" ); $success = $titleObj->getFullURL( "action=success" ); $wgOut->redirect( $success ); } diff --git a/includes/SpecialUnusedtemplates.php b/includes/SpecialUnusedtemplates.php index b33a24da05..d232f02d6b 100644 --- a/includes/SpecialUnusedtemplates.php +++ b/includes/SpecialUnusedtemplates.php @@ -37,7 +37,7 @@ class UnusedtemplatesPage extends QueryPage { $title = Title::makeTitle( NS_TEMPLATE, $result->title ); $pageLink = $skin->makeKnownLinkObj( $title, '', 'redirect=no' ); $wlhLink = $skin->makeKnownLinkObj( - Title::makeTitle( NS_SPECIAL, 'Whatlinkshere' ), + SpecialPage::getTitleFor( 'Whatlinkshere' ), wfMsgHtml( 'unusedtemplateswlh' ), 'target=' . $title->getPrefixedUrl() ); return wfSpecialList( $pageLink, $wlhLink ); diff --git a/includes/SpecialUpload.php b/includes/SpecialUpload.php index 29d6f3bab6..5873dfed0c 100644 --- a/includes/SpecialUpload.php +++ b/includes/SpecialUpload.php @@ -398,7 +398,7 @@ class UploadForm { $image = new Image( $nt ); if( $image->wasDeleted() ) { $skin = $wgUser->getSkin(); - $ltitle = Title::makeTitle( NS_SPECIAL, 'Log' ); + $ltitle = SpecialPage::getTitleFor( 'Log' ); $llink = $skin->makeKnownLinkObj( $ltitle, wfMsgHtml( 'deletionlog' ), 'type=delete&page=' . $nt->getPrefixedUrl() ); $warning .= wfOpenElement( 'li' ) . wfMsgWikiHtml( 'filewasdeleted', $llink ) . wfCloseElement( 'li' ); } @@ -632,7 +632,7 @@ class UploadForm { $reupload = wfMsgHtml( 'reupload' ); $iw = wfMsgWikiHtml( 'ignorewarning' ); $reup = wfMsgWikiHtml( 'reuploaddesc' ); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Upload' ); + $titleObj = SpecialPage::getTitleFor( 'Upload' ); $action = $titleObj->escapeLocalURL( 'action=submit' ); if ( $wgUseCopyrightUpload ) @@ -712,7 +712,7 @@ class UploadForm { $ulb = wfMsgHtml( 'uploadbtn' ); - $titleObj = Title::makeTitle( NS_SPECIAL, 'Upload' ); + $titleObj = SpecialPage::getTitleFor( 'Upload' ); $action = $titleObj->escapeLocalURL(); $encDestFile = htmlspecialchars( $this->mDestFile ); diff --git a/includes/SpecialUserlogin.php b/includes/SpecialUserlogin.php index 2cd14687f2..719ab370b1 100644 --- a/includes/SpecialUserlogin.php +++ b/includes/SpecialUserlogin.php @@ -178,7 +178,7 @@ class LoginForm { # Confirm that the account was created global $wgOut; $skin = $wgUser->getSkin(); - $self = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); + $self = SpecialPage::getTitleFor( 'Userlogin' ); $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) ); $wgOut->setArticleRelated( false ); $wgOut->setRobotPolicy( 'noindex,nofollow' ); @@ -564,7 +564,7 @@ class LoginForm { } } - $titleObj = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); + $titleObj = SpecialPage::getTitleFor( 'Userlogin' ); if ( $this->mType == 'signup' ) { $template = new UsercreateTemplate(); @@ -662,7 +662,7 @@ class LoginForm { function cookieRedirectCheck( $type ) { global $wgOut; - $titleObj = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); + $titleObj = SpecialPage::getTitleFor( 'Userlogin' ); $check = $titleObj->getFullURL( 'wpCookieCheck='.$type ); return $wgOut->redirect( $check ); @@ -728,7 +728,7 @@ class LoginForm { */ function makeLanguageSelectorLink( $text, $lang ) { global $wgUser; - $self = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); + $self = SpecialPage::getTitleFor( 'Userlogin' ); $attr[] = 'uselang=' . $lang; if( $this->mType == 'signup' ) $attr[] = 'type=signup'; diff --git a/includes/SpecialUserrights.php b/includes/SpecialUserrights.php index b17cc4aae7..4edbf12805 100644 --- a/includes/SpecialUserrights.php +++ b/includes/SpecialUserrights.php @@ -34,7 +34,7 @@ class UserrightsForm extends HTMLForm { $this->mRequest =& $request; $this->mName = 'userrights'; - $titleObj = Title::makeTitle( NS_SPECIAL, 'Userrights' ); + $titleObj = SpecialPage::getTitleFor( 'Userrights' ); $this->action = $titleObj->escapeLocalURL(); } diff --git a/includes/SpecialWantedpages.php b/includes/SpecialWantedpages.php index 7b070604ea..8e5cee3ec2 100644 --- a/includes/SpecialWantedpages.php +++ b/includes/SpecialWantedpages.php @@ -103,7 +103,7 @@ class WantedPagesPage extends QueryPage { * @return string */ function makeWlhLink( &$title, &$skin, $text ) { - $wlhTitle = Title::makeTitle( NS_SPECIAL, 'Whatlinkshere' ); + $wlhTitle = SpecialPage::getTitleFor( 'Whatlinkshere' ); return $skin->makeKnownLinkObj( $wlhTitle, $text, 'target=' . $title->getPrefixedUrl() ); } diff --git a/includes/SpecialWatchlist.php b/includes/SpecialWatchlist.php index 87c925ac58..0ce03b8b17 100644 --- a/includes/SpecialWatchlist.php +++ b/includes/SpecialWatchlist.php @@ -23,13 +23,13 @@ function wfSpecialWatchlist( $par ) { $fname = 'wfSpecialWatchlist'; $skin =& $wgUser->getSkin(); - $specialTitle = Title::makeTitle( NS_SPECIAL, 'Watchlist' ); + $specialTitle = SpecialPage::getTitleFor( 'Watchlist' ); $wgOut->setRobotPolicy( 'noindex,nofollow' ); # Anons don't get a watchlist if( $wgUser->isAnon() ) { $wgOut->setPageTitle( wfMsg( 'watchnologin' ) ); - $llink = $skin->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Userlogin' ), wfMsgHtml( 'loginreqlink' ), 'returnto=' . $specialTitle->getPrefixedUrl() ); + $llink = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Userlogin' ), wfMsgHtml( 'loginreqlink' ), 'returnto=' . $specialTitle->getPrefixedUrl() ); $wgOut->addHtml( wfMsgWikiHtml( 'watchlistanontext', $llink ) ); return; } else { @@ -325,7 +325,7 @@ function wfSpecialWatchlist( $par ) { $wgOut->addHTML( "\n" . wlCutoffLinks( $days, 'Watchlist', $nondefaults ) . "
      \n" ); # Spit out some control panel links - $thisTitle = Title::makeTitle( NS_SPECIAL, 'Watchlist' ); + $thisTitle = SpecialPage::getTitleFor( 'Watchlist' ); $skin = $wgUser->getSkin(); $linkElements = array( 'hideOwn' => 'wlhideshowown', 'hideBots' => 'wlhideshowbots' ); @@ -493,7 +493,7 @@ function wlHandleClear( &$out, &$request, $par ) { $out->returnToMain(); } else { # Confirming, so show a form - $wlTitle = Title::makeTitle( NS_SPECIAL, 'Watchlist' ); + $wlTitle = SpecialPage::getTitleFor( 'Watchlist' ); $out->addHTML( wfElement( 'form', array( 'method' => 'post', 'action' => $wlTitle->getLocalUrl( 'action=clear' ) ), NULL ) ); $out->addWikiText( wfMsgExt( 'watchlistcount', array( 'parsemag', 'escape'), $wgLang->formatNum( $count ) ) ); $out->addWikiText( wfMsg( 'watchlistcleartext' ) ); diff --git a/includes/Title.php b/includes/Title.php index acc4b89e36..b81b63176b 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -299,7 +299,7 @@ class Title { $rt = Title::newFromText( $m[1] ); # Disallow redirects to Special:Userlogout - if ( !is_null($rt) && $rt->getNamespace() == NS_SPECIAL && preg_match( '/^Userlogout/i', $rt->getText() ) ) { + if ( !is_null($rt) && $rt->isSpecial( 'Userlogout' ) ) { $rt = NULL; } } @@ -2365,5 +2365,37 @@ class Title { return 'nstab-' . $wgContLang->lc( $this->getSubjectNsText() ); } } + + /** + * Returns true if this title resolves to the named special page + * @param string $name The special page name + * @access public + */ + function isSpecial( $name ) { + if ( $this->getNamespace() == NS_SPECIAL ) { + list( $thisName, $subpage ) = SpecialPage::resolveAliasWithSubpage( $this->getDBkey() ); + if ( $name == $thisName ) { + return true; + } + } + return false; + } + + /** + * If the Title refers to a special page alias which is not the local default, + * returns a new Title which points to the local default. Otherwise, returns $this. + */ + function fixSpecialName() { + if ( $this->getNamespace() == NS_SPECIAL ) { + $canonicalName = SpecialPage::resolveAlias( $this->mDbkeyform ); + if ( $canonicalName ) { + $localName = SpecialPage::getLocalNameFor( $canonicalName ); + if ( $localName != $this->mDbkeyform ) { + return Title::makeTitle( NS_SPECIAL, $localName ); + } + } + } + return $this; + } } ?> diff --git a/includes/User.php b/includes/User.php index 5d169e5b60..6bda68e0dc 100644 --- a/includes/User.php +++ b/includes/User.php @@ -2234,7 +2234,7 @@ class User { */ function confirmationTokenUrl( &$expiration ) { $token = $this->confirmationToken( $expiration ); - $title = Title::makeTitle( NS_SPECIAL, 'Confirmemail/' . $token ); + $title = SpecialPage::getTitleFor( 'Confirmemail', $token ); return $title->getFullUrl(); } diff --git a/includes/UserMailer.php b/includes/UserMailer.php index 9428761038..8953d7abb8 100644 --- a/includes/UserMailer.php +++ b/includes/UserMailer.php @@ -382,7 +382,7 @@ class EmailNotification { } else { $subject = str_replace('$PAGEEDITOR', $name, $subject); $keys['$PAGEEDITOR'] = $name; - $emailPage = Title::makeTitle( NS_SPECIAL, 'Emailuser/' . $name ); + $emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $name ); $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getFullUrl(); } $userPage = $wgUser->getUserPage(); diff --git a/includes/Wiki.php b/includes/Wiki.php index 401756bec5..ea89eef4f8 100644 --- a/includes/Wiki.php +++ b/includes/Wiki.php @@ -99,7 +99,7 @@ class MediaWiki { if( !is_null( $search ) && $search !== '' ) { // Compatibility with old search URLs which didn't use Special:Search // Do this above the read whitelist check for security... - $title = Title::makeTitle( NS_SPECIAL, 'Search' ); + $title = SpecialPage::getTitleFor( 'Search' ); } $this->setVal( 'Search', $search ); @@ -125,10 +125,10 @@ class MediaWiki { $action = $this->getVal('Action'); if( !$this->getVal('DisableInternalSearch') && !is_null( $search ) && $search !== '' ) { require_once( 'includes/SpecialSearch.php' ); - $title = Title::makeTitle( NS_SPECIAL, 'Search' ); + $title = SpecialPage::getTitleFor( 'Search' ); wfSpecialSearch(); } else if( !$title or $title->getDBkey() == '' ) { - $title = Title::makeTitle( NS_SPECIAL, 'Badtitle' ); + $title = SpecialPage::getTitleFor( 'Badtitle' ); # Die now before we mess up $wgArticle and the skin stops working throw new ErrorPageError( 'badtitle', 'badtitletext' ); } else if ( $title->getInterwiki() != '' ) { @@ -141,7 +141,7 @@ class MediaWiki { if ( !preg_match( '/^' . preg_quote( $this->getVal('Server'), '/' ) . '/', $url ) && $title->isLocal() ) { $output->redirect( $url ); } else { - $title = Title::makeTitle( NS_SPECIAL, 'Badtitle' ); + $title = SpecialPage::getTitleFor( 'Badtitle' ); throw new ErrorPageError( 'badtitle', 'badtitletext' ); } } else if ( ( $action == 'view' ) && diff --git a/includes/api/ApiFeedWatchlist.php b/includes/api/ApiFeedWatchlist.php index b5003a221b..a2c75b9f84 100644 --- a/includes/api/ApiFeedWatchlist.php +++ b/includes/api/ApiFeedWatchlist.php @@ -71,7 +71,7 @@ class ApiFeedWatchlist extends ApiBase { global $wgFeedClasses, $wgSitename, $wgContLanguageCode; $feedTitle = $wgSitename . ' - ' . wfMsgForContent('watchlist') . ' [' . $wgContLanguageCode . ']'; - $feedUrl = Title :: makeTitle(NS_SPECIAL, 'Watchlist')->getFullUrl(); + $feedUrl = SpecialPage::getTitleFor( 'Watchlist' )->getFullUrl(); $feed = new $wgFeedClasses[$feedformat] ($feedTitle, htmlspecialchars(wfMsgForContent('watchlist')), $feedUrl); @@ -124,4 +124,4 @@ class ApiFeedWatchlist extends ApiBase { return __CLASS__ . ': $Id$'; } } -?> \ No newline at end of file +?> diff --git a/languages/Language.php b/languages/Language.php index 454d60e147..877ebd681d 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -67,13 +67,15 @@ class Language { 'separatorTransformTable', 'fallback8bitEncoding', 'linkPrefixExtension', 'defaultUserOptionOverrides', 'linkTrail', 'namespaceAliases', 'dateFormats', 'datePreferences', 'datePreferenceMigrationMap', - 'defaultDateFormat', 'extraUserToggles' ); + 'defaultDateFormat', 'extraUserToggles', 'specialPageAliases' ); static public $mMergeableMapKeys = array( 'messages', 'namespaceNames', 'mathNames', 'dateFormats', 'defaultUserOptionOverrides', 'magicWords' ); static public $mMergeableListKeys = array( 'extraUserToggles' ); + static public $mMergeableAliasListKeys = array( 'specialPageAliases' ); + static public $mLocalisationCache = array(); static public $mWeekdayMsgs = array( @@ -248,6 +250,10 @@ class Language { } function specialPage( $name ) { + $aliases = $this->getSpecialPageAliases(); + if ( isset( $aliases[$name][0] ) ) { + $name = $aliases[$name][0]; + } return $this->getNsText(NS_SPECIAL) . ':' . $name; } @@ -908,6 +914,21 @@ class Language { $str ); } + /** + * Return a case-folded representation of $s + * + * This is a representation such that caseFold($s1)==caseFold($s2) if $s1 + * and $s2 are the same except for the case of their characters. It is not + * necessary for the value returned to make sense when displayed. + * + * Do *not* perform any other normalisation in this function. If a caller + * uses this function when it should be using a more general normalisation + * function, then fix the caller. + */ + function caseFold( $s ) { + return $this->uc( $s ); + } + function checkTitleEncoding( $s ) { if( is_array( $s ) ) { wfDebugDieBacktrace( 'Given array to checkTitleEncoding.' ); @@ -1083,6 +1104,20 @@ class Language { $mw->mSynonyms = array_slice( $rawEntry, 1 ); } + /** + * Get special page names, as an associative array + * case folded alias => real name + */ + function getSpecialPageAliases() { + $this->load(); + if ( !isset( $this->mExtendedSpecialPageAliases ) ) { + $this->mExtendedSpecialPageAliases = $this->specialPageAliases; + wfRunHooks( 'LangugeGetSpecialPageAliases', + array( &$this->mExtendedSpecialPageAliases, $this->getCode() ) ); + } + return $this->mExtendedSpecialPageAliases; + } + /** * Italic is unsuitable for some languages * @@ -1550,6 +1585,8 @@ class Language { $cache[$key] = $cache[$key] + $secondary[$key]; } elseif ( in_array( $key, self::$mMergeableListKeys ) ) { $cache[$key] = array_merge( $secondary[$key], $cache[$key] ); + } elseif ( in_array( $key, self::$mMergeableAliasListKeys ) ) { + $cache[$key] = array_merge_recursive( $cache[$key], $secondary[$key] ); } } } else { diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 8d35dea21a..7d2de2cf29 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -206,6 +206,8 @@ $bookstoreList = array( * Note to translators: * Please include the English words as synonyms. This allows people * from other wikis to contribute more easily. + * + * This array can be modified at runtime with the LanguageGetMagic hook */ $magicWords = array( # ID CASE SYNONYMS @@ -318,6 +320,81 @@ $magicWords = array( 'padright' => array( 0, 'PADRIGHT' ), ); +/** + * Alternate names of special pages. All names are case-insensitive. The first + * listed alias will be used as the default. Aliases from the fallback + * localisation (usually English) will be included by default. + * + * This array may be altered at runtime using the LangugeGetSpecialPageAliases + * hook. + */ +$specialPageAliases = array( + 'DoubleRedirects' => array( 'DoubleRedirects' ), + 'BrokenRedirects' => array( 'BrokenRedirects' ), + 'Disambiguations' => array( 'Disambiguations' ), + 'Userlogin' => array( 'Userlogin' ), + 'Userlogout' => array( 'Userlogout' ), + 'Preferences' => array( 'Preferences' ), + 'Watchlist' => array( 'Watchlist' ), + 'Recentchanges' => array( 'Recentchanges' ), + 'Upload' => array( 'Upload' ), + 'Imagelist' => array( 'Imagelist' ), + 'Newimages' => array( 'Newimages' ), + 'Listusers' => array( 'Listusers', 'Userlist' ), + 'Statistics' => array( 'Statistics' ), + 'Randompage' => array( 'Random', 'Randompage' ), + 'Lonelypages' => array( 'Lonelypages' ), + 'Uncategorizedpages' => array( 'Uncategorizedpages' ), + 'Uncategorizedcategories' => array( 'Uncategorizedcategories' ), + 'Uncategorizedimages' => array( 'Uncategorizedimages' ), + 'Unusedcategories' => array( 'Unusedcategories' ), + 'Unusedimages' => array( 'Unusedimages' ), + 'Wantedpages' => array( 'Wantedpages' ), + 'Wantedcategories' => array( 'Wantedcategories' ), + 'Mostlinked' => array( 'Mostlinked' ), + 'Mostlinkedcategories' => array( 'Mostlinkedcategories' ), + 'Mostcategories' => array( 'Mostcategories' ), + 'Mostimages' => array( 'Mostimages' ), + 'Mostrevisions' => array( 'Mostrevisions' ), + 'Shortpages' => array( 'Shortpages' ), + 'Longpages' => array( 'Longpages' ), + 'Newpages' => array( 'Newpages' ), + 'Ancientpages' => array( 'Ancientpages' ), + 'Deadendpages' => array( 'Deadendpages' ), + 'Allpages' => array( 'Allpages' ), + 'Prefixindex' => array( 'Prefixindex' ) , + 'Ipblocklist' => array( 'Ipblocklist' ), + 'Specialpages' => array( 'Specialpages' ), + 'Contributions' => array( 'Contributions' ), + 'Emailuser' => array( 'Emailuser' ), + 'Whatlinkshere' => array( 'Whatlinkshere' ), + 'Recentchangeslinked' => array( 'Recentchangeslinked' ), + 'Movepage' => array( 'Movepage' ), + 'Blockme' => array( 'Blockme' ), + 'Booksources' => array( 'Booksources' ), + 'Categories' => array( 'Categories' ), + 'Export' => array( 'Export' ), + 'Version' => array( 'Version' ), + 'Allmessages' => array( 'Allmessages' ), + 'Log' => array( 'Log', 'Logs' ), + 'Blockip' => array( 'Blockip' ), + 'Undelete' => array( 'Undelete' ), + 'Import' => array( 'Import' ), + 'Lockdb' => array( 'Lockdb' ), + 'Unlockdb' => array( 'Unlockdb' ), + 'Userrights' => array( 'Userrights' ), + 'MIMEsearch' => array( 'MIMEsearch' ), + 'Unwatchedpages' => array( 'Unwatchedpages' ), + 'Listredirects' => array( 'Listredirects' ), + 'Revisiondelete' => array( 'Revisiondelete' ), + 'Unusedtemplates' => array( 'Unusedtemplates' ), + 'Randomredirect' => array( 'Randomredirect' ), + 'Mypage' => array( 'Mypage' ), + 'Mytalk' => array( 'Mytalk' ), + 'Mycontributions' => array( 'Mycontributions' ), + 'Listadmins' => array( 'Listadmins' ), +); + /** * Regular expression matching the "link trail", e.g. "ed" in [[Toast]]ed, as * the first group, and the remainder of the string as the second group. diff --git a/maintenance/dumpHTML.inc b/maintenance/dumpHTML.inc index ca2a62dc9d..0f6e62c271 100644 --- a/maintenance/dumpHTML.inc +++ b/maintenance/dumpHTML.inc @@ -193,7 +193,7 @@ class DumpHTML { $this->setupGlobals(); print "Special:Categories..."; - $this->doArticle( Title::makeTitle( NS_SPECIAL, 'Categories' ) ); + $this->doArticle( SpecialPage::getTitleFor( 'Categories' ) ); print "\n"; } diff --git a/opensearch_desc.php b/opensearch_desc.php index 90bfe7d9dd..b06b7feecf 100644 --- a/opensearch_desc.php +++ b/opensearch_desc.php @@ -16,7 +16,7 @@ if ( !preg_match( '/^https?:/', $wgFavicon ) ) { $favicon = htmlspecialchars( $wgFavicon ); } -$title = Title::makeTitle( NS_SPECIAL, 'Search' ); +$title = SpecialPage::getTitleFor( 'Search' ); $template = $title->escapeFullURL( 'search={searchTerms}' ); $suggest = htmlspecialchars($wgServer . $wgScriptPath . '/api.php?action=opensearch&search={searchTerms}'); diff --git a/skins/CologneBlue.php b/skins/CologneBlue.php index 63fe96388b..6ad8914843 100644 --- a/skins/CologneBlue.php +++ b/skins/CologneBlue.php @@ -252,8 +252,8 @@ class SkinCologneBlue extends Skin { wfMsg( "mypage" ) ) . $sep . $tl . $sep . $this->specialLink( "watchlist" ) - . $sep . $this->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, "Contributions" ), - wfMsg( "mycontris" ), "target=" . wfUrlencode($wgUser->getName() ) ) + . $sep . $this->makeKnownLinkObj( SpecialPage::getSafeTitleFor( "Contributions", $wgUser->getName() ), + wfMsg( "mycontris" ) ) . $sep . $this->specialLink( "preferences" ) . $sep . $this->specialLink( "userlogout" ); } else { @@ -275,7 +275,7 @@ class SkinCologneBlue extends Skin { } $s .= $sep . $this->makeKnownLinkObj( - Title::makeTitle( NS_SPECIAL, 'Specialpages' ), + SpecialPage::getTitleFor( 'Specialpages' ), wfMsg( 'moredotdotdot' ) ); $s .= $sep . "\n\n"; -- 2.20.1

    ' . wfMsgHtml( 'namespace' ) . '' . HtmlNamespaceSelector( $this->namespace ) . '