Restore Special:Contributions to its state as of 17964
authorBrion Vibber <brion@users.mediawiki.org>
Tue, 5 Dec 2006 01:11:12 +0000 (01:11 +0000)
committerBrion Vibber <brion@users.mediawiki.org>
Tue, 5 Dec 2006 01:11:12 +0000 (01:11 +0000)
New version doesn't keep all features; keep it off trunk until complete

RELEASE-NOTES
includes/QueryPage.php
includes/SpecialContributions.php
includes/SpecialNewbieContributions.php [deleted file]
includes/SpecialPage.php
languages/messages/MessagesEn.php
languages/messages/MessagesFi.php

index 03cab3e..81c69e6 100644 (file)
@@ -242,9 +242,6 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * {{REVISIONTIMESTAMP}} now uses site local timezone instead of user timezone
   to ensure consistent behavior
 * {{REVISIONTIMESTAMP}} and friends should now work on non-MySQL backends
-* Special:Contributions has been rewritten to inherit from QueryPage
-* New special page Special:NewbieContributions, with a (deprecated)
-  redirect from Special:Contributions/newbies for backwards compatibility
 * (bug 7671) Observe canonical media namespace prefix in Linker::formatComment
 * Added js variable wgCurRevisionId to the output
 * (bug 8141) Cleanup of Parser::doTableStuff, patch by AzaTht
