[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/specials/ -> SpecialRecentchanges.php (source)

   1  <?php
   2  /**
   3   * Implements Special:Recentchanges
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   * @ingroup SpecialPage
  22   */
  23  
  24  /**
  25   * A special page that lists last changes made to the wiki
  26   *
  27   * @ingroup SpecialPage
  28   */
  29  class SpecialRecentChanges extends ChangesListSpecialPage {
  30      // @codingStandardsIgnoreStart Needed "useless" override to change parameters.
  31  	public function __construct( $name = 'Recentchanges', $restriction = '' ) {
  32          parent::__construct( $name, $restriction );
  33      }
  34      // @codingStandardsIgnoreEnd
  35  
  36      /**
  37       * Main execution point
  38       *
  39       * @param string $subpage
  40       */
  41  	public function execute( $subpage ) {
  42          // Backwards-compatibility: redirect to new feed URLs
  43          $feedFormat = $this->getRequest()->getVal( 'feed' );
  44          if ( !$this->including() && $feedFormat ) {
  45              $query = $this->getFeedQuery();
  46              $query['feedformat'] = $feedFormat === 'atom' ? 'atom' : 'rss';
  47              $this->getOutput()->redirect( wfAppendQuery( wfScript( 'api' ), $query ) );
  48  
  49              return;
  50          }
  51  
  52          // 10 seconds server-side caching max
  53          $this->getOutput()->setSquidMaxage( 10 );
  54          // Check if the client has a cached version
  55          $lastmod = $this->checkLastModified();
  56          if ( $lastmod === false ) {
  57              return;
  58          }
  59  
  60          parent::execute( $subpage );
  61      }
  62  
  63      /**
  64       * Get a FormOptions object containing the default options
  65       *
  66       * @return FormOptions
  67       */
  68  	public function getDefaultOptions() {
  69          $opts = parent::getDefaultOptions();
  70          $user = $this->getUser();
  71  
  72          $opts->add( 'days', $user->getIntOption( 'rcdays' ) );
  73          $opts->add( 'limit', $user->getIntOption( 'rclimit' ) );
  74          $opts->add( 'from', '' );
  75  
  76          $opts->add( 'hideminor', $user->getBoolOption( 'hideminor' ) );
  77          $opts->add( 'hidebots', true );
  78          $opts->add( 'hideanons', false );
  79          $opts->add( 'hideliu', false );
  80          $opts->add( 'hidepatrolled', $user->getBoolOption( 'hidepatrolled' ) );
  81          $opts->add( 'hidemyself', false );
  82  
  83          $opts->add( 'categories', '' );
  84          $opts->add( 'categories_any', false );
  85          $opts->add( 'tagfilter', '' );
  86  
  87          return $opts;
  88      }
  89  
  90      /**
  91       * Get custom show/hide filters
  92       *
  93       * @return array Map of filter URL param names to properties (msg/default)
  94       */
  95  	protected function getCustomFilters() {
  96          if ( $this->customFilters === null ) {
  97              $this->customFilters = parent::getCustomFilters();
  98              wfRunHooks( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ), '1.23' );
  99          }
 100  
 101          return $this->customFilters;
 102      }
 103  
 104      /**
 105       * Process $par and put options found in $opts. Used when including the page.
 106       *
 107       * @param string $par
 108       * @param FormOptions $opts
 109       */
 110  	public function parseParameters( $par, FormOptions $opts ) {
 111          $bits = preg_split( '/\s*,\s*/', trim( $par ) );
 112          foreach ( $bits as $bit ) {
 113              if ( 'hidebots' === $bit ) {
 114                  $opts['hidebots'] = true;
 115              }
 116              if ( 'bots' === $bit ) {
 117                  $opts['hidebots'] = false;
 118              }
 119              if ( 'hideminor' === $bit ) {
 120                  $opts['hideminor'] = true;
 121              }
 122              if ( 'minor' === $bit ) {
 123                  $opts['hideminor'] = false;
 124              }
 125              if ( 'hideliu' === $bit ) {
 126                  $opts['hideliu'] = true;
 127              }
 128              if ( 'hidepatrolled' === $bit ) {
 129                  $opts['hidepatrolled'] = true;
 130              }
 131              if ( 'hideanons' === $bit ) {
 132                  $opts['hideanons'] = true;
 133              }
 134              if ( 'hidemyself' === $bit ) {
 135                  $opts['hidemyself'] = true;
 136              }
 137  
 138              if ( is_numeric( $bit ) ) {
 139                  $opts['limit'] = $bit;
 140              }
 141  
 142              $m = array();
 143              if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
 144                  $opts['limit'] = $m[1];
 145              }
 146              if ( preg_match( '/^days=(\d+)$/', $bit, $m ) ) {
 147                  $opts['days'] = $m[1];
 148              }
 149              if ( preg_match( '/^namespace=(\d+)$/', $bit, $m ) ) {
 150                  $opts['namespace'] = $m[1];
 151              }
 152          }
 153      }
 154  
 155  	public function validateOptions( FormOptions $opts ) {
 156          $opts->validateIntBounds( 'limit', 0, 5000 );
 157          parent::validateOptions( $opts );
 158      }
 159  
 160      /**
 161       * Return an array of conditions depending of options set in $opts
 162       *
 163       * @param FormOptions $opts
 164       * @return array
 165       */
 166  	public function buildMainQueryConds( FormOptions $opts ) {
 167          $dbr = $this->getDB();
 168          $conds = parent::buildMainQueryConds( $opts );
 169  
 170          // Calculate cutoff
 171          $cutoff_unixtime = time() - ( $opts['days'] * 86400 );
 172          $cutoff_unixtime = $cutoff_unixtime - ( $cutoff_unixtime % 86400 );
 173          $cutoff = $dbr->timestamp( $cutoff_unixtime );
 174  
 175          $fromValid = preg_match( '/^[0-9]{14}$/', $opts['from'] );
 176          if ( $fromValid && $opts['from'] > wfTimestamp( TS_MW, $cutoff ) ) {
 177              $cutoff = $dbr->timestamp( $opts['from'] );
 178          } else {
 179              $opts->reset( 'from' );
 180          }
 181  
 182          $conds[] = 'rc_timestamp >= ' . $dbr->addQuotes( $cutoff );
 183  
 184          return $conds;
 185      }
 186  
 187      /**
 188       * Process the query
 189       *
 190       * @param array $conds
 191       * @param FormOptions $opts
 192       * @return bool|ResultWrapper Result or false (for Recentchangeslinked only)
 193       */
 194  	public function doMainQuery( $conds, $opts ) {
 195          $dbr = $this->getDB();
 196          $user = $this->getUser();
 197  
 198          $tables = array( 'recentchanges' );
 199          $fields = RecentChange::selectFields();
 200          $query_options = array();
 201          $join_conds = array();
 202  
 203          // JOIN on watchlist for users
 204          if ( $user->getId() && $user->isAllowed( 'viewmywatchlist' ) ) {
 205              $tables[] = 'watchlist';
 206              $fields[] = 'wl_user';
 207              $fields[] = 'wl_notificationtimestamp';
 208              $join_conds['watchlist'] = array( 'LEFT JOIN', array(
 209                  'wl_user' => $user->getId(),
 210                  'wl_title=rc_title',
 211                  'wl_namespace=rc_namespace'
 212              ) );
 213          }
 214  
 215          if ( $user->isAllowed( 'rollback' ) ) {
 216              $tables[] = 'page';
 217              $fields[] = 'page_latest';
 218              $join_conds['page'] = array( 'LEFT JOIN', 'rc_cur_id=page_id' );
 219          }
 220  
 221          ChangeTags::modifyDisplayQuery(
 222              $tables,
 223              $fields,
 224              $conds,
 225              $join_conds,
 226              $query_options,
 227              $opts['tagfilter']
 228          );
 229  
 230          if ( !$this->runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds,
 231              $opts )
 232          ) {
 233              return false;
 234          }
 235  
 236          // rc_new is not an ENUM, but adding a redundant rc_new IN (0,1) gives mysql enough
 237          // knowledge to use an index merge if it wants (it may use some other index though).
 238          $rows = $dbr->select(
 239              $tables,
 240              $fields,
 241              $conds + array( 'rc_new' => array( 0, 1 ) ),
 242              __METHOD__,
 243              array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $opts['limit'] ) + $query_options,
 244              $join_conds
 245          );
 246  
 247          // Build the final data
 248          if ( $this->getConfig()->get( 'AllowCategorizedRecentChanges' ) ) {
 249              $this->filterByCategories( $rows, $opts );
 250          }
 251  
 252          return $rows;
 253      }
 254  
 255  	protected function runMainQueryHook( &$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts ) {
 256          return parent::runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts )
 257              && wfRunHooks(
 258                  'SpecialRecentChangesQuery',
 259                  array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$fields ),
 260                  '1.23'
 261              );
 262      }
 263  
 264  	public function outputFeedLinks() {
 265          $this->addFeedLinks( $this->getFeedQuery() );
 266      }
 267  
 268      /**
 269       * Get URL query parameters for action=feedrecentchanges API feed of current recent changes view.
 270       *
 271       * @return array
 272       */
 273  	private function getFeedQuery() {
 274          $query = array_filter( $this->getOptions()->getAllValues(), function ( $value ) {
 275              // API handles empty parameters in a different way
 276              return $value !== '';
 277          } );
 278          $query['action'] = 'feedrecentchanges';
 279          $feedLimit = $this->getConfig()->get( 'FeedLimit' );
 280          if ( $query['limit'] > $feedLimit ) {
 281              $query['limit'] = $feedLimit;
 282          }
 283  
 284          return $query;
 285      }
 286  
 287      /**
 288       * Build and output the actual changes list.
 289       *
 290       * @param array $rows Database rows
 291       * @param FormOptions $opts
 292       */
 293  	public function outputChangesList( $rows, $opts ) {
 294          $limit = $opts['limit'];
 295  
 296          $showWatcherCount = $this->getConfig()->get( 'RCShowWatchingUsers' )
 297              && $this->getUser()->getOption( 'shownumberswatching' );
 298          $watcherCache = array();
 299  
 300          $dbr = $this->getDB();
 301  
 302          $counter = 1;
 303          $list = ChangesList::newFromContext( $this->getContext() );
 304          $list->initChangesListRows( $rows );
 305  
 306          $rclistOutput = $list->beginRecentChangesList();
 307          foreach ( $rows as $obj ) {
 308              if ( $limit == 0 ) {
 309                  break;
 310              }
 311              $rc = RecentChange::newFromRow( $obj );
 312              $rc->counter = $counter++;
 313              # Check if the page has been updated since the last visit
 314              if ( $this->getConfig()->get( 'ShowUpdatedMarker' ) && !empty( $obj->wl_notificationtimestamp ) ) {
 315                  $rc->notificationtimestamp = ( $obj->rc_timestamp >= $obj->wl_notificationtimestamp );
 316              } else {
 317                  $rc->notificationtimestamp = false; // Default
 318              }
 319              # Check the number of users watching the page
 320              $rc->numberofWatchingusers = 0; // Default
 321              if ( $showWatcherCount && $obj->rc_namespace >= 0 ) {
 322                  if ( !isset( $watcherCache[$obj->rc_namespace][$obj->rc_title] ) ) {
 323                      $watcherCache[$obj->rc_namespace][$obj->rc_title] =
 324                          $dbr->selectField(
 325                              'watchlist',
 326                              'COUNT(*)',
 327                              array(
 328                                  'wl_namespace' => $obj->rc_namespace,
 329                                  'wl_title' => $obj->rc_title,
 330                              ),
 331                              __METHOD__ . '-watchers'
 332                          );
 333                  }
 334                  $rc->numberofWatchingusers = $watcherCache[$obj->rc_namespace][$obj->rc_title];
 335              }
 336  
 337              $changeLine = $list->recentChangesLine( $rc, !empty( $obj->wl_user ), $counter );
 338              if ( $changeLine !== false ) {
 339                  $rclistOutput .= $changeLine;
 340                  --$limit;
 341              }
 342          }
 343          $rclistOutput .= $list->endRecentChangesList();
 344  
 345          if ( $rows->numRows() === 0 ) {
 346              $this->getOutput()->addHtml(
 347                  '<div class="mw-changeslist-empty">' .
 348                  $this->msg( 'recentchanges-noresult' )->parse() .
 349                  '</div>'
 350              );
 351              if ( !$this->including() ) {
 352                  $this->getOutput()->setStatusCode( 404 );
 353              }
 354          } else {
 355              $this->getOutput()->addHTML( $rclistOutput );
 356          }
 357      }
 358  
 359      /**
 360       * Set the text to be displayed above the changes
 361       *
 362       * @param FormOptions $opts
 363       * @param int $numRows Number of rows in the result to show after this header
 364       */
 365  	public function doHeader( $opts, $numRows ) {
 366          $this->setTopText( $opts );
 367  
 368          $defaults = $opts->getAllValues();
 369          $nondefaults = $opts->getChangedValues();
 370  
 371          $panel = array();
 372          $panel[] = self::makeLegend( $this->getContext() );
 373          $panel[] = $this->optionsPanel( $defaults, $nondefaults, $numRows );
 374          $panel[] = '<hr />';
 375  
 376          $extraOpts = $this->getExtraOptions( $opts );
 377          $extraOptsCount = count( $extraOpts );
 378          $count = 0;
 379          $submit = ' ' . Xml::submitbutton( $this->msg( 'allpagessubmit' )->text() );
 380  
 381          $out = Xml::openElement( 'table', array( 'class' => 'mw-recentchanges-table' ) );
 382          foreach ( $extraOpts as $name => $optionRow ) {
 383              # Add submit button to the last row only
 384              ++$count;
 385              $addSubmit = ( $count === $extraOptsCount ) ? $submit : '';
 386  
 387              $out .= Xml::openElement( 'tr' );
 388              if ( is_array( $optionRow ) ) {
 389                  $out .= Xml::tags(
 390                      'td',
 391                      array( 'class' => 'mw-label mw-' . $name . '-label' ),
 392                      $optionRow[0]
 393                  );
 394                  $out .= Xml::tags(
 395                      'td',
 396                      array( 'class' => 'mw-input' ),
 397                      $optionRow[1] . $addSubmit
 398                  );
 399              } else {
 400                  $out .= Xml::tags(
 401                      'td',
 402                      array( 'class' => 'mw-input', 'colspan' => 2 ),
 403                      $optionRow . $addSubmit
 404                  );
 405              }
 406              $out .= Xml::closeElement( 'tr' );
 407          }
 408          $out .= Xml::closeElement( 'table' );
 409  
 410          $unconsumed = $opts->getUnconsumedValues();
 411          foreach ( $unconsumed as $key => $value ) {
 412              $out .= Html::hidden( $key, $value );
 413          }
 414  
 415          $t = $this->getPageTitle();
 416          $out .= Html::hidden( 'title', $t->getPrefixedText() );
 417          $form = Xml::tags( 'form', array( 'action' => wfScript() ), $out );
 418          $panel[] = $form;
 419          $panelString = implode( "\n", $panel );
 420  
 421          $this->getOutput()->addHTML(
 422              Xml::fieldset(
 423                  $this->msg( 'recentchanges-legend' )->text(),
 424                  $panelString,
 425                  array( 'class' => 'rcoptions' )
 426              )
 427          );
 428  
 429          $this->setBottomText( $opts );
 430      }
 431  
 432      /**
 433       * Send the text to be displayed above the options
 434       *
 435       * @param FormOptions $opts Unused
 436       */
 437  	function setTopText( FormOptions $opts ) {
 438          global $wgContLang;
 439  
 440          $message = $this->msg( 'recentchangestext' )->inContentLanguage();
 441          if ( !$message->isDisabled() ) {
 442              $this->getOutput()->addWikiText(
 443                  Html::rawElement( 'p',
 444                      array( 'lang' => $wgContLang->getCode(), 'dir' => $wgContLang->getDir() ),
 445                      "\n" . $message->plain() . "\n"
 446                  ),
 447                  /* $lineStart */ false,
 448                  /* $interface */ false
 449              );
 450          }
 451      }
 452  
 453      /**
 454       * Get options to be displayed in a form
 455       *
 456       * @param FormOptions $opts
 457       * @return array
 458       */
 459  	function getExtraOptions( $opts ) {
 460          $opts->consumeValues( array(
 461              'namespace', 'invert', 'associated', 'tagfilter', 'categories', 'categories_any'
 462          ) );
 463  
 464          $extraOpts = array();
 465          $extraOpts['namespace'] = $this->namespaceFilterForm( $opts );
 466  
 467          if ( $this->getConfig()->get( 'AllowCategorizedRecentChanges' ) ) {
 468              $extraOpts['category'] = $this->categoryFilterForm( $opts );
 469          }
 470  
 471          $tagFilter = ChangeTags::buildTagFilterSelector( $opts['tagfilter'] );
 472          if ( count( $tagFilter ) ) {
 473              $extraOpts['tagfilter'] = $tagFilter;
 474          }
 475  
 476          // Don't fire the hook for subclasses. (Or should we?)
 477          if ( $this->getName() === 'Recentchanges' ) {
 478              wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
 479          }
 480  
 481          return $extraOpts;
 482      }
 483  
 484      /**
 485       * Add page-specific modules.
 486       */
 487  	protected function addModules() {
 488          parent::addModules();
 489          $out = $this->getOutput();
 490          $out->addModules( 'mediawiki.special.recentchanges' );
 491      }
 492  
 493      /**
 494       * Get last modified date, for client caching
 495       * Don't use this if we are using the patrol feature, patrol changes don't
 496       * update the timestamp
 497       *
 498       * @return string|bool
 499       */
 500  	public function checkLastModified() {
 501          $dbr = $this->getDB();
 502          $lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, __METHOD__ );
 503  
 504          return $lastmod;
 505      }
 506  
 507      /**
 508       * Creates the choose namespace selection
 509       *
 510       * @param FormOptions $opts
 511       * @return string
 512       */
 513  	protected function namespaceFilterForm( FormOptions $opts ) {
 514          $nsSelect = Html::namespaceSelector(
 515              array( 'selected' => $opts['namespace'], 'all' => '' ),
 516              array( 'name' => 'namespace', 'id' => 'namespace' )
 517          );
 518          $nsLabel = Xml::label( $this->msg( 'namespace' )->text(), 'namespace' );
 519          $invert = Xml::checkLabel(
 520              $this->msg( 'invert' )->text(), 'invert', 'nsinvert',
 521              $opts['invert'],
 522              array( 'title' => $this->msg( 'tooltip-invert' )->text() )
 523          );
 524          $associated = Xml::checkLabel(
 525              $this->msg( 'namespace_association' )->text(), 'associated', 'nsassociated',
 526              $opts['associated'],
 527              array( 'title' => $this->msg( 'tooltip-namespace_association' )->text() )
 528          );
 529  
 530          return array( $nsLabel, "$nsSelect $invert $associated" );
 531      }
 532  
 533      /**
 534       * Create an input to filter changes by categories
 535       *
 536       * @param FormOptions $opts
 537       * @return array
 538       */
 539  	protected function categoryFilterForm( FormOptions $opts ) {
 540          list( $label, $input ) = Xml::inputLabelSep( $this->msg( 'rc_categories' )->text(),
 541              'categories', 'mw-categories', false, $opts['categories'] );
 542  
 543          $input .= ' ' . Xml::checkLabel( $this->msg( 'rc_categories_any' )->text(),
 544              'categories_any', 'mw-categories_any', $opts['categories_any'] );
 545  
 546          return array( $label, $input );
 547      }
 548  
 549      /**
 550       * Filter $rows by categories set in $opts
 551       *
 552       * @param ResultWrapper $rows Database rows
 553       * @param FormOptions $opts
 554       */
 555  	function filterByCategories( &$rows, FormOptions $opts ) {
 556          $categories = array_map( 'trim', explode( '|', $opts['categories'] ) );
 557  
 558          if ( !count( $categories ) ) {
 559              return;
 560          }
 561  
 562          # Filter categories
 563          $cats = array();
 564          foreach ( $categories as $cat ) {
 565              $cat = trim( $cat );
 566              if ( $cat == '' ) {
 567                  continue;
 568              }
 569              $cats[] = $cat;
 570          }
 571  
 572          # Filter articles
 573          $articles = array();
 574          $a2r = array();
 575          $rowsarr = array();
 576          foreach ( $rows as $k => $r ) {
 577              $nt = Title::makeTitle( $r->rc_namespace, $r->rc_title );
 578              $id = $nt->getArticleID();
 579              if ( $id == 0 ) {
 580                  continue; # Page might have been deleted...
 581              }
 582              if ( !in_array( $id, $articles ) ) {
 583                  $articles[] = $id;
 584              }
 585              if ( !isset( $a2r[$id] ) ) {
 586                  $a2r[$id] = array();
 587              }
 588              $a2r[$id][] = $k;
 589              $rowsarr[$k] = $r;
 590          }
 591  
 592          # Shortcut?
 593          if ( !count( $articles ) || !count( $cats ) ) {
 594              return;
 595          }
 596  
 597          # Look up
 598          $catFind = new CategoryFinder;
 599          $catFind->seed( $articles, $cats, $opts['categories_any'] ? 'OR' : 'AND' );
 600          $match = $catFind->run();
 601  
 602          # Filter
 603          $newrows = array();
 604          foreach ( $match as $id ) {
 605              foreach ( $a2r[$id] as $rev ) {
 606                  $k = $rev;
 607                  $newrows[$k] = $rowsarr[$k];
 608              }
 609          }
 610          $rows = $newrows;
 611      }
 612  
 613      /**
 614       * Makes change an option link which carries all the other options
 615       *
 616       * @param string $title Title
 617       * @param array $override Options to override
 618       * @param array $options Current options
 619       * @param bool $active Whether to show the link in bold
 620       * @return string
 621       */
 622  	function makeOptionsLink( $title, $override, $options, $active = false ) {
 623          $params = $override + $options;
 624  
 625          // Bug 36524: false values have be converted to "0" otherwise
 626          // wfArrayToCgi() will omit it them.
 627          foreach ( $params as &$value ) {
 628              if ( $value === false ) {
 629                  $value = '0';
 630              }
 631          }
 632          unset( $value );
 633  
 634          $text = htmlspecialchars( $title );
 635          if ( $active ) {
 636              $text = '<strong>' . $text . '</strong>';
 637          }
 638  
 639          return Linker::linkKnown( $this->getPageTitle(), $text, array(), $params );
 640      }
 641  
 642      /**
 643       * Creates the options panel.
 644       *
 645       * @param array $defaults
 646       * @param array $nondefaults
 647       * @param int $numRows Number of rows in the result to show after this header
 648       * @return string
 649       */
 650  	function optionsPanel( $defaults, $nondefaults, $numRows ) {
 651          $options = $nondefaults + $defaults;
 652  
 653          $note = '';
 654          $msg = $this->msg( 'rclegend' );
 655          if ( !$msg->isDisabled() ) {
 656              $note .= '<div class="mw-rclegend">' . $msg->parse() . "</div>\n";
 657          }
 658  
 659          $lang = $this->getLanguage();
 660          $user = $this->getUser();
 661          if ( $options['from'] ) {
 662              $note .= $this->msg( 'rcnotefrom' )
 663                  ->numParams( $options['limit'] )
 664                  ->params(
 665                      $lang->userTimeAndDate( $options['from'], $user ),
 666                      $lang->userDate( $options['from'], $user ),
 667                      $lang->userTime( $options['from'], $user )
 668                  )
 669                  ->numParams( $numRows )
 670                  ->parse() . '<br />';
 671          }
 672  
 673          # Sort data for display and make sure it's unique after we've added user data.
 674          $linkLimits = $this->getConfig()->get( 'RCLinkLimits' );
 675          $linkLimits[] = $options['limit'];
 676          sort( $linkLimits );
 677          $linkLimits = array_unique( $linkLimits );
 678  
 679          $linkDays = $this->getConfig()->get( 'RCLinkDays' );
 680          $linkDays[] = $options['days'];
 681          sort( $linkDays );
 682          $linkDays = array_unique( $linkDays );
 683  
 684          // limit links
 685          $cl = array();
 686          foreach ( $linkLimits as $value ) {
 687              $cl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
 688                  array( 'limit' => $value ), $nondefaults, $value == $options['limit'] );
 689          }
 690          $cl = $lang->pipeList( $cl );
 691  
 692          // day links, reset 'from' to none
 693          $dl = array();
 694          foreach ( $linkDays as $value ) {
 695              $dl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
 696                  array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] );
 697          }
 698          $dl = $lang->pipeList( $dl );
 699  
 700          // show/hide links
 701          $filters = array(
 702              'hideminor' => 'rcshowhideminor',
 703              'hidebots' => 'rcshowhidebots',
 704              'hideanons' => 'rcshowhideanons',
 705              'hideliu' => 'rcshowhideliu',
 706              'hidepatrolled' => 'rcshowhidepatr',
 707              'hidemyself' => 'rcshowhidemine'
 708          );
 709  
 710          $showhide = array( 'show', 'hide' );
 711  
 712          foreach ( $this->getCustomFilters() as $key => $params ) {
 713              $filters[$key] = $params['msg'];
 714          }
 715          // Disable some if needed
 716          if ( !$user->useRCPatrol() ) {
 717              unset( $filters['hidepatrolled'] );
 718          }
 719  
 720          $links = array();
 721          foreach ( $filters as $key => $msg ) {
 722              // The following messages are used here:
 723              // rcshowhideminor-show, rcshowhideminor-hide, rcshowhidebots-show, rcshowhidebots-hide,
 724              // rcshowhideanons-show, rcshowhideanons-hide, rcshowhideliu-show, rcshowhideliu-hide,
 725              // rcshowhidepatr-show, rcshowhidepatr-hide, rcshowhidemine-show, rcshowhidemine-hide.
 726              $linkMessage = $this->msg( $msg . '-' . $showhide[1 - $options[$key]] );
 727              // Extensions can define additional filters, but don't need to define the corresponding
 728              // messages. If they don't exist, just fall back to 'show' and 'hide'.
 729              if ( !$linkMessage->exists() ) {
 730                  $linkMessage = $this->msg( $showhide[1 - $options[$key]] );
 731              }
 732  
 733              $link = $this->makeOptionsLink( $linkMessage->text(),
 734                  array( $key => 1 - $options[$key] ), $nondefaults );
 735              $links[] = "<span class=\"$msg rcshowhideoption\">" . $this->msg( $msg )->rawParams( $link )->escaped() . '</span>';
 736          }
 737  
 738          // show from this onward link
 739          $timestamp = wfTimestampNow();
 740          $now = $lang->userTimeAndDate( $timestamp, $user );
 741          $timenow = $lang->userTime( $timestamp, $user );
 742          $datenow = $lang->userDate( $timestamp, $user );
 743          $pipedLinks = '<span class="rcshowhide">' . $lang->pipeList( $links ) . '</span>';
 744  
 745          $rclinks = '<span class="rclinks">' . $this->msg( 'rclinks' )->rawParams( $cl, $dl, $pipedLinks )
 746              ->parse() . '</span>';
 747  
 748          $rclistfrom = '<span class="rclistfrom">' . $this->makeOptionsLink(
 749              $this->msg( 'rclistfrom' )->rawParams( $now, $timenow, $datenow )->parse(),
 750              array( 'from' => $timestamp ),
 751              $nondefaults
 752          ) . '</span>';
 753  
 754          return "{$note}$rclinks<br />$rclistfrom";
 755      }
 756  
 757  	public function isIncludable() {
 758          return true;
 759      }
 760  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1