123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- <?php
- /**
- * Implements Special:Contributions
- *
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
- use MediaWiki\Block\DatabaseBlock;
- use MediaWiki\MediaWikiServices;
- /**
- * Special:Contributions, show user contributions in a paged list
- *
- * @ingroup SpecialPage
- */
- class SpecialContributions extends IncludableSpecialPage {
- protected $opts;
- public function __construct() {
- parent::__construct( 'Contributions' );
- }
- public function execute( $par ) {
- $this->setHeaders();
- $this->outputHeader();
- $out = $this->getOutput();
- // Modules required for viewing the list of contributions (also when included on other pages)
- $out->addModuleStyles( [
- 'jquery.makeCollapsible.styles',
- 'mediawiki.interface.helpers.styles',
- 'mediawiki.special',
- 'mediawiki.special.changeslist',
- ] );
- $out->addModules( [
- 'mediawiki.special.recentchanges',
- // Certain skins e.g. Minerva might have disabled this module.
- 'mediawiki.page.ready'
- ] );
- $this->addHelpLink( 'Help:User contributions' );
- $this->opts = [];
- $request = $this->getRequest();
- $target = $par ?? $request->getVal( 'target' );
- $this->opts['deletedOnly'] = $request->getBool( 'deletedOnly' );
- if ( !strlen( $target ) ) {
- if ( !$this->including() ) {
- $out->addHTML( $this->getForm( $this->opts ) );
- }
- return;
- }
- $user = $this->getUser();
- $this->opts['limit'] = $request->getInt( 'limit', $user->getOption( 'rclimit' ) );
- $this->opts['target'] = $target;
- $this->opts['topOnly'] = $request->getBool( 'topOnly' );
- $this->opts['newOnly'] = $request->getBool( 'newOnly' );
- $this->opts['hideMinor'] = $request->getBool( 'hideMinor' );
- $id = 0;
- if ( ExternalUserNames::isExternal( $target ) ) {
- $userObj = User::newFromName( $target, false );
- if ( !$userObj ) {
- $out->addHTML( $this->getForm( $this->opts ) );
- return;
- }
- $out->addSubtitle( $this->contributionsSub( $userObj ) );
- $out->setHTMLTitle( $this->msg(
- 'pagetitle',
- $this->msg( 'contributions-title', $target )->plain()
- )->inContentLanguage() );
- } else {
- $nt = Title::makeTitleSafe( NS_USER, $target );
- if ( !$nt ) {
- $out->addHTML( $this->getForm( $this->opts ) );
- return;
- }
- $userObj = User::newFromName( $nt->getText(), false );
- if ( !$userObj ) {
- $out->addHTML( $this->getForm( $this->opts ) );
- return;
- }
- $id = $userObj->getId();
- $target = $nt->getText();
- $out->addSubtitle( $this->contributionsSub( $userObj ) );
- $out->setHTMLTitle( $this->msg(
- 'pagetitle',
- $this->msg( 'contributions-title', $target )->plain()
- )->inContentLanguage() );
- # For IP ranges, we want the contributionsSub, but not the skin-dependent
- # links under 'Tools', which may include irrelevant links like 'Logs'.
- if ( !IP::isValidRange( $target ) ) {
- $this->getSkin()->setRelevantUser( $userObj );
- }
- }
- $ns = $request->getVal( 'namespace', null );
- if ( $ns !== null && $ns !== '' && $ns !== 'all' ) {
- $this->opts['namespace'] = intval( $ns );
- } else {
- $this->opts['namespace'] = '';
- }
- // Backwards compatibility: Before using OOUI form the old HTML form had
- // fields for nsInvert and associated. These have now been replaced with the
- // wpFilters query string parameters. These are retained to keep old URIs working.
- $this->opts['associated'] = $request->getBool( 'associated' );
- $this->opts['nsInvert'] = (bool)$request->getVal( 'nsInvert' );
- $nsFilters = $request->getArray( 'wpfilters', null );
- if ( $nsFilters !== null ) {
- $this->opts['associated'] = in_array( 'associated', $nsFilters );
- $this->opts['nsInvert'] = in_array( 'nsInvert', $nsFilters );
- }
- $this->opts['tagfilter'] = (string)$request->getVal( 'tagfilter' );
- // Allows reverts to have the bot flag in recent changes. It is just here to
- // be passed in the form at the top of the page
- if ( MediaWikiServices::getInstance()
- ->getPermissionManager()
- ->userHasRight( $user, 'markbotedits' ) && $request->getBool( 'bot' )
- ) {
- $this->opts['bot'] = '1';
- }
- $skip = $request->getText( 'offset' ) || $request->getText( 'dir' ) == 'prev';
- # Offset overrides year/month selection
- if ( !$skip ) {
- $this->opts['year'] = $request->getVal( 'year' );
- $this->opts['month'] = $request->getVal( 'month' );
- $this->opts['start'] = $request->getVal( 'start' );
- $this->opts['end'] = $request->getVal( 'end' );
- }
- $this->opts = ContribsPager::processDateFilter( $this->opts );
- if ( $this->opts['namespace'] < NS_MAIN ) {
- $this->getOutput()->wrapWikiMsg(
- "<div class=\"mw-negative-namespace-not-supported error\">\n\$1\n</div>",
- [ 'negative-namespace-not-supported' ]
- );
- $out->addHTML( $this->getForm( $this->opts ) );
- return;
- }
- $feedType = $request->getVal( 'feed' );
- $feedParams = [
- 'action' => 'feedcontributions',
- 'user' => $target,
- ];
- if ( $this->opts['topOnly'] ) {
- $feedParams['toponly'] = true;
- }
- if ( $this->opts['newOnly'] ) {
- $feedParams['newonly'] = true;
- }
- if ( $this->opts['hideMinor'] ) {
- $feedParams['hideminor'] = true;
- }
- if ( $this->opts['deletedOnly'] ) {
- $feedParams['deletedonly'] = true;
- }
- if ( $this->opts['tagfilter'] !== '' ) {
- $feedParams['tagfilter'] = $this->opts['tagfilter'];
- }
- if ( $this->opts['namespace'] !== '' ) {
- $feedParams['namespace'] = $this->opts['namespace'];
- }
- // Don't use year and month for the feed URL, but pass them on if
- // we redirect to API (if $feedType is specified)
- if ( $feedType && $this->opts['year'] !== null ) {
- $feedParams['year'] = $this->opts['year'];
- }
- if ( $feedType && $this->opts['month'] !== null ) {
- $feedParams['month'] = $this->opts['month'];
- }
- if ( $feedType ) {
- // Maintain some level of backwards compatibility
- // If people request feeds using the old parameters, redirect to API
- $feedParams['feedformat'] = $feedType;
- $url = wfAppendQuery( wfScript( 'api' ), $feedParams );
- $out->redirect( $url, '301' );
- return;
- }
- // Add RSS/atom links
- $this->addFeedLinks( $feedParams );
- if ( Hooks::run( 'SpecialContributionsBeforeMainOutput', [ $id, $userObj, $this ] ) ) {
- $pager = new ContribsPager( $this->getContext(), [
- 'target' => $target,
- 'namespace' => $this->opts['namespace'],
- 'tagfilter' => $this->opts['tagfilter'],
- 'start' => $this->opts['start'],
- 'end' => $this->opts['end'],
- 'deletedOnly' => $this->opts['deletedOnly'],
- 'topOnly' => $this->opts['topOnly'],
- 'newOnly' => $this->opts['newOnly'],
- 'hideMinor' => $this->opts['hideMinor'],
- 'nsInvert' => $this->opts['nsInvert'],
- 'associated' => $this->opts['associated'],
- ], $this->getLinkRenderer() );
- if ( !$this->including() ) {
- $out->addHTML( $this->getForm( $this->opts ) );
- }
- if ( IP::isValidRange( $target ) && !$pager->isQueryableRange( $target ) ) {
- // Valid range, but outside CIDR limit.
- $limits = $this->getConfig()->get( 'RangeContributionsCIDRLimit' );
- $limit = $limits[ IP::isIPv4( $target ) ? 'IPv4' : 'IPv6' ];
- $out->addWikiMsg( 'sp-contributions-outofrange', $limit );
- } elseif ( !$pager->getNumRows() ) {
- $out->addWikiMsg( 'nocontribs', $target );
- } else {
- # Show a message about replica DB lag, if applicable
- $lag = $pager->getDatabase()->getSessionLagStatus()['lag'];
- if ( $lag > 0 ) {
- $out->showLagWarning( $lag );
- }
- $output = $pager->getBody();
- if ( !$this->including() ) {
- $output = $pager->getNavigationBar() .
- $output .
- $pager->getNavigationBar();
- }
- $out->addHTML( $output );
- }
- $out->preventClickjacking( $pager->getPreventClickjacking() );
- # Show the appropriate "footer" message - WHOIS tools, etc.
- if ( IP::isValidRange( $target ) ) {
- $message = 'sp-contributions-footer-anon-range';
- } elseif ( IP::isIPAddress( $target ) ) {
- $message = 'sp-contributions-footer-anon';
- } elseif ( $userObj->isAnon() ) {
- // No message for non-existing users
- $message = '';
- } else {
- $message = 'sp-contributions-footer';
- }
- if ( $message && !$this->including() && !$this->msg( $message, $target )->isDisabled() ) {
- $out->wrapWikiMsg(
- "<div class='mw-contributions-footer'>\n$1\n</div>",
- [ $message, $target ] );
- }
- }
- }
- /**
- * Generates the subheading with links
- * @param User $userObj User object for the target
- * @return string Appropriately-escaped HTML to be output literally
- * @todo FIXME: Almost the same as getSubTitle in SpecialDeletedContributions.php.
- * Could be combined.
- */
- protected function contributionsSub( $userObj ) {
- if ( $userObj->isAnon() ) {
- // Show a warning message that the user being searched for doesn't exist.
- // User::isIP returns true for IP address and usemod IPs like '123.123.123.xxx',
- // but returns false for IP ranges. We don't want to suggest either of these are
- // valid usernames which we would with the 'contributions-userdoesnotexist' message.
- if ( !User::isIP( $userObj->getName() ) && !$userObj->isIPRange() ) {
- $this->getOutput()->wrapWikiMsg(
- "<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
- [
- 'contributions-userdoesnotexist',
- wfEscapeWikiText( $userObj->getName() ),
- ]
- );
- if ( !$this->including() ) {
- $this->getOutput()->setStatusCode( 404 );
- }
- }
- $user = htmlspecialchars( $userObj->getName() );
- } else {
- $user = $this->getLinkRenderer()->makeLink( $userObj->getUserPage(), $userObj->getName() );
- }
- $nt = $userObj->getUserPage();
- $talk = $userObj->getTalkPage();
- $links = '';
- if ( $talk ) {
- $tools = self::getUserLinks( $this, $userObj );
- $links = Html::openElement( 'span', [ 'class' => 'mw-changeslist-links' ] );
- foreach ( $tools as $tool ) {
- $links .= Html::rawElement( 'span', [], $tool ) . ' ';
- }
- $links = trim( $links ) . Html::closeElement( 'span' );
- // Show a note if the user is blocked and display the last block log entry.
- // Do not expose the autoblocks, since that may lead to a leak of accounts' IPs,
- // and also this will display a totally irrelevant log entry as a current block.
- if ( !$this->including() ) {
- // For IP ranges you must give DatabaseBlock::newFromTarget the CIDR string
- // and not a user object.
- if ( $userObj->isIPRange() ) {
- $block = DatabaseBlock::newFromTarget( $userObj->getName(), $userObj->getName() );
- } else {
- $block = DatabaseBlock::newFromTarget( $userObj, $userObj );
- }
- if ( !is_null( $block ) && $block->getType() != DatabaseBlock::TYPE_AUTO ) {
- if ( $block->getType() == DatabaseBlock::TYPE_RANGE ) {
- $nt = MediaWikiServices::getInstance()->getNamespaceInfo()->
- getCanonicalName( NS_USER ) . ':' . $block->getTarget();
- }
- $out = $this->getOutput(); // showLogExtract() wants first parameter by reference
- LogEventsList::showLogExtract(
- $out,
- 'block',
- $nt,
- '',
- [
- 'lim' => 1,
- 'showIfEmpty' => false,
- 'msgKey' => [
- $userObj->isAnon() ?
- 'sp-contributions-blocked-notice-anon' :
- 'sp-contributions-blocked-notice',
- $userObj->getName() # Support GENDER in 'sp-contributions-blocked-notice'
- ],
- 'offset' => '' # don't use WebRequest parameter offset
- ]
- );
- }
- }
- }
- return Html::rawElement( 'div', [ 'class' => 'mw-contributions-user-tools' ],
- $this->msg( 'contributions-subtitle' )->rawParams( $user )->params( $userObj->getName() )
- . ' ' . $links
- );
- }
- /**
- * Links to different places.
- *
- * @note This function is also called in DeletedContributionsPage
- * @param SpecialPage $sp SpecialPage instance, for context
- * @param User $target Target user object
- * @return array
- */
- public static function getUserLinks( SpecialPage $sp, User $target ) {
- $id = $target->getId();
- $username = $target->getName();
- $userpage = $target->getUserPage();
- $talkpage = $target->getTalkPage();
- $isIP = IP::isValid( $username );
- $isRange = IP::isValidRange( $username );
- $linkRenderer = $sp->getLinkRenderer();
- $tools = [];
- # No talk pages for IP ranges.
- if ( !$isRange ) {
- $tools['user-talk'] = $linkRenderer->makeLink(
- $talkpage,
- $sp->msg( 'sp-contributions-talk' )->text()
- );
- }
- # Block / Change block / Unblock links
- $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
- if ( $permissionManager->userHasRight( $sp->getUser(), 'block' ) ) {
- if ( $target->getBlock() && $target->getBlock()->getType() != DatabaseBlock::TYPE_AUTO ) {
- $tools['block'] = $linkRenderer->makeKnownLink( # Change block link
- SpecialPage::getTitleFor( 'Block', $username ),
- $sp->msg( 'change-blocklink' )->text()
- );
- $tools['unblock'] = $linkRenderer->makeKnownLink( # Unblock link
- SpecialPage::getTitleFor( 'Unblock', $username ),
- $sp->msg( 'unblocklink' )->text()
- );
- } else { # User is not blocked
- $tools['block'] = $linkRenderer->makeKnownLink( # Block link
- SpecialPage::getTitleFor( 'Block', $username ),
- $sp->msg( 'blocklink' )->text()
- );
- }
- }
- # Block log link
- $tools['log-block'] = $linkRenderer->makeKnownLink(
- SpecialPage::getTitleFor( 'Log', 'block' ),
- $sp->msg( 'sp-contributions-blocklog' )->text(),
- [],
- [ 'page' => $userpage->getPrefixedText() ]
- );
- # Suppression log link (T61120)
- if ( $permissionManager->userHasRight( $sp->getUser(), 'suppressionlog' ) ) {
- $tools['log-suppression'] = $linkRenderer->makeKnownLink(
- SpecialPage::getTitleFor( 'Log', 'suppress' ),
- $sp->msg( 'sp-contributions-suppresslog', $username )->text(),
- [],
- [ 'offender' => $username ]
- );
- }
- # Don't show some links for IP ranges
- if ( !$isRange ) {
- # Uploads: hide if IPs cannot upload (T220674)
- if ( !$isIP || $permissionManager->userHasRight( $target, 'upload' ) ) {
- $tools['uploads'] = $linkRenderer->makeKnownLink(
- SpecialPage::getTitleFor( 'Listfiles', $username ),
- $sp->msg( 'sp-contributions-uploads' )->text()
- );
- }
- # Other logs link
- # Todo: T146628
- $tools['logs'] = $linkRenderer->makeKnownLink(
- SpecialPage::getTitleFor( 'Log', $username ),
- $sp->msg( 'sp-contributions-logs' )->text()
- );
- # Add link to deleted user contributions for priviledged users
- # Todo: T183457
- if ( $permissionManager->userHasRight( $sp->getUser(), 'deletedhistory' ) ) {
- $tools['deletedcontribs'] = $linkRenderer->makeKnownLink(
- SpecialPage::getTitleFor( 'DeletedContributions', $username ),
- $sp->msg( 'sp-contributions-deleted', $username )->text()
- );
- }
- }
- # Add a link to change user rights for privileged users
- $userrightsPage = new UserrightsPage();
- $userrightsPage->setContext( $sp->getContext() );
- if ( $userrightsPage->userCanChangeRights( $target ) ) {
- $tools['userrights'] = $linkRenderer->makeKnownLink(
- SpecialPage::getTitleFor( 'Userrights', $username ),
- $sp->msg( 'sp-contributions-userrights', $username )->text()
- );
- }
- Hooks::run( 'ContributionsToolLinks', [ $id, $userpage, &$tools, $sp ] );
- return $tools;
- }
- /**
- * Generates the namespace selector form with hidden attributes.
- * @param array $pagerOptions with keys contribs, user, deletedOnly, limit, target, topOnly,
- * newOnly, hideMinor, namespace, associated, nsInvert, tagfilter, year, start, end
- * @return string HTML fragment
- */
- protected function getForm( array $pagerOptions ) {
- $this->opts['title'] = $this->getPageTitle()->getPrefixedText();
- // Modules required only for the form
- $this->getOutput()->addModules( [
- 'mediawiki.userSuggest',
- 'mediawiki.special.contributions',
- ] );
- $this->getOutput()->addModuleStyles( 'mediawiki.widgets.DateInputWidget.styles' );
- $this->getOutput()->enableOOUI();
- $fields = [];
- # Add hidden params for tracking except for parameters in $skipParameters
- $skipParameters = [
- 'namespace',
- 'nsInvert',
- 'deletedOnly',
- 'target',
- 'year',
- 'month',
- 'start',
- 'end',
- 'topOnly',
- 'newOnly',
- 'hideMinor',
- 'associated',
- 'tagfilter'
- ];
- foreach ( $this->opts as $name => $value ) {
- if ( in_array( $name, $skipParameters ) ) {
- continue;
- }
- $fields[$name] = [
- 'name' => $name,
- 'type' => 'hidden',
- 'default' => $value,
- ];
- }
- $target = $this->opts['target'] ?? null;
- $fields['target'] = [
- 'type' => 'text',
- 'cssclass' => 'mw-autocomplete-user mw-ui-input-inline mw-input',
- 'default' => $target ?
- str_replace( '_', ' ', $target ) : '' ,
- 'label' => $this->msg( 'sp-contributions-username' )->text(),
- 'name' => 'target',
- 'id' => 'mw-target-user-or-ip',
- 'size' => 40,
- 'autofocus' => !$target,
- 'section' => 'contribs-top',
- ];
- $ns = $this->opts['namespace'] ?? null;
- $fields['namespace'] = [
- 'type' => 'namespaceselect',
- 'label' => $this->msg( 'namespace' )->text(),
- 'name' => 'namespace',
- 'cssclass' => 'namespaceselector',
- 'default' => $ns,
- 'id' => 'namespace',
- 'section' => 'contribs-top',
- ];
- $request = $this->getRequest();
- $nsFilters = $request->getArray( 'wpfilters' );
- $fields['nsFilters'] = [
- 'class' => 'HTMLMultiSelectField',
- 'label' => '',
- 'name' => 'wpfilters',
- 'flatlist' => true,
- // Only shown when namespaces are selected.
- 'cssclass' => $ns === '' ?
- 'contribs-ns-filters mw-input-with-label mw-input-hidden' :
- 'contribs-ns-filters mw-input-with-label',
- // `contribs-ns-filters` class allows these fields to be toggled on/off by JavaScript.
- // See resources/src/mediawiki.special.recentchanges.js
- 'infusable' => true,
- 'options' => [
- $this->msg( 'invert' )->text() => 'nsInvert',
- $this->msg( 'namespace_association' )->text() => 'associated',
- ],
- 'default' => $nsFilters,
- 'section' => 'contribs-top',
- ];
- $fields['tagfilter'] = [
- 'type' => 'tagfilter',
- 'cssclass' => 'mw-tagfilter-input',
- 'id' => 'tagfilter',
- 'label-message' => [ 'tag-filter', 'parse' ],
- 'name' => 'tagfilter',
- 'size' => 20,
- 'section' => 'contribs-top',
- ];
- if ( MediaWikiServices::getInstance()
- ->getPermissionManager()
- ->userHasRight( $this->getUser(), 'deletedhistory' )
- ) {
- $fields['deletedOnly'] = [
- 'type' => 'check',
- 'id' => 'mw-show-deleted-only',
- 'label' => $this->msg( 'history-show-deleted' )->text(),
- 'name' => 'deletedOnly',
- 'section' => 'contribs-top',
- ];
- }
- $fields['topOnly'] = [
- 'type' => 'check',
- 'id' => 'mw-show-top-only',
- 'label' => $this->msg( 'sp-contributions-toponly' )->text(),
- 'name' => 'topOnly',
- 'section' => 'contribs-top',
- ];
- $fields['newOnly'] = [
- 'type' => 'check',
- 'id' => 'mw-show-new-only',
- 'label' => $this->msg( 'sp-contributions-newonly' )->text(),
- 'name' => 'newOnly',
- 'section' => 'contribs-top',
- ];
- $fields['hideMinor'] = [
- 'type' => 'check',
- 'cssclass' => 'mw-hide-minor-edits',
- 'id' => 'mw-show-new-only',
- 'label' => $this->msg( 'sp-contributions-hideminor' )->text(),
- 'name' => 'hideMinor',
- 'section' => 'contribs-top',
- ];
- // Allow additions at this point to the filters.
- $rawFilters = [];
- Hooks::run(
- 'SpecialContributions::getForm::filters',
- [ $this, &$rawFilters ]
- );
- foreach ( $rawFilters as $filter ) {
- // Backwards compatibility support for previous hook function signature.
- if ( is_string( $filter ) ) {
- $fields[] = [
- 'type' => 'info',
- 'default' => $filter,
- 'raw' => true,
- 'section' => 'contribs-top',
- ];
- wfDeprecated(
- __METHOD__ .
- ' returning string[]',
- '1.33'
- );
- } else {
- // Preferred append method.
- $fields[] = $filter;
- }
- }
- $fields['start'] = [
- 'type' => 'date',
- 'default' => '',
- 'id' => 'mw-date-start',
- 'label' => $this->msg( 'date-range-from' )->text(),
- 'name' => 'start',
- 'section' => 'contribs-date',
- ];
- $fields['end'] = [
- 'type' => 'date',
- 'default' => '',
- 'id' => 'mw-date-end',
- 'label' => $this->msg( 'date-range-to' )->text(),
- 'name' => 'end',
- 'section' => 'contribs-date',
- ];
- $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
- $htmlForm
- ->setMethod( 'get' )
- // When offset is defined, the user is paging through results
- // so we hide the form by default to allow users to focus on browsing
- // rather than defining search parameters
- ->setCollapsibleOptions(
- ( $pagerOptions['target'] ?? null ) ||
- ( $pagerOptions['start'] ?? null ) ||
- ( $pagerOptions['end'] ?? null )
- )
- ->setAction( wfScript() )
- ->setSubmitText( $this->msg( 'sp-contributions-submit' )->text() )
- ->setWrapperLegend( $this->msg( 'sp-contributions-search' )->text() );
- $explain = $this->msg( 'sp-contributions-explain' );
- if ( !$explain->isBlank() ) {
- $htmlForm->addFooterText( "<p id='mw-sp-contributions-explain'>{$explain->parse()}</p>" );
- }
- $htmlForm->loadData();
- return $htmlForm->getHTML( false );
- }
- /**
- * Return an array of subpages beginning with $search that this special page will accept.
- *
- * @param string $search Prefix to search for
- * @param int $limit Maximum number of results to return (usually 10)
- * @param int $offset Number of results to skip (usually 0)
- * @return string[] Matching subpages
- */
- public function prefixSearchSubpages( $search, $limit, $offset ) {
- $user = User::newFromName( $search );
- if ( !$user ) {
- // No prefix suggestion for invalid user
- return [];
- }
- // Autocomplete subpage as user list - public to allow caching
- return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
- }
- protected function getGroupName() {
- return 'users';
- }
- }
|