index b8fedc4..850365c 100644 (file)
@@ -14,7 +14,6 @@ $wgQueryPages = array(
        array( 'AncientPagesPage',              'Ancientpages'                  ),
        array( 'BrokenRedirectsPage',           'BrokenRedirects'               ),
        array( 'CategoriesPage',                'Categories'                    ),
-       array( 'ContributionsPage',             'Contributions'                 ),
        array( 'DeadendPagesPage',              'Deadendpages'                  ),
        array( 'DisambiguationsPage',           'Disambiguations'               ),
        array( 'DoubleRedirectsPage',           'DoubleRedirects'               ),
@@ -28,7 +27,6 @@ $wgQueryPages = array(
        array( 'MostlinkedPage',                'Mostlinked'                    ),
        array( 'MostrevisionsPage',             'Mostrevisions'                 ),
        array( 'NewPagesPage',                  'Newpages'                      ),
-       array( 'NewbieContributionsPage',       'NewbieContributions'           ),
        array( 'ShortPagesPage',                'Shortpages'                    ),
        array( 'UncategorizedCategoriesPage',   'Uncategorizedcategories'       ),
        array( 'UncategorizedPagesPage',        'Uncategorizedpages'            ),
index 933d7ee..34de8e0 100644 (file)
 <?php
-
 /**
- * Special page allowing users to view their own contributions
- * and those of others.
- *
  * @package MediaWiki
- * @subpackage Special pages
+ * @subpackage SpecialPage
  */
-class ContributionsPage extends QueryPage {
-       var $user = null;
-       var $namespace = null;
-       var $botmode = false;
 
-       /**
-        * Constructor.
-        * @param $username username to list contribs for (or "newbies" for extra magic)
-        */
-       function __construct( $username='' ) {
-               $this->user = User::newFromName( $username, false );
+/** @package MediaWiki */
+class ContribsFinder {
+       var $username, $offset, $limit, $namespace;
+       var $dbr;
+
+       function ContribsFinder( $username ) {
+               $this->username = $username;
+               $this->namespace = false;
+               $this->dbr =& wfGetDB( DB_SLAVE );
        }
 
-       function openList( $offset ) {
-               return "<ul class='special'>";
+       function setNamespace( $ns ) {
+               $this->namespace = $ns;
        }
-       
-       function closeList() {
-               return '</ul>';
+
+       function setLimit( $limit ) {
+               $this->limit = $limit;
        }
-       
-       /**
-        * @return string Name of this special page.
-        */
-       function getName() {
-               return 'Contributions';
+
+       function setOffset( $offset ) {
+               $this->offset = $offset;
+       }
+
+       function getEditLimit( $dir ) {
+               list( $index, $usercond ) = $this->getUserCond();
+               $nscond = $this->getNamespaceCond();
+               $use_index = $this->dbr->useIndexClause( $index );
+               list( $revision, $page) = $this->dbr->tableNamesN( 'revision', 'page' );
+               $sql =  "SELECT rev_timestamp " .
+                       " FROM $page,$revision $use_index " .
+                       " WHERE rev_page=page_id AND $usercond $nscond" .
+                       " ORDER BY rev_timestamp $dir LIMIT 1";
+
+               $res = $this->dbr->query( $sql, __METHOD__ );
+               $row = $this->dbr->fetchObject( $res );
+               if ( $row ) {
+                       return $row->rev_timestamp;
+               } else {
+                       return false;
+               }
        }
 
-       /**
-        * Not expensive, won't work with the query cache anyway.
-        */
-       function isExpensive() { return false; }
+       function getEditLimits() {
+               return array(
+                       $this->getEditLimit( "ASC" ),
+                       $this->getEditLimit( "DESC" )
+               );
+       }
 
-       /**
-        * Should we?
-        */
-       function isSyndicated() { return false; }
+       function getUserCond() {
+               $condition = '';
 
-       /**
-        * Get target user name.  May be overridden in subclasses.
-        * @return string username
-        */
-       function getUsername() {
-               return $this->user->getName();
+               if ( $this->username == 'newbies' ) {
+                       $max = $this->dbr->selectField( 'user', 'max(user_id)', false, 'make_sql' );
+                       $condition = '>' . (int)($max - $max / 100);
+               }
+
+               if ( $condition == '' ) {
+                       $condition = ' rev_user_text=' . $this->dbr->addQuotes( $this->username );
+                       $index = 'usertext_timestamp';
+               } else {
+                       $condition = ' rev_user '.$condition ;
+                       $index = 'user_timestamp';
+               }
+               return array( $index, $condition );
        }
 
-       /**
-        * @return array Extra URL params for self-links.
-        */
-       function linkParameters() {
-               $params['target'] = $this->getUsername();
+       function getNamespaceCond() {
+               if ( $this->namespace !== false )
+                       return ' AND page_namespace = ' . (int)$this->namespace;
+               return '';
+       }
 
-               if ( isset($this->namespace) )
-                       $params['namespace'] = $this->namespace;
+       function getPreviousOffsetForPaging() {
+               list( $index, $usercond ) = $this->getUserCond();
+               $nscond = $this->getNamespaceCond();
 
-               if ( $this->botmode )
-                       $params['bot'] = 1;
+               $use_index = $this->dbr->useIndexClause( $index );
+               list( $page, $revision ) = $this->dbr->tableNamesN( 'page', 'revision' );
 
-               return $params;
+               $sql =  "SELECT rev_timestamp FROM $page, $revision $use_index " .
+                       "WHERE page_id = rev_page AND rev_timestamp > '" . $this->offset . "' AND " .
+                       $usercond . $nscond;
+               $sql .= " ORDER BY rev_timestamp ASC";
+               $sql = $this->dbr->limitResult( $sql, $this->limit, 0 );
+               $res = $this->dbr->query( $sql );
+               
+               $numRows = $this->dbr->numRows( $res );
+               if ( $numRows ) {
+                       $this->dbr->dataSeek( $res, $numRows - 1 );
+                       $row = $this->dbr->fetchObject( $res );
+                       $offset = $row->rev_timestamp;
+               } else {
+                       $offset = false;
+               }
+               $this->dbr->freeResult( $res );
+               return $offset;
        }
 
-       /**
-        * Build the list of links to be shown in the subtitle.
-        * @return string Link list for "contribsub" UI message.
-        */
-       function getTargetUserLinks() {
-               global $wgSysopUserBans, $wgLang, $wgUser;
+       function getFirstOffsetForPaging() {
+               list( $index, $usercond ) = $this->getUserCond();
+               $use_index = $this->dbr->useIndexClause( $index );
+               list( $page, $revision ) = $this->dbr->tableNamesN( 'page', 'revision' );
+               $nscond = $this->getNamespaceCond();
+               $sql =  "SELECT rev_timestamp FROM $page, $revision $use_index " .
+                       "WHERE page_id = rev_page AND " .
+                       $usercond . $nscond;
+               $sql .= " ORDER BY rev_timestamp ASC";
+               $sql = $this->dbr->limitResult( $sql, $this->limit, 0 );
+               $res = $this->dbr->query( $sql );
+               
+               $numRows = $this->dbr->numRows( $res );
+               if ( $numRows ) {
+                       $this->dbr->dataSeek( $res, $numRows - 1 );
+                       $row = $this->dbr->fetchObject( $res );
+                       $offset = $row->rev_timestamp;
+               } else {
+                       $offset = false;
+               }
+               $this->dbr->freeResult( $res );
+               return $offset;
+       }
 
-               $skin = $wgUser->getSkin();
+       /* private */ function makeSql() {
+               $offsetQuery = '';
+
+               list( $page, $revision ) = $this->dbr->tableNamesN( 'page', 'revision' );
+               list( $index, $userCond ) = $this->getUserCond();
+
+               if ( $this->offset )
+                       $offsetQuery = "AND rev_timestamp <= '{$this->offset}'";
+
+               $nscond = $this->getNamespaceCond();
+               $use_index = $this->dbr->useIndexClause( $index );
+               $sql = "SELECT
+                       page_namespace,page_title,page_is_new,page_latest,
+                       rev_id,rev_page,rev_text_id,rev_timestamp,rev_comment,rev_minor_edit,rev_user,rev_user_text,
+                       rev_deleted
+                       FROM $page,$revision $use_index
+                       WHERE page_id=rev_page AND $userCond $nscond $offsetQuery
+                       ORDER BY rev_timestamp DESC";
+               $sql = $this->dbr->limitResult( $sql, $this->limit, 0 );
+               return $sql;
+       }
 
-               $username = $this->getUsername();
-               $userpage = $this->user->getUserPage();
-               $userlink = $skin->makeLinkObj( $userpage, $username );
+       function find() {
+               $contribs = array();
+               $res = $this->dbr->query( $this->makeSql(), __METHOD__ );
+               while ( $c = $this->dbr->fetchObject( $res ) )
+                       $contribs[] = $c;
+               $this->dbr->freeResult( $res );
+               return $contribs;
+       }
+};
 
-               // talk page link
-               $tools[] = $skin->makeLinkObj( $userpage->getTalkPage(), $wgLang->getNsText( NS_TALK ) );
+/**
+ * Special page "user contributions".
+ * Shows a list of the contributions of a user.
+ *
+ * @return     none
+ * @param      $par    String: (optional) user name of the user for which to show the contributions
+ */
+function wfSpecialContributions( $par = null ) {
+       global $wgUser, $wgOut, $wgLang, $wgRequest;
 
-               // block or block log link
-               $id = $this->user->getId();
-               if ( ( $id != 0 && $wgSysopUserBans ) || ( $id == 0 && User::isIP( $username ) ) ) {
-                       if( $wgUser->isAllowed( 'block' ) )
-                               $tools[] = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Blockip', $username ),
-                                                                 wfMsgHtml( 'blocklink' ) );
-                       else
-                               $tools[] = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ),
-                                                                 htmlspecialchars( LogPage::logName( 'block' ) ),
-                                                                 'type=block&page=' . $userpage->getPrefixedUrl() );
-               }
+       $target = isset( $par ) ? $par : $wgRequest->getVal( 'target' );
+       if ( !strlen( $target ) ) {
+               $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
+               return;
+       }
+
+       $nt = Title::newFromURL( $target );
+       if ( !$nt ) {
+               $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
+               return;
+       }
+
+       $options = array();
+
+       list( $options['limit'], $options['offset']) = wfCheckLimits();
+       $options['offset'] = $wgRequest->getVal( 'offset' );
+       /* Offset must be an integral. */
+       if ( !strlen( $options['offset'] ) || !preg_match( '/^[0-9]+$/', $options['offset'] ) )
+               $options['offset'] = '';
 
-               // other logs link
-               $tools[] = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ),
-                                                 wfMsgHtml( 'log' ),
-                                                 'user=' . $userpage->getPartialUrl() );
+       $title = SpecialPage::getTitleFor( 'Contributions' );
+       $options['target'] = $target;
 
-               return $userlink . ' (' . implode( ' | ', $tools ) . ')';
-       }
+       $nt =& Title::makeTitle( NS_USER, $nt->getDBkey() );
+       $finder = new ContribsFinder( ( $target == 'newbies' ) ? 'newbies' : $nt->getText() );
+       $finder->setLimit( $options['limit'] );
+       $finder->setOffset( $options['offset'] );
 
-       /**
-        * Generate "For User (...)" message in subtitle.  Calls
-        * getTargetUserLinks() for most of the work.
-        * @return string 
-        */
-       function getSubtitleForTarget() {
-               return wfMsgHtml( 'contribsub', $this->getTargetUserLinks() );
+       if ( ( $ns = $wgRequest->getVal( 'namespace', null ) ) !== null && $ns !== '' ) {
+               $options['namespace'] = intval( $ns );
+               $finder->setNamespace( $options['namespace'] );
+       } else {
+               $options['namespace'] = '';
        }
 
-       /**
-        * If the user has deleted contributions and we are allowed to
-        * view them, generate a link to Special:DeletedContributions.
-        * @return string 
-        */
-       function getDeletedContributionsLink() {
-               global $wgUser;
-
-               if( !$wgUser->isAllowed( 'deletedhistory' ) )
-                       return '';
-
-               $dbr = wfGetDB( DB_SLAVE );
-               $n = $dbr->selectField( 'archive', 'count(*)', array( 'ar_user_text' => $this->getUsername() ), __METHOD__ );
-
-               if ( $n == 0 )
-                       return '';
-
-               $msg = wfMsg( ( $wgUser->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted' ),
-                             $wgUser->getSkin()->makeKnownLinkObj(
-                                     SpecialPage::getTitleFor( 'DeletedContributions', $this->getUsername() ),
-                                     wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $n ) ) );
-
-               return "<p>$msg</p>";
-       }
-
-       /**
-        * Construct and output the page subtitle.
-        */
-       function outputSubtitle() {
-               global $wgOut;
-               $subtitle = $this->getSubtitleForTarget();
-               // $subtitle .= $this->getDeletedContributionsLink();  NOT YET...
-               $wgOut->setSubtitle( $subtitle );
-       }
-
-       /**
-        * Construct the namespace selector form.
-        * @return string 
-        */
-       function getNamespaceForm() {
-               $title = $this->getTitle();
-
-               $ns = $this->namespace;
-               if ( !isset($ns) )
-                       $ns = '';
-
-               $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $title->getLocalUrl() ) );
-               $form .= wfMsgHtml( 'namespace' ) . ' ';
-               $form .= Xml::namespaceSelector( $ns, '' ) . ' ';
-               $form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) );
-               $form .= Xml::hidden( 'offset', $this->offset );
-               $form .= Xml::hidden( 'limit',  $this->limit );
-               $form .= Xml::hidden( 'target', $this->getUsername() );
-               if ( $this->botmode )
-                       $form .= Xml::hidden( 'bot', 1 );
-               $form .= '</form>';
-
-               return '<p>' . $form . '</p>';
-       }
-
-       /**
-        * Build the page header.  Also calls outputSubtitle().
-        * @return string 
-        */
-       function getPageHeader() {
-               $this->outputSubtitle();
-               return $this->getNamespaceForm();
-       }
-
-       /**
-        * Construct the WHERE clause of the SQL SELECT statement for
-        * this query.
-        * @return string
-        */
-       function makeSQLCond( $dbr ) {
-               $cond = ' page_id = rev_page';
-               $cond .= ' AND rev_user_text = ' . $dbr->addQuotes( $this->getUsername() );
-
-               if ( isset($this->namespace) )
-                       $cond .= ' AND page_namespace = ' . (int)$this->namespace;
-
-               return $cond;
-       }
-
-       /**
-        * Construct the SQL SELECT statement for this query.
-        * @return string
-        */
-       function getSQL() {
-               $dbr = wfGetDB( DB_SLAVE );
-
-               list( $page, $revision ) = $dbr->tableNamesN( 'page', 'revision' );
-
-               // XXX: the username and userid fields aren't used for much here,
-               // but some subclasses rely on them more than we do.
-
-               return "SELECT 'Contributions' as type,
-                               page_namespace AS namespace,
-                               page_title     AS title,
-                               rev_timestamp  AS value,
-                               rev_user       AS userid,
-                               rev_user_text  AS username,
-                               rev_minor_edit AS is_minor,
-                               page_latest    AS cur_id,
-                               rev_id         AS rev_id,
-                               rev_comment    AS comment,
-                               rev_deleted    AS deleted
-                       FROM $page, $revision
-                       WHERE " . $this->makeSQLCond( $dbr );
-       }
-
-       /**
-        * Get user links for output row, for subclasses that may want
-        * such functionality.
-        *
-        * @param $skin Skin to use
-        * @param $row Result row
-        * @return string
-        */
-       function getRowUserLinks( $skin, $row ) { return ''; }
-
-       /**
-        * Format a row, providing the timestamp, links to the
-        * page/diff/history and a comment
-        *
-        * @param $skin Skin to use
-        * @param $row Result row
-        * @return string
-        */
-       function formatResult( $skin, $row ) {
-               global $wgLang, $wgContLang, $wgUser;
-
-               $dm = $wgContLang->getDirMark();
-
-               /*
-                * Cache UI messages in a static array so we don't
-                * have to regenerate them for each row.
-                */
-               static $messages;
-               if( !isset( $messages ) ) {
-                       foreach( explode( ' ', 'uctop diff newarticle rollbacklink diff hist minoreditletter' ) as $msg )
-                               $messages[$msg] = wfMsgExt( $msg, array( 'escape') );
+       if ( $wgUser->isAllowed( 'rollback' ) && $wgRequest->getBool( 'bot' ) ) {
+               $options['bot'] = '1';
+       }
+
+       if ( $wgRequest->getText( 'go' ) == 'prev' ) {
+               $offset = $finder->getPreviousOffsetForPaging();
+               if ( $offset !== false ) {
+                       $options['offset'] = $offset;
+                       $prevurl = $title->getLocalURL( wfArrayToCGI( $options ) );
+                       $wgOut->redirect( $prevurl );
+                       return;
                }
+       }
 
-               $page = Title::makeTitle( $row->namespace, $row->title );
+       if ( $wgRequest->getText( 'go' ) == 'first' && $target != 'newbies') {
+               $offset = $finder->getFirstOffsetForPaging();
+               if ( $offset !== false ) {
+                       $options['offset'] = $offset;
+                       $prevurl = $title->getLocalURL( wfArrayToCGI( $options ) );
+                       $wgOut->redirect( $prevurl );
+                       return;
+               }
+       }
 
-               /*
-                * HACK: We need a revision object, so we make a very
-                * heavily stripped-down one.  All we really need are
-                * the comment, the title and the deletion bitmask.
-                */
-               $rev = new Revision( array(
-                       'comment'   => $row->comment,
-                       'deleted'   => $row->deleted,
-                       'user_text' => $row->username,
-                       'user'      => $row->userid,
-               ) );
-               $rev->setTitle( $page );
+       if ( $target == 'newbies' ) {
+               $wgOut->setSubtitle( wfMsgHtml( 'sp-contributions-newbies-sub') );
+       } else {
+               $wgOut->setSubtitle( wfMsgHtml( 'contribsub', contributionsSub( $nt ) ) );
+       }
 
-               $ts = wfTimestamp( TS_MW, $row->value );
-               $time = $wgLang->timeAndDate( $ts, true );
-               $hist = $skin->makeKnownLinkObj( $page, $messages['hist'], 'action=history' );
+       $id = User::idFromName( $nt->getText() );
+       wfRunHooks( 'SpecialContributionsBeforeMainOutput', $id );
 
-               if ( $rev->userCan( Revision::DELETED_TEXT ) )
-                       $diff = $skin->makeKnownLinkObj( $page, $messages['diff'], 'diff=prev&oldid=' . $row->rev_id );
-               else
-                       $diff = $messages['diff'];
+       $wgOut->addHTML( contributionsForm( $options) );
 
-               if( $row->is_minor )
-                       $mflag = '<span class="minor">' . $messages['minoreditletter'] . '</span> ';
-               else
-                       $mflag = '';
+       $contribs = $finder->find();
 
-               $link    = $skin->makeKnownLinkObj( $page );
-               $comment = $skin->revComment( $rev );
+       if ( count( $contribs ) == 0) {
+               $wgOut->addWikiText( wfMsg( 'nocontribs' ) );
+               return;
+       }
 
-               $user = $this->getRowUserLinks( $skin, $row );  // for subclasses
+       list( $early, $late ) = $finder->getEditLimits();
+       $lastts = count( $contribs ) ? $contribs[count( $contribs ) - 1]->rev_timestamp : 0;
+       $atstart = ( !count( $contribs ) || $late == $contribs[0]->rev_timestamp );
+       $atend = ( !count( $contribs ) || $early == $lastts );
+
+       // These four are defaults
+       $newestlink = wfMsgHtml( 'sp-contributions-newest' );
+       $oldestlink = wfMsgHtml( 'sp-contributions-oldest' );
+       $newerlink  = wfMsgHtml( 'sp-contributions-newer', $options['limit'] );
+       $olderlink  = wfMsgHtml( 'sp-contributions-older', $options['limit'] );
+
+       if ( !$atstart ) {
+               $stuff = $title->escapeLocalURL( wfArrayToCGI( array( 'offset' => '' ), $options ) );
+               $newestlink = "<a href=\"$stuff\">$newestlink</a>";
+               $stuff = $title->escapeLocalURL( wfArrayToCGI( array( 'go' => 'prev' ), $options ) );
+               $newerlink = "<a href=\"$stuff\">$newerlink</a>";
+       }
 
-               $notes = '';
+       if ( !$atend ) {
+               $stuff = $title->escapeLocalURL( wfArrayToCGI( array( 'go' => 'first' ), $options ) );
+               $oldestlink = "<a href=\"$stuff\">$oldestlink</a>";
+               $stuff = $title->escapeLocalURL( wfArrayToCGI( array( 'offset' => $lastts ), $options ) );
+               $olderlink = "<a href=\"$stuff\">$olderlink</a>";
+       }
 
-               if( $row->rev_id == $row->cur_id ) {
-                       $notes .= ' <strong>' . $messages['uctop'] . '</strong>';
+       if ( $target == 'newbies' ) {
+               $firstlast ="($newestlink)";
+       } else {
+               $firstlast = "($newestlink | $oldestlink)";
+       }
 
-                       if( $wgUser->isAllowed( 'rollback' ) )
-                               $notes .= ' ' . $skin->generateRollback( $rev );
-               }
-               
-               if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
-                       $time = '<span class="history-deleted">' . $time . '</span>';
-                       $notes .= ' ' . wfMsgHtml( 'deletedrev' );
+       $urls = array();
+       foreach ( array( 20, 50, 100, 250, 500 ) as $num ) {
+               $stuff = $title->escapeLocalURL( wfArrayToCGI( array( 'limit' => $num ), $options ) );
+               $urls[] = "<a href=\"$stuff\">".$wgLang->formatNum( $num )."</a>";
+       }
+       $bits = implode( $urls, ' | ' );
+
+       $prevnextbits = $firstlast .' '. wfMsgHtml( 'viewprevnext', $newerlink, $olderlink, $bits );
+
+       $wgOut->addHTML( "<p>{$prevnextbits}</p>\n" );
+
+       $wgOut->addHTML( "<ul>\n" );
+
+       $sk = $wgUser->getSkin();
+       foreach ( $contribs as $contrib )
+               $wgOut->addHTML( ucListEdit( $sk, $contrib ) );
+
+       $wgOut->addHTML( "</ul>\n" );
+       $wgOut->addHTML( "<p>{$prevnextbits}</p>\n" );
+}
+
+/**
+ * Generates the subheading with links
+ * @param $nt @see Title object for the target
+ */
+function contributionsSub( $nt ) {
+       global $wgSysopUserBans, $wgLang, $wgUser;
+
+       $sk = $wgUser->getSkin();
+       $id = User::idFromName( $nt->getText() );
+
+       if ( 0 == $id ) {
+               $ul = $nt->getText();
+       } else {
+               $ul = $sk->makeLinkObj( $nt, htmlspecialchars( $nt->getText() ) );
+       }
+       $talk = $nt->getTalkPage();
+       if( $talk ) {
+               # Talk page link        
+               $tools[] = $sk->makeLinkObj( $talk, $wgLang->getNsText( NS_TALK ) );
+               if( ( $id != 0 && $wgSysopUserBans ) || ( $id == 0 && User::isIP( $nt->getText() ) ) ) {
+                       # Block link
+                       if( $wgUser->isAllowed( 'block' ) )
+                               $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ), wfMsgHtml( 'blocklink' ) );
+                       # Block log link
+                       $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ), htmlspecialchars( LogPage::logName( 'block' ) ), 'type=block&page=' . $nt->getPrefixedUrl() );
                }
-               
-               return "{$time} ({$hist}) ({$diff}) {$mflag} {$dm}{$link}{$user} {$comment}{$notes}";
+               # Other logs link
+               $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ), wfMsgHtml( 'log' ), 'user=' . $nt->getPartialUrl() );
+               $ul .= ' (' . implode( ' | ', $tools ) . ')';
        }
