2004-02-18 02:15:00 +00:00
|
|
|
<?php
|
2010-06-21 12:59:04 +00:00
|
|
|
/**
|
2010-08-15 07:16:58 +00:00
|
|
|
* Implements Special:Recentchanges
|
2010-06-21 12:59:04 +00:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
2010-06-21 13:16:32 +00:00
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2010-06-21 12:59:04 +00:00
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
2010-08-15 07:16:58 +00:00
|
|
|
*
|
|
|
|
|
* @file
|
|
|
|
|
* @ingroup SpecialPage
|
2010-06-21 12:59:04 +00:00
|
|
|
*/
|
2008-06-26 19:12:52 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2010-08-15 07:16:58 +00:00
|
|
|
* A special page that lists last changes made to the wiki
|
|
|
|
|
*
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @ingroup SpecialPage
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2010-07-17 19:04:07 +00:00
|
|
|
class SpecialRecentChanges extends IncludableSpecialPage {
|
2010-02-10 04:13:43 +00:00
|
|
|
var $rcOptions, $rcSubpage;
|
2011-05-23 04:28:58 +00:00
|
|
|
protected $customFilters;
|
2010-02-10 04:13:43 +00:00
|
|
|
|
2010-07-17 19:04:07 +00:00
|
|
|
public function __construct( $name = 'Recentchanges' ) {
|
|
|
|
|
parent::__construct( $name );
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Get a FormOptions object containing the default options
|
|
|
|
|
*
|
|
|
|
|
* @return FormOptions
|
|
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function getDefaultOptions() {
|
|
|
|
|
$opts = new FormOptions();
|
|
|
|
|
|
2011-04-03 05:46:42 +00:00
|
|
|
$opts->add( 'days', (int)$this->getUser()->getOption( 'rcdays' ) );
|
|
|
|
|
$opts->add( 'limit', (int)$this->getUser()->getOption( 'rclimit' ) );
|
2008-06-17 08:24:00 +00:00
|
|
|
$opts->add( 'from', '' );
|
|
|
|
|
|
2011-04-03 05:46:42 +00:00
|
|
|
$opts->add( 'hideminor', $this->getUser()->getBoolOption( 'hideminor' ) );
|
2009-04-19 21:03:30 +00:00
|
|
|
$opts->add( 'hidebots', true );
|
2008-06-17 08:24:00 +00:00
|
|
|
$opts->add( 'hideanons', false );
|
|
|
|
|
$opts->add( 'hideliu', false );
|
2011-04-03 05:46:42 +00:00
|
|
|
$opts->add( 'hidepatrolled', $this->getUser()->getBoolOption( 'hidepatrolled' ) );
|
2009-04-19 21:03:30 +00:00
|
|
|
$opts->add( 'hidemyself', false );
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
$opts->add( 'namespace', '', FormOptions::INTNULL );
|
|
|
|
|
$opts->add( 'invert', false );
|
2011-03-02 20:40:40 +00:00
|
|
|
$opts->add( 'associated', false );
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
$opts->add( 'categories', '' );
|
|
|
|
|
$opts->add( 'categories_any', false );
|
2009-01-28 19:08:18 +00:00
|
|
|
$opts->add( 'tagfilter', '' );
|
2008-06-17 08:24:00 +00:00
|
|
|
return $opts;
|
2008-06-26 19:12:52 +00:00
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
2010-02-10 04:13:43 +00:00
|
|
|
* Create a FormOptions object with options as specified by the user
|
2008-06-26 19:12:52 +00:00
|
|
|
*
|
2011-05-29 14:25:20 +00:00
|
|
|
* @param $parameters array
|
|
|
|
|
*
|
2008-06-26 19:12:52 +00:00
|
|
|
* @return FormOptions
|
|
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function setup( $parameters ) {
|
|
|
|
|
$opts = $this->getDefaultOptions();
|
2011-05-23 04:28:58 +00:00
|
|
|
|
2012-01-13 09:14:56 +00:00
|
|
|
foreach( $this->getCustomFilters() as $key => $params ) {
|
2011-05-23 04:28:58 +00:00
|
|
|
$opts->add( $key, $params['default'] );
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-17 09:25:50 +00:00
|
|
|
$opts->fetchValuesFromRequest( $this->getRequest() );
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
// Give precedence to subpage syntax
|
2008-11-28 23:06:25 +00:00
|
|
|
if( $parameters !== null ) {
|
2008-06-17 10:44:12 +00:00
|
|
|
$this->parseParameters( $parameters, $opts );
|
2004-12-12 04:13:19 +00:00
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2009-09-14 21:26:04 +00:00
|
|
|
$opts->validateIntBounds( 'limit', 0, 5000 );
|
2008-06-17 08:24:00 +00:00
|
|
|
return $opts;
|
2003-07-02 06:22:03 +00:00
|
|
|
}
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2012-01-13 09:14:56 +00:00
|
|
|
/**
|
|
|
|
|
* Get custom show/hide filters
|
|
|
|
|
*
|
|
|
|
|
* @return Array Map of filter URL param names to properties (msg/default)
|
|
|
|
|
*/
|
|
|
|
|
protected function getCustomFilters() {
|
|
|
|
|
if ( $this->customFilters === null ) {
|
|
|
|
|
$this->customFilters = array();
|
|
|
|
|
wfRunHooks( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ) );
|
|
|
|
|
}
|
|
|
|
|
return $this->customFilters;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
2010-02-10 04:13:43 +00:00
|
|
|
* Create a FormOptions object specific for feed requests and return it
|
2008-06-26 19:12:52 +00:00
|
|
|
*
|
|
|
|
|
* @return FormOptions
|
|
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function feedSetup() {
|
2011-07-17 09:25:50 +00:00
|
|
|
global $wgFeedLimit;
|
2008-06-17 08:24:00 +00:00
|
|
|
$opts = $this->getDefaultOptions();
|
2009-12-17 15:42:17 +00:00
|
|
|
# Feed is cached on limit,hideminor,namespace; other params would randomly not work
|
2011-07-17 09:25:50 +00:00
|
|
|
$opts->fetchValuesFromRequest( $this->getRequest(), array( 'limit', 'hideminor', 'namespace' ) );
|
2008-06-17 08:24:00 +00:00
|
|
|
$opts->validateIntBounds( 'limit', 0, $wgFeedLimit );
|
|
|
|
|
return $opts;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-10 04:13:43 +00:00
|
|
|
/**
|
|
|
|
|
* Get the current FormOptions for this request
|
|
|
|
|
*/
|
|
|
|
|
public function getOptions() {
|
|
|
|
|
if ( $this->rcOptions === null ) {
|
2011-07-10 07:33:29 +00:00
|
|
|
if ( $this->including() ) {
|
|
|
|
|
$isFeed = false;
|
|
|
|
|
} else {
|
2011-07-17 09:25:50 +00:00
|
|
|
$isFeed = (bool)$this->getRequest()->getVal( 'feed' );
|
2011-07-10 07:33:29 +00:00
|
|
|
}
|
|
|
|
|
$this->rcOptions = $isFeed ? $this->feedSetup() : $this->setup( $this->rcSubpage );
|
2010-02-10 04:13:43 +00:00
|
|
|
}
|
|
|
|
|
return $this->rcOptions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Main execution point
|
|
|
|
|
*
|
2010-07-03 21:09:25 +00:00
|
|
|
* @param $subpage String
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
2010-02-10 04:13:43 +00:00
|
|
|
public function execute( $subpage ) {
|
|
|
|
|
$this->rcSubpage = $subpage;
|
2011-07-17 09:25:50 +00:00
|
|
|
$feedFormat = $this->including() ? null : $this->getRequest()->getVal( 'feed' );
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
# 10 seconds server-side caching max
|
2011-07-17 09:25:50 +00:00
|
|
|
$this->getOutput()->setSquidMaxage( 10 );
|
2008-12-20 08:36:14 +00:00
|
|
|
# Check if the client has a cached version
|
2008-06-17 08:24:00 +00:00
|
|
|
$lastmod = $this->checkLastModified( $feedFormat );
|
2008-12-20 08:36:14 +00:00
|
|
|
if( $lastmod === false ) {
|
2008-06-17 08:24:00 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-10 04:13:43 +00:00
|
|
|
$opts = $this->getOptions();
|
2008-06-17 08:24:00 +00:00
|
|
|
$this->setHeaders();
|
2008-06-26 19:12:52 +00:00
|
|
|
$this->outputHeader();
|
2011-06-28 06:40:49 +00:00
|
|
|
$this->addRecentChangesJS();
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
// Fetch results, prepare a batch link existence check query
|
|
|
|
|
$conds = $this->buildMainQueryConds( $opts );
|
2008-07-27 18:14:59 +00:00
|
|
|
$rows = $this->doMainQuery( $conds, $opts );
|
|
|
|
|
if( $rows === false ){
|
2008-10-08 21:30:21 +00:00
|
|
|
if( !$this->including() ) {
|
|
|
|
|
$this->doHeader( $opts );
|
|
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2008-07-26 15:51:49 +00:00
|
|
|
|
2008-12-20 08:36:14 +00:00
|
|
|
if( !$feedFormat ) {
|
|
|
|
|
$batch = new LinkBatch;
|
|
|
|
|
foreach( $rows as $row ) {
|
2011-05-09 22:57:44 +00:00
|
|
|
$batch->add( NS_USER, $row->rc_user_text );
|
|
|
|
|
$batch->add( NS_USER_TALK, $row->rc_user_text );
|
2009-01-29 01:22:43 +00:00
|
|
|
$batch->add( $row->rc_namespace, $row->rc_title );
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
2008-12-20 08:36:14 +00:00
|
|
|
$batch->execute();
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
2008-11-28 23:06:25 +00:00
|
|
|
if( $feedFormat ) {
|
2010-02-10 04:13:43 +00:00
|
|
|
list( $changesFeed, $formatter ) = $this->getFeedObject( $feedFormat );
|
|
|
|
|
$changesFeed->execute( $formatter, $rows, $lastmod, $opts );
|
2008-06-17 08:24:00 +00:00
|
|
|
} else {
|
|
|
|
|
$this->webOutput( $rows, $opts );
|
|
|
|
|
}
|
2008-07-27 18:14:59 +00:00
|
|
|
|
|
|
|
|
$rows->free();
|
2005-05-04 21:56:14 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Return an array with a ChangesFeed object and ChannelFeed object
|
|
|
|
|
*
|
2010-07-03 21:09:25 +00:00
|
|
|
* @return Array
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
|
|
|
|
public function getFeedObject( $feedFormat ){
|
2010-02-10 04:13:43 +00:00
|
|
|
$changesFeed = new ChangesFeed( $feedFormat, 'rcfeed' );
|
|
|
|
|
$formatter = $changesFeed->getFeedObject(
|
2012-04-28 18:20:11 +00:00
|
|
|
$this->msg( 'recentchanges' )->inContentLanguage()->text(),
|
|
|
|
|
$this->msg( 'recentchanges-feed-description' )->inContentLanguage()->text(),
|
2011-05-09 22:57:44 +00:00
|
|
|
$this->getTitle()->getFullURL()
|
2008-06-26 19:12:52 +00:00
|
|
|
);
|
2010-02-10 04:13:43 +00:00
|
|
|
return array( $changesFeed, $formatter );
|
2008-06-26 19:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Process $par and put options found if $opts
|
|
|
|
|
* Mainly used when including the page
|
|
|
|
|
*
|
|
|
|
|
* @param $par String
|
|
|
|
|
* @param $opts FormOptions
|
|
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function parseParameters( $par, FormOptions $opts ) {
|
|
|
|
|
$bits = preg_split( '/\s*,\s*/', trim( $par ) );
|
2008-11-28 23:06:25 +00:00
|
|
|
foreach( $bits as $bit ) {
|
2011-05-09 22:57:44 +00:00
|
|
|
if( 'hidebots' === $bit ) {
|
|
|
|
|
$opts['hidebots'] = true;
|
|
|
|
|
}
|
|
|
|
|
if( 'bots' === $bit ) {
|
|
|
|
|
$opts['hidebots'] = false;
|
|
|
|
|
}
|
|
|
|
|
if( 'hideminor' === $bit ) {
|
|
|
|
|
$opts['hideminor'] = true;
|
|
|
|
|
}
|
|
|
|
|
if( 'minor' === $bit ) {
|
|
|
|
|
$opts['hideminor'] = false;
|
|
|
|
|
}
|
|
|
|
|
if( 'hideliu' === $bit ) {
|
|
|
|
|
$opts['hideliu'] = true;
|
|
|
|
|
}
|
|
|
|
|
if( 'hidepatrolled' === $bit ) {
|
|
|
|
|
$opts['hidepatrolled'] = true;
|
|
|
|
|
}
|
|
|
|
|
if( 'hideanons' === $bit ) {
|
|
|
|
|
$opts['hideanons'] = true;
|
|
|
|
|
}
|
|
|
|
|
if( 'hidemyself' === $bit ) {
|
|
|
|
|
$opts['hidemyself'] = true;
|
|
|
|
|
}
|
2008-11-28 23:06:25 +00:00
|
|
|
|
2011-05-09 22:57:44 +00:00
|
|
|
if( is_numeric( $bit ) ) {
|
|
|
|
|
$opts['limit'] = $bit;
|
|
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
$m = array();
|
2011-05-09 22:57:44 +00:00
|
|
|
if( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
|
|
|
|
|
$opts['limit'] = $m[1];
|
|
|
|
|
}
|
|
|
|
|
if( preg_match( '/^days=(\d+)$/', $bit, $m ) ) {
|
|
|
|
|
$opts['days'] = $m[1];
|
|
|
|
|
}
|
2011-10-01 18:20:31 +00:00
|
|
|
if( preg_match( '/^namespace=(\d+)$/', $bit, $m ) ) {
|
|
|
|
|
$opts['namespace'] = $m[1];
|
|
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
2004-11-18 11:37:14 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Get last modified date, for client caching
|
|
|
|
|
* Don't use this if we are using the patrol feature, patrol changes don't
|
|
|
|
|
* update the timestamp
|
|
|
|
|
*
|
|
|
|
|
* @param $feedFormat String
|
2010-07-03 21:09:25 +00:00
|
|
|
* @return String or false
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function checkLastModified( $feedFormat ) {
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2009-05-11 15:32:51 +00:00
|
|
|
$lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, __METHOD__ );
|
2011-04-03 05:46:42 +00:00
|
|
|
if( $feedFormat || !$this->getUser()->useRCPatrol() ) {
|
|
|
|
|
if( $lastmod && $this->getOutput()->checkLastModified( $lastmod ) ) {
|
2008-06-17 08:24:00 +00:00
|
|
|
# Client cache fresh and headers sent, nothing more to do.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2004-11-18 11:37:14 +00:00
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
return $lastmod;
|
2003-12-11 20:16:34 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Return an array of conditions depending of options set in $opts
|
|
|
|
|
*
|
|
|
|
|
* @param $opts FormOptions
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function buildMainQueryConds( FormOptions $opts ) {
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$conds = array();
|
|
|
|
|
|
|
|
|
|
# It makes no sense to hide both anons and logged-in users
|
|
|
|
|
# Where this occurs, force anons to be shown
|
|
|
|
|
$forcebot = false;
|
|
|
|
|
if( $opts['hideanons'] && $opts['hideliu'] ){
|
|
|
|
|
# Check if the user wants to show bots only
|
|
|
|
|
if( $opts['hidebots'] ){
|
|
|
|
|
$opts['hideanons'] = false;
|
|
|
|
|
} else {
|
|
|
|
|
$forcebot = true;
|
|
|
|
|
$opts['hidebots'] = false;
|
|
|
|
|
}
|
2008-04-02 10:47:50 +00:00
|
|
|
}
|
2006-04-03 01:32:35 +00:00
|
|
|
|
2008-06-17 08:24:00 +00:00
|
|
|
// Calculate cutoff
|
|
|
|
|
$cutoff_unixtime = time() - ( $opts['days'] * 86400 );
|
|
|
|
|
$cutoff_unixtime = $cutoff_unixtime - ($cutoff_unixtime % 86400);
|
|
|
|
|
$cutoff = $dbr->timestamp( $cutoff_unixtime );
|
2008-04-02 10:47:50 +00:00
|
|
|
|
2008-06-17 08:24:00 +00:00
|
|
|
$fromValid = preg_match('/^[0-9]{14}$/', $opts['from']);
|
|
|
|
|
if( $fromValid && $opts['from'] > wfTimestamp(TS_MW,$cutoff) ) {
|
|
|
|
|
$cutoff = $dbr->timestamp($opts['from']);
|
2006-02-11 12:28:50 +00:00
|
|
|
} else {
|
2008-06-17 08:24:00 +00:00
|
|
|
$opts->reset( 'from' );
|
2006-02-11 12:28:50 +00:00
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
$conds[] = 'rc_timestamp >= ' . $dbr->addQuotes( $cutoff );
|
|
|
|
|
|
2011-04-03 05:46:42 +00:00
|
|
|
$hidePatrol = $this->getUser()->useRCPatrol() && $opts['hidepatrolled'];
|
2008-06-17 08:24:00 +00:00
|
|
|
$hideLoggedInUsers = $opts['hideliu'] && !$forcebot;
|
|
|
|
|
$hideAnonymousUsers = $opts['hideanons'] && !$forcebot;
|
|
|
|
|
|
2011-05-09 22:57:44 +00:00
|
|
|
if( $opts['hideminor'] ) {
|
|
|
|
|
$conds['rc_minor'] = 0;
|
|
|
|
|
}
|
|
|
|
|
if( $opts['hidebots'] ) {
|
|
|
|
|
$conds['rc_bot'] = 0;
|
|
|
|
|
}
|
|
|
|
|
if( $hidePatrol ) {
|
|
|
|
|
$conds['rc_patrolled'] = 0;
|
|
|
|
|
}
|
|
|
|
|
if( $forcebot ) {
|
|
|
|
|
$conds['rc_bot'] = 1;
|
|
|
|
|
}
|
|
|
|
|
if( $hideLoggedInUsers ) {
|
|
|
|
|
$conds[] = 'rc_user = 0';
|
|
|
|
|
}
|
|
|
|
|
if( $hideAnonymousUsers ) {
|
|
|
|
|
$conds[] = 'rc_user != 0';
|
|
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
if( $opts['hidemyself'] ) {
|
2011-04-03 05:46:42 +00:00
|
|
|
if( $this->getUser()->getId() ) {
|
|
|
|
|
$conds[] = 'rc_user != ' . $dbr->addQuotes( $this->getUser()->getId() );
|
2008-06-17 08:24:00 +00:00
|
|
|
} else {
|
2011-04-03 05:46:42 +00:00
|
|
|
$conds[] = 'rc_user_text != ' . $dbr->addQuotes( $this->getUser()->getName() );
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
|
2008-06-17 08:24:00 +00:00
|
|
|
# Namespace filtering
|
2008-11-28 23:06:25 +00:00
|
|
|
if( $opts['namespace'] !== '' ) {
|
2011-09-13 00:19:04 +00:00
|
|
|
$selectedNS = $dbr->addQuotes( $opts['namespace'] );
|
|
|
|
|
$operator = $opts['invert'] ? '!=' : '=';
|
|
|
|
|
$boolean = $opts['invert'] ? 'AND' : 'OR';
|
2011-03-02 20:40:40 +00:00
|
|
|
|
2011-09-13 00:19:04 +00:00
|
|
|
# namespace association (bug 2429)
|
|
|
|
|
if( !$opts['associated'] ) {
|
|
|
|
|
$condition = "rc_namespace $operator $selectedNS";
|
|
|
|
|
} else {
|
|
|
|
|
# Also add the associated namespace
|
|
|
|
|
$associatedNS = $dbr->addQuotes(
|
|
|
|
|
MWNamespace::getAssociated( $opts['namespace'] )
|
|
|
|
|
);
|
|
|
|
|
$condition = "(rc_namespace $operator $selectedNS "
|
|
|
|
|
. $boolean
|
|
|
|
|
. " rc_namespace $operator $associatedNS)";
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-02 20:40:40 +00:00
|
|
|
$conds[] = $condition;
|
|
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
return $conds;
|
2006-02-11 12:28:50 +00:00
|
|
|
}
|
2006-04-03 01:32:35 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Process the query
|
|
|
|
|
*
|
2010-07-03 21:09:25 +00:00
|
|
|
* @param $conds Array
|
2008-06-26 19:12:52 +00:00
|
|
|
* @param $opts FormOptions
|
2012-02-09 18:01:10 +00:00
|
|
|
* @return bool|ResultWrapper result or false (for Recentchangeslinked only)
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function doMainQuery( $conds, $opts ) {
|
2008-09-16 05:56:43 +00:00
|
|
|
$tables = array( 'recentchanges' );
|
|
|
|
|
$join_conds = array();
|
2011-05-09 22:57:44 +00:00
|
|
|
$query_options = array(
|
|
|
|
|
'USE INDEX' => array( 'recentchanges' => 'rc_timestamp' )
|
|
|
|
|
);
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2011-04-03 05:46:42 +00:00
|
|
|
$uid = $this->getUser()->getId();
|
2008-06-17 08:24:00 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$limit = $opts['limit'];
|
|
|
|
|
$namespace = $opts['namespace'];
|
|
|
|
|
$invert = $opts['invert'];
|
2011-06-26 23:32:46 +00:00
|
|
|
$associated = $opts['associated'];
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2011-04-19 20:39:08 +00:00
|
|
|
$fields = array( $dbr->tableName( 'recentchanges' ) . '.*' ); // all rc columns
|
2008-06-17 08:24:00 +00:00
|
|
|
// JOIN on watchlist for users
|
2011-04-19 20:39:08 +00:00
|
|
|
if ( $uid ) {
|
2008-06-17 08:24:00 +00:00
|
|
|
$tables[] = 'watchlist';
|
2011-04-19 20:39:08 +00:00
|
|
|
$fields[] = 'wl_user';
|
|
|
|
|
$fields[] = 'wl_notificationtimestamp';
|
2009-01-28 19:08:18 +00:00
|
|
|
$join_conds['watchlist'] = array('LEFT JOIN',
|
|
|
|
|
"wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace");
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
2011-04-19 20:39:08 +00:00
|
|
|
if ( $this->getUser()->isAllowed( 'rollback' ) ) {
|
2009-03-29 11:02:16 +00:00
|
|
|
$tables[] = 'page';
|
2011-04-19 20:39:08 +00:00
|
|
|
$fields[] = 'page_latest';
|
2009-03-29 11:14:08 +00:00
|
|
|
$join_conds['page'] = array('LEFT JOIN', 'rc_cur_id=page_id');
|
2009-03-29 11:02:16 +00:00
|
|
|
}
|
2010-07-23 22:37:52 +00:00
|
|
|
if ( !$this->including() ) {
|
|
|
|
|
// Tag stuff.
|
|
|
|
|
// Doesn't work when transcluding. See bug 23293
|
|
|
|
|
ChangeTags::modifyDisplayQuery(
|
2012-01-13 21:57:52 +00:00
|
|
|
$tables, $fields, $conds, $join_conds, $query_options,
|
|
|
|
|
$opts['tagfilter']
|
2010-07-23 22:37:52 +00:00
|
|
|
);
|
|
|
|
|
}
|
2009-01-28 19:08:18 +00:00
|
|
|
|
2011-04-19 20:39:08 +00:00
|
|
|
if ( !wfRunHooks( 'SpecialRecentChangesQuery',
|
|
|
|
|
array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$fields ) ) )
|
|
|
|
|
{
|
2010-01-29 17:27:30 +00:00
|
|
|
return false;
|
2011-04-19 20:39:08 +00:00
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2010-01-28 08:57:34 +00:00
|
|
|
// Don't use the new_namespace_time timestamp index if:
|
|
|
|
|
// (a) "All namespaces" selected
|
2011-06-26 23:32:46 +00:00
|
|
|
// (b) We want pages in more than one namespace (inverted/associated)
|
2010-01-28 08:57:34 +00:00
|
|
|
// (c) There is a tag to filter on (use tag index instead)
|
|
|
|
|
// (d) UNION + sort/limit is not an option for the DBMS
|
2011-06-26 23:32:46 +00:00
|
|
|
if( $namespace === ''
|
|
|
|
|
|| ( $invert || $associated )
|
2010-01-28 08:57:34 +00:00
|
|
|
|| $opts['tagfilter'] != ''
|
2009-10-17 12:23:23 +00:00
|
|
|
|| !$dbr->unionSupportsOrderAndLimit() )
|
|
|
|
|
{
|
2011-04-19 20:39:08 +00:00
|
|
|
$res = $dbr->select( $tables, $fields, $conds, __METHOD__,
|
2009-03-31 13:01:05 +00:00
|
|
|
array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit ) +
|
|
|
|
|
$query_options,
|
2008-06-17 08:24:00 +00:00
|
|
|
$join_conds );
|
|
|
|
|
// We have a new_namespace_time index! UNION over new=(0,1) and sort result set!
|
|
|
|
|
} else {
|
|
|
|
|
// New pages
|
2011-05-09 22:57:44 +00:00
|
|
|
$sqlNew = $dbr->selectSQLText(
|
|
|
|
|
$tables,
|
|
|
|
|
$fields,
|
2008-06-17 08:24:00 +00:00
|
|
|
array( 'rc_new' => 1 ) + $conds,
|
|
|
|
|
__METHOD__,
|
2011-05-09 22:57:44 +00:00
|
|
|
array(
|
|
|
|
|
'ORDER BY' => 'rc_timestamp DESC',
|
|
|
|
|
'LIMIT' => $limit,
|
2011-06-26 23:32:46 +00:00
|
|
|
'USE INDEX' => array( 'recentchanges' => 'new_name_timestamp' )
|
2011-05-09 22:57:44 +00:00
|
|
|
),
|
|
|
|
|
$join_conds
|
|
|
|
|
);
|
2008-06-17 08:24:00 +00:00
|
|
|
// Old pages
|
2011-05-09 22:57:44 +00:00
|
|
|
$sqlOld = $dbr->selectSQLText(
|
|
|
|
|
$tables,
|
|
|
|
|
$fields,
|
2008-06-17 08:24:00 +00:00
|
|
|
array( 'rc_new' => 0 ) + $conds,
|
|
|
|
|
__METHOD__,
|
2011-05-09 22:57:44 +00:00
|
|
|
array(
|
|
|
|
|
'ORDER BY' => 'rc_timestamp DESC',
|
|
|
|
|
'LIMIT' => $limit,
|
2011-06-26 23:32:46 +00:00
|
|
|
'USE INDEX' => array( 'recentchanges' => 'new_name_timestamp' )
|
2011-05-09 22:57:44 +00:00
|
|
|
),
|
|
|
|
|
$join_conds
|
|
|
|
|
);
|
2008-06-17 08:24:00 +00:00
|
|
|
# Join the two fast queries, and sort the result set
|
2011-05-09 22:57:44 +00:00
|
|
|
$sql = $dbr->unionQueries( array( $sqlNew, $sqlOld ), false ) .
|
|
|
|
|
' ORDER BY rc_timestamp DESC';
|
|
|
|
|
$sql = $dbr->limitResult( $sql, $limit, false );
|
2008-06-17 08:24:00 +00:00
|
|
|
$res = $dbr->query( $sql, __METHOD__ );
|
2005-11-15 11:12:21 +00:00
|
|
|
}
|
2005-04-03 08:27:08 +00:00
|
|
|
|
2008-06-17 08:24:00 +00:00
|
|
|
return $res;
|
2004-01-28 15:57:47 +00:00
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
2011-07-17 09:25:50 +00:00
|
|
|
* Send output to the OutputPage object, only called if not used feeds
|
2008-06-26 19:12:52 +00:00
|
|
|
*
|
2010-07-03 21:09:25 +00:00
|
|
|
* @param $rows Array of database rows
|
2008-06-26 19:12:52 +00:00
|
|
|
* @param $opts FormOptions
|
|
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function webOutput( $rows, $opts ) {
|
2011-07-17 09:25:50 +00:00
|
|
|
global $wgRCShowWatchingUsers, $wgShowUpdatedMarker, $wgAllowCategorizedRecentChanges;
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
$limit = $opts['limit'];
|
|
|
|
|
|
2008-11-28 23:06:25 +00:00
|
|
|
if( !$this->including() ) {
|
2008-06-17 08:24:00 +00:00
|
|
|
// Output options box
|
|
|
|
|
$this->doHeader( $opts );
|
2005-05-28 11:09:22 +00:00
|
|
|
}
|
2005-05-04 21:56:14 +00:00
|
|
|
|
|
|
|
|
// And now for the content
|
2011-07-17 09:25:50 +00:00
|
|
|
$this->getOutput()->setFeedAppendQuery( $this->getFeedQuery() );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-11-28 23:06:25 +00:00
|
|
|
if( $wgAllowCategorizedRecentChanges ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$this->filterByCategories( $rows, $opts );
|
2006-01-09 14:20:26 +00:00
|
|
|
}
|
2005-09-06 18:43:45 +00:00
|
|
|
|
2011-04-03 05:46:42 +00:00
|
|
|
$showWatcherCount = $wgRCShowWatchingUsers && $this->getUser()->getOption( 'shownumberswatching' );
|
2007-12-01 09:48:40 +00:00
|
|
|
$watcherCache = array();
|
|
|
|
|
|
2008-06-17 08:24:00 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
|
2008-11-28 23:06:25 +00:00
|
|
|
$counter = 1;
|
2011-07-17 09:25:50 +00:00
|
|
|
$list = ChangesList::newFromContext( $this->getContext() );
|
2008-11-28 23:06:25 +00:00
|
|
|
|
|
|
|
|
$s = $list->beginRecentChangesList();
|
|
|
|
|
foreach( $rows as $obj ) {
|
2011-05-09 22:57:44 +00:00
|
|
|
if( $limit == 0 ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-11-28 23:06:25 +00:00
|
|
|
$rc = RecentChange::newFromRow( $obj );
|
|
|
|
|
$rc->counter = $counter++;
|
2008-12-20 08:36:14 +00:00
|
|
|
# Check if the page has been updated since the last visit
|
2011-05-09 22:57:44 +00:00
|
|
|
if( $wgShowUpdatedMarker && !empty( $obj->wl_notificationtimestamp ) ) {
|
|
|
|
|
$rc->notificationtimestamp = ( $obj->rc_timestamp >= $obj->wl_notificationtimestamp );
|
2008-12-20 08:36:14 +00:00
|
|
|
} else {
|
|
|
|
|
$rc->notificationtimestamp = false; // Default
|
2008-11-28 23:06:25 +00:00
|
|
|
}
|
2008-12-20 08:36:14 +00:00
|
|
|
# Check the number of users watching the page
|
2008-11-28 23:06:25 +00:00
|
|
|
$rc->numberofWatchingusers = 0; // Default
|
|
|
|
|
if( $showWatcherCount && $obj->rc_namespace >= 0 ) {
|
2011-05-09 22:57:44 +00:00
|
|
|
if( !isset( $watcherCache[$obj->rc_namespace][$obj->rc_title] ) ) {
|
2008-11-28 23:06:25 +00:00
|
|
|
$watcherCache[$obj->rc_namespace][$obj->rc_title] =
|
2011-05-09 22:57:44 +00:00
|
|
|
$dbr->selectField(
|
|
|
|
|
'watchlist',
|
2008-11-28 23:06:25 +00:00
|
|
|
'COUNT(*)',
|
|
|
|
|
array(
|
|
|
|
|
'wl_namespace' => $obj->rc_namespace,
|
|
|
|
|
'wl_title' => $obj->rc_title,
|
|
|
|
|
),
|
2011-05-09 22:57:44 +00:00
|
|
|
__METHOD__ . '-watchers'
|
|
|
|
|
);
|
2004-12-18 03:47:11 +00:00
|
|
|
}
|
2008-11-28 23:06:25 +00:00
|
|
|
$rc->numberofWatchingusers = $watcherCache[$obj->rc_namespace][$obj->rc_title];
|
2004-03-19 05:31:18 +00:00
|
|
|
}
|
2009-02-08 15:55:32 +00:00
|
|
|
$s .= $list->recentChangesLine( $rc, !empty( $obj->wl_user ), $counter );
|
2008-11-28 23:06:25 +00:00
|
|
|
--$limit;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2004-11-25 13:47:17 +00:00
|
|
|
$s .= $list->endRecentChangesList();
|
2011-07-17 09:25:50 +00:00
|
|
|
$this->getOutput()->addHTML( $s );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2010-02-10 04:13:43 +00:00
|
|
|
/**
|
|
|
|
|
* Get the query string to append to feed link URLs.
|
|
|
|
|
* This is overridden by RCL to add the target parameter
|
2012-02-09 21:36:14 +00:00
|
|
|
* @return bool
|
2010-02-10 04:13:43 +00:00
|
|
|
*/
|
|
|
|
|
public function getFeedQuery() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Return the text to be displayed above the changes
|
|
|
|
|
*
|
|
|
|
|
* @param $opts FormOptions
|
|
|
|
|
* @return String: XHTML
|
|
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
public function doHeader( $opts ) {
|
2011-07-17 09:25:50 +00:00
|
|
|
global $wgScript;
|
2008-06-26 19:12:52 +00:00
|
|
|
|
2011-07-17 09:25:50 +00:00
|
|
|
$this->setTopText( $opts );
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
$defaults = $opts->getAllValues();
|
|
|
|
|
$nondefaults = $opts->getChangedValues();
|
2011-05-09 22:57:44 +00:00
|
|
|
$opts->consumeValues( array(
|
|
|
|
|
'namespace', 'invert', 'associated', 'tagfilter',
|
2012-01-13 21:57:52 +00:00
|
|
|
'categories', 'categories_any'
|
2011-05-09 22:57:44 +00:00
|
|
|
) );
|
2008-06-17 08:24:00 +00:00
|
|
|
|
|
|
|
|
$panel = array();
|
2008-06-26 19:12:52 +00:00
|
|
|
$panel[] = $this->optionsPanel( $defaults, $nondefaults );
|
2008-07-02 02:31:05 +00:00
|
|
|
$panel[] = '<hr />';
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
$extraOpts = $this->getExtraOptions( $opts );
|
2008-08-28 07:14:33 +00:00
|
|
|
$extraOptsCount = count( $extraOpts );
|
|
|
|
|
$count = 0;
|
2012-04-28 18:20:11 +00:00
|
|
|
$submit = ' ' . Xml::submitbutton( $this->msg( 'allpagessubmit' )->text() );
|
2008-06-17 08:24:00 +00:00
|
|
|
|
2008-08-28 07:14:33 +00:00
|
|
|
$out = Xml::openElement( 'table', array( 'class' => 'mw-recentchanges-table' ) );
|
2012-04-09 18:33:28 +00:00
|
|
|
foreach( $extraOpts as $name => $optionRow ) {
|
2008-08-28 07:14:33 +00:00
|
|
|
# Add submit button to the last row only
|
|
|
|
|
++$count;
|
2012-04-09 18:33:28 +00:00
|
|
|
$addSubmit = ( $count === $extraOptsCount ) ? $submit : '';
|
2008-08-28 07:14:33 +00:00
|
|
|
|
2008-06-17 08:24:00 +00:00
|
|
|
$out .= Xml::openElement( 'tr' );
|
2008-11-28 23:06:25 +00:00
|
|
|
if( is_array( $optionRow ) ) {
|
2012-04-09 18:33:28 +00:00
|
|
|
$out .= Xml::tags( 'td', array( 'class' => 'mw-label mw-' . $name . '-label' ), $optionRow[0] );
|
2008-08-28 07:14:33 +00:00
|
|
|
$out .= Xml::tags( 'td', array( 'class' => 'mw-input' ), $optionRow[1] . $addSubmit );
|
2008-06-17 08:24:00 +00:00
|
|
|
} else {
|
2008-08-28 07:14:33 +00:00
|
|
|
$out .= Xml::tags( 'td', array( 'class' => 'mw-input', 'colspan' => 2 ), $optionRow . $addSubmit );
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
|
|
|
|
$out .= Xml::closeElement( 'tr' );
|
|
|
|
|
}
|
|
|
|
|
$out .= Xml::closeElement( 'table' );
|
|
|
|
|
|
|
|
|
|
$unconsumed = $opts->getUnconsumedValues();
|
2008-11-28 23:06:25 +00:00
|
|
|
foreach( $unconsumed as $key => $value ) {
|
2010-10-31 16:33:48 +00:00
|
|
|
$out .= Html::hidden( $key, $value );
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$t = $this->getTitle();
|
2010-10-31 16:33:48 +00:00
|
|
|
$out .= Html::hidden( 'title', $t->getPrefixedText() );
|
2008-06-17 08:24:00 +00:00
|
|
|
$form = Xml::tags( 'form', array( 'action' => $wgScript ), $out );
|
|
|
|
|
$panel[] = $form;
|
|
|
|
|
$panelString = implode( "\n", $panel );
|
|
|
|
|
|
2011-07-17 09:25:50 +00:00
|
|
|
$this->getOutput()->addHTML(
|
2012-04-28 18:20:11 +00:00
|
|
|
Xml::fieldset( $this->msg( 'recentchanges-legend' )->text(), $panelString, array( 'class' => 'rcoptions' ) )
|
2008-07-02 02:31:05 +00:00
|
|
|
);
|
2008-06-26 19:12:52 +00:00
|
|
|
|
2011-07-17 09:25:50 +00:00
|
|
|
$this->setBottomText( $opts );
|
2008-06-26 19:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get options to be displayed in a form
|
|
|
|
|
*
|
|
|
|
|
* @param $opts FormOptions
|
2010-07-03 21:09:25 +00:00
|
|
|
* @return Array
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
2011-05-09 22:57:44 +00:00
|
|
|
function getExtraOptions( $opts ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$extraOpts = array();
|
|
|
|
|
$extraOpts['namespace'] = $this->namespaceFilterForm( $opts );
|
|
|
|
|
|
|
|
|
|
global $wgAllowCategorizedRecentChanges;
|
2008-11-28 23:06:25 +00:00
|
|
|
if( $wgAllowCategorizedRecentChanges ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$extraOpts['category'] = $this->categoryFilterForm( $opts );
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-13 21:57:52 +00:00
|
|
|
$tagFilter = ChangeTags::buildTagFilterSelector( $opts['tagfilter'] );
|
2011-05-09 22:57:44 +00:00
|
|
|
if ( count( $tagFilter ) ) {
|
2012-01-13 21:57:52 +00:00
|
|
|
$extraOpts['tagfilter'] = $tagFilter;
|
2011-05-09 22:57:44 +00:00
|
|
|
}
|
2009-01-28 19:08:18 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
|
|
|
|
|
return $extraOpts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send the text to be displayed above the options
|
|
|
|
|
*
|
|
|
|
|
* @param $opts FormOptions
|
|
|
|
|
*/
|
2011-07-17 09:25:50 +00:00
|
|
|
function setTopText( FormOptions $opts ) {
|
2011-07-24 00:56:59 +00:00
|
|
|
global $wgContLang;
|
2012-05-01 11:33:51 +00:00
|
|
|
|
|
|
|
|
$message = $this->msg( 'recentchangestext' )->inContentLanguage();
|
2012-06-05 22:58:54 +00:00
|
|
|
if ( !$message->isDisabled() ) {
|
2012-05-01 11:33:51 +00:00
|
|
|
$this->getOutput()->addWikiText(
|
|
|
|
|
Html::rawElement( 'p',
|
|
|
|
|
array( 'lang' => $wgContLang->getCode(), 'dir' => $wgContLang->getDir() ),
|
|
|
|
|
"\n" . $message->plain() . "\n"
|
|
|
|
|
),
|
|
|
|
|
/* $lineStart */ false,
|
|
|
|
|
/* $interface */ false
|
|
|
|
|
);
|
|
|
|
|
}
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 19:12:52 +00:00
|
|
|
* Send the text to be displayed after the options, for use in
|
|
|
|
|
* Recentchangeslinked
|
|
|
|
|
*
|
|
|
|
|
* @param $opts FormOptions
|
|
|
|
|
*/
|
2011-07-17 09:25:50 +00:00
|
|
|
function setBottomText( FormOptions $opts ) {}
|
2008-06-26 19:12:52 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates the choose namespace selection
|
|
|
|
|
*
|
2011-03-02 20:40:40 +00:00
|
|
|
* @todo Uses radio buttons (HASHAR)
|
2008-06-26 19:12:52 +00:00
|
|
|
* @param $opts FormOptions
|
2010-07-03 21:09:25 +00:00
|
|
|
* @return String
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
protected function namespaceFilterForm( FormOptions $opts ) {
|
2012-01-29 19:05:25 +00:00
|
|
|
$nsSelect = Html::namespaceSelector(
|
2012-02-02 22:57:39 +00:00
|
|
|
array( 'selected' => $opts['namespace'], 'all' => '' ),
|
|
|
|
|
array( 'name' => 'namespace', 'id' => 'namespace' )
|
2012-01-29 19:05:25 +00:00
|
|
|
);
|
2012-04-28 18:20:11 +00:00
|
|
|
$nsLabel = Xml::label( $this->msg( 'namespace' )->text(), 'namespace' );
|
2011-06-23 20:00:05 +00:00
|
|
|
$invert = Xml::checkLabel(
|
2012-04-28 18:20:11 +00:00
|
|
|
$this->msg( 'invert' )->text(), 'invert', 'nsinvert',
|
2011-06-23 20:00:05 +00:00
|
|
|
$opts['invert'],
|
2012-04-28 18:20:11 +00:00
|
|
|
array( 'title' => $this->msg( 'tooltip-invert' )->text() )
|
2011-06-23 20:00:05 +00:00
|
|
|
);
|
2011-05-09 22:57:44 +00:00
|
|
|
$associated = Xml::checkLabel(
|
2012-04-28 18:20:11 +00:00
|
|
|
$this->msg( 'namespace_association' )->text(), 'associated', 'nsassociated',
|
2011-06-23 20:00:05 +00:00
|
|
|
$opts['associated'],
|
2012-04-28 18:20:11 +00:00
|
|
|
array( 'title' => $this->msg( 'tooltip-namespace_association' )->text() )
|
2011-05-09 22:57:44 +00:00
|
|
|
);
|
2011-03-02 20:40:40 +00:00
|
|
|
return array( $nsLabel, "$nsSelect $invert $associated" );
|
2008-06-17 08:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Create a input to filter changes by categories
|
|
|
|
|
*
|
|
|
|
|
* @param $opts FormOptions
|
2010-07-03 21:09:25 +00:00
|
|
|
* @return Array
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
2008-06-17 08:24:00 +00:00
|
|
|
protected function categoryFilterForm( FormOptions $opts ) {
|
2012-04-28 18:20:11 +00:00
|
|
|
list( $label, $input ) = Xml::inputLabelSep( $this->msg( 'rc_categories' )->text(),
|
2008-06-17 08:24:00 +00:00
|
|
|
'categories', 'mw-categories', false, $opts['categories'] );
|
|
|
|
|
|
2012-04-28 18:20:11 +00:00
|
|
|
$input .= ' ' . Xml::checkLabel( $this->msg( 'rc_categories_any' )->text(),
|
2008-06-17 08:24:00 +00:00
|
|
|
'categories_any', 'mw-categories_any', $opts['categories_any'] );
|
|
|
|
|
|
|
|
|
|
return array( $label, $input );
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Filter $rows by categories set in $opts
|
|
|
|
|
*
|
2010-07-03 21:09:25 +00:00
|
|
|
* @param $rows Array of database rows
|
2008-06-26 19:12:52 +00:00
|
|
|
* @param $opts FormOptions
|
|
|
|
|
*/
|
|
|
|
|
function filterByCategories( &$rows, FormOptions $opts ) {
|
2010-03-04 15:42:17 +00:00
|
|
|
$categories = array_map( 'trim', explode( '|' , $opts['categories'] ) );
|
2008-06-26 19:12:52 +00:00
|
|
|
|
2010-03-04 15:42:17 +00:00
|
|
|
if( !count( $categories ) ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
# Filter categories
|
|
|
|
|
$cats = array();
|
2008-11-28 23:06:25 +00:00
|
|
|
foreach( $categories as $cat ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$cat = trim( $cat );
|
2011-05-09 22:57:44 +00:00
|
|
|
if( $cat == '' ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
$cats[] = $cat;
|
2006-01-09 14:20:26 +00:00
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
|
|
|
|
|
# Filter articles
|
|
|
|
|
$articles = array();
|
|
|
|
|
$a2r = array();
|
2010-03-04 15:42:17 +00:00
|
|
|
$rowsarr = array();
|
2011-05-09 22:57:44 +00:00
|
|
|
foreach( $rows as $k => $r ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$nt = Title::makeTitle( $r->rc_namespace, $r->rc_title );
|
|
|
|
|
$id = $nt->getArticleID();
|
2011-05-09 22:57:44 +00:00
|
|
|
if( $id == 0 ) {
|
|
|
|
|
continue; # Page might have been deleted...
|
|
|
|
|
}
|
2010-03-04 15:42:17 +00:00
|
|
|
if( !in_array( $id, $articles ) ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$articles[] = $id;
|
|
|
|
|
}
|
2010-03-04 15:42:17 +00:00
|
|
|
if( !isset( $a2r[$id] ) ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$a2r[$id] = array();
|
|
|
|
|
}
|
|
|
|
|
$a2r[$id][] = $k;
|
2010-03-04 15:42:17 +00:00
|
|
|
$rowsarr[$k] = $r;
|
2006-01-09 14:20:26 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
# Shortcut?
|
2011-05-09 22:57:44 +00:00
|
|
|
if( !count( $articles ) || !count( $cats ) ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
|
|
|
|
|
# Look up
|
2010-03-04 15:42:17 +00:00
|
|
|
$c = new Categoryfinder;
|
2011-05-09 22:57:44 +00:00
|
|
|
$c->seed( $articles, $cats, $opts['categories_any'] ? 'OR' : 'AND' );
|
2008-06-26 19:12:52 +00:00
|
|
|
$match = $c->run();
|
|
|
|
|
|
|
|
|
|
# Filter
|
|
|
|
|
$newrows = array();
|
2011-05-09 22:57:44 +00:00
|
|
|
foreach( $match as $id ) {
|
|
|
|
|
foreach( $a2r[$id] as $rev ) {
|
2008-06-26 19:12:52 +00:00
|
|
|
$k = $rev;
|
2010-03-04 15:42:17 +00:00
|
|
|
$newrows[$k] = $rowsarr[$k];
|
2008-06-26 19:12:52 +00:00
|
|
|
}
|
2004-12-12 04:13:19 +00:00
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
$rows = $newrows;
|
2004-12-12 04:13:19 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Makes change an option link which carries all the other options
|
2010-07-03 21:09:25 +00:00
|
|
|
*
|
|
|
|
|
* @param $title Title
|
|
|
|
|
* @param $override Array: options to override
|
|
|
|
|
* @param $options Array: current options
|
|
|
|
|
* @param $active Boolean: whether to show the link in bold
|
2012-02-09 21:36:14 +00:00
|
|
|
* @return string
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
|
|
|
|
function makeOptionsLink( $title, $override, $options, $active = false ) {
|
2008-11-01 23:20:25 +00:00
|
|
|
$params = $override + $options;
|
2011-07-17 09:25:50 +00:00
|
|
|
$text = htmlspecialchars( $title );
|
2009-04-13 12:39:12 +00:00
|
|
|
if ( $active ) {
|
2011-07-17 09:25:50 +00:00
|
|
|
$text = '<strong>' . $text . '</strong>';
|
2009-04-13 12:39:12 +00:00
|
|
|
}
|
2011-07-17 09:25:50 +00:00
|
|
|
return Linker::linkKnown( $this->getTitle(), $text, array(), $params );
|
2006-04-05 18:31:58 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
/**
|
|
|
|
|
* Creates the options panel.
|
2010-07-03 21:09:25 +00:00
|
|
|
*
|
|
|
|
|
* @param $defaults Array
|
|
|
|
|
* @param $nondefaults Array
|
2012-02-09 21:36:14 +00:00
|
|
|
* @return string
|
2008-06-26 19:12:52 +00:00
|
|
|
*/
|
|
|
|
|
function optionsPanel( $defaults, $nondefaults ) {
|
2011-07-17 09:25:50 +00:00
|
|
|
global $wgRCLinkLimits, $wgRCLinkDays;
|
2008-06-26 19:12:52 +00:00
|
|
|
|
|
|
|
|
$options = $nondefaults + $defaults;
|
|
|
|
|
|
2008-10-29 15:47:58 +00:00
|
|
|
$note = '';
|
2012-04-28 18:20:11 +00:00
|
|
|
$msg = $this->msg( 'rclegend' );
|
|
|
|
|
if( !$msg->isDisabled() ) {
|
|
|
|
|
$note .= '<div class="mw-rclegend">' . $msg->parse() . "</div>\n";
|
2009-01-25 00:19:01 +00:00
|
|
|
}
|
2012-04-28 18:20:11 +00:00
|
|
|
|
|
|
|
|
$lang = $this->getLanguage();
|
|
|
|
|
$user = $this->getUser();
|
2008-10-29 15:47:58 +00:00
|
|
|
if( $options['from'] ) {
|
2012-04-28 18:20:11 +00:00
|
|
|
$note .= $this->msg( 'rcnotefrom' )->numParams( $options['limit'] )->params(
|
|
|
|
|
$lang->userTimeAndDate( $options['from'], $user ),
|
|
|
|
|
$lang->userDate( $options['from'], $user ),
|
|
|
|
|
$lang->userTime( $options['from'], $user ) )->parse() . '<br />';
|
2008-10-29 15:47:58 +00:00
|
|
|
}
|
2008-10-29 15:35:18 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
# Sort data for display and make sure it's unique after we've added user data.
|
|
|
|
|
$wgRCLinkLimits[] = $options['limit'];
|
|
|
|
|
$wgRCLinkDays[] = $options['days'];
|
2008-08-11 16:24:51 +00:00
|
|
|
sort( $wgRCLinkLimits );
|
|
|
|
|
sort( $wgRCLinkDays );
|
|
|
|
|
$wgRCLinkLimits = array_unique( $wgRCLinkLimits );
|
|
|
|
|
$wgRCLinkDays = array_unique( $wgRCLinkDays );
|
2008-06-26 19:12:52 +00:00
|
|
|
|
|
|
|
|
// limit links
|
|
|
|
|
foreach( $wgRCLinkLimits as $value ) {
|
2012-04-28 18:20:11 +00:00
|
|
|
$cl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
|
2011-05-09 22:57:44 +00:00
|
|
|
array( 'limit' => $value ), $nondefaults, $value == $options['limit'] );
|
2008-06-26 19:12:52 +00:00
|
|
|
}
|
2012-04-28 18:20:11 +00:00
|
|
|
$cl = $lang->pipeList( $cl );
|
2005-05-03 18:30:46 +00:00
|
|
|
|
2008-06-26 19:12:52 +00:00
|
|
|
// day links, reset 'from' to none
|
|
|
|
|
foreach( $wgRCLinkDays as $value ) {
|
2012-04-28 18:20:11 +00:00
|
|
|
$dl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
|
2011-05-09 22:57:44 +00:00
|
|
|
array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] );
|
2008-06-26 19:12:52 +00:00
|
|
|
}
|
2012-04-28 18:20:11 +00:00
|
|
|
$dl = $lang->pipeList( $dl );
|
2008-06-26 19:12:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// show/hide links
|
2012-04-28 18:20:11 +00:00
|
|
|
$showhide = array( $this->msg( 'show' )->text(), $this->msg( 'hide' )->text() );
|
2011-05-23 04:28:58 +00:00
|
|
|
$filters = array(
|
2012-01-13 09:14:56 +00:00
|
|
|
'hideminor' => 'rcshowhideminor',
|
|
|
|
|
'hidebots' => 'rcshowhidebots',
|
|
|
|
|
'hideanons' => 'rcshowhideanons',
|
|
|
|
|
'hideliu' => 'rcshowhideliu',
|
2011-05-23 04:28:58 +00:00
|
|
|
'hidepatrolled' => 'rcshowhidepatr',
|
2012-01-13 09:14:56 +00:00
|
|
|
'hidemyself' => 'rcshowhidemine'
|
2011-05-23 04:28:58 +00:00
|
|
|
);
|
2012-01-13 09:14:56 +00:00
|
|
|
foreach ( $this->getCustomFilters() as $key => $params ) {
|
2011-05-23 04:28:58 +00:00
|
|
|
$filters[$key] = $params['msg'];
|
|
|
|
|
}
|
|
|
|
|
// Disable some if needed
|
2012-04-28 18:20:11 +00:00
|
|
|
if ( !$user->useRCPatrol() ) {
|
2011-05-23 04:28:58 +00:00
|
|
|
unset( $filters['hidepatrolled'] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$links = array();
|
|
|
|
|
foreach ( $filters as $key => $msg ) {
|
|
|
|
|
$link = $this->makeOptionsLink( $showhide[1 - $options[$key]],
|
|
|
|
|
array( $key => 1-$options[$key] ), $nondefaults );
|
2012-04-28 18:20:11 +00:00
|
|
|
$links[] = $this->msg( $msg )->rawParams( $link )->escaped();
|
2011-05-23 04:28:58 +00:00
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
|
|
|
|
|
// show from this onward link
|
2011-06-24 10:00:35 +00:00
|
|
|
$timestamp = wfTimestampNow();
|
2012-04-28 18:20:11 +00:00
|
|
|
$now = $lang->userTimeAndDate( $timestamp, $user );
|
2011-05-09 22:57:44 +00:00
|
|
|
$tl = $this->makeOptionsLink(
|
2011-06-24 10:00:35 +00:00
|
|
|
$now, array( 'from' => $timestamp ), $nondefaults
|
2011-05-09 22:57:44 +00:00
|
|
|
);
|
2008-06-26 19:12:52 +00:00
|
|
|
|
2012-04-28 18:20:11 +00:00
|
|
|
$rclinks = $this->msg( 'rclinks' )->rawParams( $cl, $dl, $lang->pipeList( $links ) )->parse();
|
|
|
|
|
$rclistfrom = $this->msg( 'rclistfrom' )->rawParams( $tl )->parse();
|
2008-10-29 15:47:58 +00:00
|
|
|
return "{$note}$rclinks<br />$rclistfrom";
|
2005-05-03 18:30:46 +00:00
|
|
|
}
|
2011-06-28 06:40:49 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* add javascript specific to the [[Special:RecentChanges]] page
|
|
|
|
|
*/
|
|
|
|
|
function addRecentChangesJS() {
|
2011-07-17 09:25:50 +00:00
|
|
|
$this->getOutput()->addModules( array(
|
2011-06-28 06:40:49 +00:00
|
|
|
'mediawiki.special.recentchanges',
|
|
|
|
|
) );
|
|
|
|
|
}
|
2008-06-26 19:12:52 +00:00
|
|
|
}
|