+       return $ul;
 }
 
 /**
- * Show the special page.
+ * Generates the namespace selector form with hidden attributes.
+ * @param $options Array: the options to be included.
  */
-function wfSpecialContributions( $par = null ) {
-       global $wgRequest, $wgUser, $wgOut;
+function contributionsForm( $options ) {
+       global $wgScript, $wgTitle;
+
+       $options['title'] = $wgTitle->getPrefixedText();
+
+       $f = "<form method='get' action=\"$wgScript\">\n";
+       foreach ( $options as $name => $value ) {
+               if( $name === 'namespace') continue;
+               $f .= "\t" . wfElement( 'input', array(
+                       'name' => $name,
+                       'type' => 'hidden',
+                       'value' => $value ) ) . "\n";
+       }
 
-       $username = ( isset($par) ? $par : $wgRequest->getVal( 'target' ) );
+       $f .= '<p>' . wfMsgHtml( 'namespace' ) . ' ' .
+       HTMLnamespaceselector( $options['namespace'], '' ) .
+       wfElement( 'input', array(
+                       'type' => 'submit',
+                       'value' => wfMsg( 'allpagessubmit' ) )
+       ) .
+       "</p></form>\n";
 
-       // compatibility hack
-       if ( $username == 'newbies' ) {
-               $wgOut->redirect( SpecialPage::getTitleFor( 'NewbieContributions' )->getFullURL() );
-               return;
+       return $f;
+}
+
+/**
+ * Generates each row in the contributions list.
+ *
+ * Contributions which are marked "top" are currently on top of the history.
+ * For these contributions, a [rollback] link is shown for users with sysop
+ * privileges. The rollback link restores the most recent version that was not
+ * written by the target user.
+ *
+ * @todo This would probably look a lot nicer in a table.
+ */
+function ucListEdit( $sk, $row ) {
+       $fname = 'ucListEdit';
+       wfProfileIn( $fname );
+
+       global $wgLang, $wgUser, $wgRequest;
+       static $messages;
+       if( !isset( $messages ) ) {
+               foreach( explode( ' ', 'uctop diff newarticle rollbacklink diff hist minoreditletter' ) as $msg ) {
+                       $messages[$msg] = wfMsgExt( $msg, array( 'escape') );
+               }
        }
 
-       $page = new ContributionsPage( $username );
+       $rev = new Revision( $row );
+
+       $page = Title::makeTitle( $row->page_namespace, $row->page_title );
+       $link = $sk->makeKnownLinkObj( $page );
+       $difftext = $topmarktext = '';
+       if( $row->rev_id == $row->page_latest ) {
+               $topmarktext .= '<strong>' . $messages['uctop'] . '</strong>';
+               if( !$row->page_is_new ) {
+                       $difftext .= '(' . $sk->makeKnownLinkObj( $page, $messages['diff'], 'diff=0' ) . ')';
+               } else {
+                       $difftext .= $messages['newarticle'];
+               }
+
+               if( $wgUser->isAllowed( 'rollback' ) ) {
+                       $topmarktext .= ' '.$sk->generateRollback( $rev );
+               }
 
-       if( !$page->user ) {
-               $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
-               return;
        }
 
-       // hook for Contributionseditcount extension
-       if ( $page->user && $page->user->isLoggedIn() )
-               wfRunHooks( 'SpecialContributionsBeforeMainOutput', $page->user->getId() );
-               
-       $page->namespace = $wgRequest->getIntOrNull( 'namespace' );
-       $page->botmode   = ( $wgUser->isAllowed( 'rollback' ) && $wgRequest->getBool( 'bot' ) );
+       if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+               if ( $rev->userCan( Revision::DELETED_TEXT ) ) {
+                       $difftext .= '(' . $sk->makeKnownLinkObj( $page, $messages['diff'], 'diff=prev&oldid='.$row->rev_id ) . ')';
+               } else {
+                       $difftext .= '(' . $messages['diff'] . ')';
+               }
+       }
+       $histlink='('.$sk->makeKnownLinkObj( $page, $messages['hist'], 'action=history' ) . ')';
+
+       $comment = $sk->revComment( $rev );
+       $d = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->rev_timestamp ), true );
        
-       list( $limit, $offset ) = wfCheckLimits();
-       return $page->doQuery( $offset, $limit );
+       if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+               $d = '<span class="history-deleted">' . $d . '</span>';
+       }
+
+       if( $row->rev_minor_edit ) {
+               $mflag = '<span class="minor">' . $messages['minoreditletter'] . '</span> ';
+       } else {
+               $mflag = '';
+       }
+
+       $ret = "{$d} {$histlink} {$difftext} {$mflag} {$link} {$comment} {$topmarktext}";
+       if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+               $ret .= ' ' . wfMsgHtml( 'deletedrev' );
+       }
+       $ret = "<li>$ret</li>\n";
+       wfProfileOut( $fname );
+       return $ret;
 }
 
 ?>
diff --git a/includes/SpecialNewbieContributions.php b/includes/SpecialNewbieContributions.php
deleted file mode 100644 (file)
index 7e8e948..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-/**
- * Special page allowing users to view the contributions of new users.
- *
- * @package MediaWiki
- * @subpackage Special pages
- */
-class NewbieContributionsPage extends ContributionsPage {
-
-       /**
-        * Constructor.  No need for username.
-        */
-       function __construct() { }
-
-       /**
-        * @return string Name of this special page.
-        */
-       function getName() {
-               return 'NewbieContributions';
-       }
-
-       /**
-        * No target user here.
-        */
-       function getUsername() {
-               return '';
-       }
-
-       /**
-        * No target user => no subtitle.
-        */
-       function getSubtitleForTarget() {
-               return '';
-       }
-
-       /**
-        * No target user => no deleted contribs link.
-        */
-       function getDeletedContributionsLink() {
-               return '';
-       }
-
-       /**
-        * Construct the WHERE clause of the SQL SELECT statement for
-        * this query.
-        * @return string
-        */
-       function makeSQLCond( $dbr ) {
-               $cond = ' page_id = rev_page';
-
-               $max = $dbr->selectField( 'user', 'max(user_id)', false, 'make_sql' );
-               $cond .= ' AND rev_user > ' . (int)($max - $max / 100);
-
-               if ( isset($this->namespace) )
-                       $cond .= ' AND page_namespace = ' . (int)$this->namespace;
-
-               return $cond;
-       }
-
-       /**
-        * Do a batch existence check for any user and user talk pages
-        * that will be shown in the list.
-        */
-       function preprocessResults( $dbr, $res ) {
-               $linkBatch = new LinkBatch();
-               while( $row = $dbr->fetchObject( $res ) ) {
-                       $linkBatch->add( NS_USER, $row->username );
-                       $linkBatch->add( NS_USER_TALK, $row->username );
-               }
-               $linkBatch->execute();
-
-               // Seek to start
-               if( $dbr->numRows( $res ) > 0 )
-                       $dbr->dataSeek( $res, 0 );
-       }
-
-       /**
-        * Get user links for output row.
-        *
-        * @param $skin Skin to use
-        * @param $row Result row
-        * @return string User links
-        */
-       function getRowUserLinks( $skin, $row ) {
-               $user = ' . . ' . $skin->userLink( $row->userid, $row->username )
-                               . $skin->userToolLinks( $row->userid, $row->username );
-               return $user;
-       }
-}
-
-/**
- * Show the special page.
- */
-function wfSpecialNewbieContributions( $par = null ) {
-       global $wgRequest, $wgUser, $wgOut;
-
-       $page = new NewbieContributionsPage();
-
-       $page->namespace = $wgRequest->getIntOrNull( 'namespace' );
-       $page->botmode   = ( $wgUser->isAllowed( 'rollback' ) && $wgRequest->getBool( 'bot' ) );
-       
-       list( $limit, $offset ) = wfCheckLimits();
-       return $page->doQuery( $offset, $limit );
-}
-
-?>
index 92aa4cb..e8db18b 100644 (file)
@@ -114,7 +114,6 @@ class SpecialPage
                'Ipblocklist'               => array( 'SpecialPage', 'Ipblocklist' ),
                'Specialpages'              => array( 'UnlistedSpecialPage', 'Specialpages' ),
                'Contributions'             => array( 'UnlistedSpecialPage', 'Contributions' ),
-               'NewbieContributions'       => array( 'SpecialPage', 'NewbieContributions' ),
                'Emailuser'                 => array( 'UnlistedSpecialPage', 'Emailuser' ),
                'Whatlinkshere'             => array( 'UnlistedSpecialPage', 'Whatlinkshere' ),
                'Recentchangeslinked'       => array( 'UnlistedSpecialPage', 'Recentchangeslinked' ),
index f1860b2..5e7a573 100644 (file)
@@ -380,7 +380,6 @@ $specialPageAliases = array(
        'Ipblocklist'               => array( 'Ipblocklist' ),
        'Specialpages'              => array( 'Specialpages' ),
        'Contributions'             => array( 'Contributions' ),
-       'NewbieContributions'       => array( 'NewbieContributions' ),
        'Emailuser'                 => array( 'Emailuser' ),
        'Whatlinkshere'             => array( 'Whatlinkshere' ),
        'Recentchangeslinked'       => array( 'Recentchangeslinked' ),
@@ -1755,11 +1754,19 @@ Consult the [[Special:Log/delete|deletion log]] for a record of recent deletions
 'contributions' => 'User contributions',
 'mycontris'     => 'My contributions',
 'contribsub'    => "For $1",
+'nocontribs'    => 'No changes were found matching these criteria.',
+'ucnote'        => "Below are this user's last <b>$1</b> changes in the last <b>$2</b> days.",
+'uclinks'       => "View the last $1 changes; view the last $2 days.",
 'uctop'         => ' (top)' ,
+'newbies'       => 'newbies',
 
-# Newbie contributions
-#
-'newbiecontributions' => 'Newbie contributions',
+'sp-newimages-showfrom' => 'Show new images starting from $1',
+
+'sp-contributions-newest' => 'Newest',
+'sp-contributions-oldest' => 'Oldest',
+'sp-contributions-newer'  => 'Newer $1',
+'sp-contributions-older'  => 'Older $1',
+'sp-contributions-newbies-sub' => 'For newbies',
 
 
 # What links here
@@ -2161,7 +2168,6 @@ ta[\'ca-nstab-category\'] = new Array(\'c\',\'View the category page\');',
 'newimages-summary' => '',
 'showhidebots' => '($1 bots)',
 'noimages'  => 'Nothing to see.',
-'sp-newimages-showfrom' => 'Show new images starting from $1',
 
 # short names for language variants used for language conversion links.
 # to disable showing a particular link, set it to 'disable', e.g.
index b9bddc4..da69814 100644 (file)
@@ -1137,11 +1137,17 @@ Palaute ja lisäapu osoitteessa:
 'contributions'       => 'Käyttäjän muokkaukset',
 'mycontris'           => 'Muokkaukset',
 'contribsub'          => 'Käyttäjän $1 muokkaukset',
+'nocontribs'          => 'Näihin ehtoihin sopivia muokkauksia ei löytynyt.',
+'ucnote'              => 'Alla on \'\'\'$1\'\'\' viimeisintä tämän käyttäjän tekemää muokkausta viimeisten \'\'\'$2\'\'\' päivän aikana.',
+'uclinks'             => 'Katso $1 viimeisintä muokkausta; katso $2 viimeisintä päivää.',
 'uctop'               => ' (uusin)' ,
+'newbies'             => 'tulokkaat',
 
-# Newbie contributions
-#
-'newbiecontributions' => 'Uusien tulokkaiden muokkaukset',
+'sp-contributions-newest' => 'Uusimmat',
+'sp-contributions-oldest' => 'Vanhimmat',
+'sp-contributions-newer'  => '← $1 uudempaa',
+'sp-contributions-older'  => '$1 vanhempaa →',
+'sp-contributions-newbies-sub' => 'Uusien tulokkaiden muokkaukset',
 
 # What links here
 #