addshore <addshorewiki@gmail.com> <adamshorland@gmail.com>
Aditya Sastry <ganeshaditya1@gmail.com>
Adrian Heine <adrian.heine@wikimedia.de>
+Alangi Derick <alangiderick@gmail.com>
Alex Z. <mrzmanwiki@gmail.com> <mrzman@users.mediawiki.org>
Aleksey Bekh-Ivanov <aleksey.bekh-ivanov@wikimedia.de>
Alexandre Emsenhuber <ialex.wiki@gmail.com>
Marcin Cieślak <saper@saper.info> <saper@users.mediawiki.org>
Marco Falke <maic23@live.de>
MarcoAurelio <strigiwm@gmail.com>
+MarcoAurelio <strigiwm@gmail.com> <maurelio@tools.wmflabs.org>
Marielle Volz <marielle.volz@gmail.com>
Marius Hoch <hoo@online.de>
Mark Clements <mediawiki@kennel17.co.uk> <happydog@users.mediawiki.org>
Markus Glaser <glaser@hallowelt.biz> <mglaser@users.mediawiki.org>
Matt Johnston <mattj@emazestudios.com> <mattj@users.mediawiki.org>
Matthew Britton <hugglegurch@gmail.com> <gurch@users.mediawiki.org>
+Matthew Bowker <matthewrbowker.bugs@gmail.com>
Matthew Flaschen <mflaschen@wikimedia.org>
Matthew Walker <mwalker@wikimedia.org>
MatthiasDD <Matthias_K2@gmx.de>
Robert Leverington <robert@rhl.me.uk> <roberthl@users.mediawiki.org>
Robert Rohde <rarohde@gmail.com> <rarohde@users.mediawiki.org>
Robert Stojnić <rainmansr@gmail.com> <rainman@users.mediawiki.org>
+Robert Vogel <vogel@hallowelt.biz>
Robin Pepermans <robinp.1273@gmail.com>
Robin Pepermans <robinp.1273@gmail.com> <robin@users.mediawiki.org>
robinhood701 <robinhood70@live.ca>
* Aashaka Shah
* abhinand
* Abhishek Das
+* Abián
* Ad Huikeshoven
* Adam Miller
* Adam Roses Wight
* Bill Traynor
* Billinghurst
* billm
+* Bjornskjald
* blackspirit96
* blotmandroid
* Bogdan Stancescu
* Jonathan Wiltshire
* Jools Wills
* jsahleen
+* Juan Osorio
* Julian Ostrow
* Juliano F. Ravasi
* Julien Girault
* Lucas Werkmeister
* Luigi Corsaro
* Luis Felipe Schenone
+* LukBukkit
* Luke Faraone
* Luke Welling
* Lupin
* Misza13
* mjbmr
* moejoe0000
+* Mogmog123
* Mohamed Magdy
* Molly White
* Moriel Schottlender
* Nicolaie Constantinescu
* Nicolas Dumazet
* Nicolas Weeger
+* Niedzielski
* Niharika Kohli
* Nik Everett
* Niklas Laxström
* Pikne
* Piotr Miazga
* PiRSquared17
+* pjht
* Platonides
* Pmlineditor
* pmolina
* quiddity
* quietust
* Quim Gil
+* Rafid Aslam
* rahul21
* Raimond Spekking
* Ramunas Geciauskas
* Sethakill
* Sfic
* Shahyar
+* shandrenkoff
* Shane Gibbons
* Shane King
* shanika
* Shinjiman
* shirayuki
+* Shreyas Minocha
* Sidhant Gupta
* Siebrand Mazeland
* Simeon Dahl
* Steve Sanbeg
* Steven Roddis
* Steven Walling
+* stibba
* Str4nd
* Strainu
* Subin Siby
'HTMLRestrictionsField' => __DIR__ . '/includes/htmlform/fields/HTMLRestrictionsField.php',
'HTMLSelectAndOtherField' => __DIR__ . '/includes/htmlform/fields/HTMLSelectAndOtherField.php',
'HTMLSelectField' => __DIR__ . '/includes/htmlform/fields/HTMLSelectField.php',
+ 'HTMLSelectLanguageField' => __DIR__ . '/includes/htmlform/HTMLSelectLanguageField.php',
'HTMLSelectLimitField' => __DIR__ . '/includes/htmlform/fields/HTMLSelectLimitField.php',
'HTMLSelectNamespace' => __DIR__ . '/includes/htmlform/fields/HTMLSelectNamespace.php',
'HTMLSelectNamespaceWithButton' => __DIR__ . '/includes/htmlform/fields/HTMLSelectNamespaceWithButton.php',
'checkmatrix' => HTMLCheckMatrix::class,
'cloner' => HTMLFormFieldCloner::class,
'autocompleteselect' => HTMLAutoCompleteSelectField::class,
+ 'language' => HTMLSelectLanguageField::class,
'date' => HTMLDateTimeField::class,
'time' => HTMLDateTimeField::class,
'datetime' => HTMLDateTimeField::class,
--- /dev/null
+<?php
+
+/**
+ * Language select field.
+ */
+class HTMLSelectLanguageField extends HTMLSelectField {
+ public function __construct( $params ) {
+ parent::__construct( $params );
+
+ if ( $this->mParent instanceof HTMLForm ) {
+ $config = $this->mParent->getConfig();
+ $languageCode = $config->get( 'LanguageCode' );
+ } else {
+ global $wgLanguageCode;
+ $languageCode = $wgLanguageCode;
+ }
+
+ $languages = Language::fetchLanguageNames( null, 'mw' );
+
+ // Make sure the site language is in the list;
+ // a custom language code might not have a defined name…
+ if ( !array_key_exists( $languageCode, $languages ) ) {
+ $languages[$languageCode] = $languageCode;
+ }
+
+ foreach ( $languages as $code => $name ) {
+ $this->mParams['options'][$code . ' - ' . $name] = $code;
+ }
+
+ if ( !array_key_exists( 'default', $params ) ) {
+ $this->mParams['default'] = $languageCode;
+ }
+ }
+}
* @param MailAddress|MailAddress[] $to Recipient's email (or an array of them)
* @param MailAddress $from Sender's email
* @param string $subject Email's subject.
- * @param string $body Email's text or Array of two strings to be the text and html bodies
+ * @param string|string[] $body Email's text or Array of two strings to be the text and html bodies
* @param array $options Keys:
* 'replyTo' MailAddress
* 'contentType' string default 'text/plain; charset=UTF-8'
* @param MailAddress[] $to Array of recipients' email addresses
* @param MailAddress $from Sender's email
* @param string $subject Email's subject.
- * @param string $body Email's text or Array of two strings to be the text and html bodies
+ * @param string|string[] $body Email's text or Array of two strings to be the text and html bodies
* @param array $options Keys:
* 'replyTo' MailAddress
* 'contentType' string default 'text/plain; charset=UTF-8'
public function getDefaultModules() {
$modules = parent::getDefaultModules();
$modules['styles']['skin'][] = 'mediawiki.skinning.interface';
+ // There is no search box, disable 'mediawiki.searchSuggest'
+ $modules['search'] = [];
return $modules;
}
* @file
* @ingroup SpecialPage
*/
+use MediaWiki\MediaWikiServices;
/**
* Use this special page to get a list of the MediaWiki system messages.
* @ingroup SpecialPage
*/
class SpecialAllMessages extends SpecialPage {
- /**
- * @var AllMessagesTablePager
- */
- protected $table;
public function __construct() {
parent::__construct( 'Allmessages' );
* @param string $par Parameter passed to the page or null
*/
public function execute( $par ) {
- $request = $this->getRequest();
$out = $this->getOutput();
$this->setHeaders();
return;
}
- $this->outputHeader( 'allmessagestext' );
$out->addModuleStyles( 'mediawiki.special' );
$this->addHelpLink( 'Help:System message' );
- $this->table = new AllMessagesTablePager(
- $this,
- [],
- wfGetLangObj( $request->getVal( 'lang', $par ) )
- );
+ $contLang = MediaWikiServices::getInstance()->getContentLanguage()->getCode();
+ $lang = $this->getLanguage();
+
+ $opts = new FormOptions();
+
+ $opts->add( 'prefix', '' );
+ $opts->add( 'filter', 'all' );
+ $opts->add( 'lang', $contLang );
+ $opts->add( 'limit', 50 );
+
+ $opts->fetchValuesFromRequest( $this->getRequest() );
+ $opts->validateIntBounds( 'limit', 0, 5000 );
+
+ $pager = new AllMessagesTablePager( $this->getContext(), $opts );
+
+ $formDescriptor = [
+ 'prefix' => [
+ 'type' => 'text',
+ 'name' => 'prefix',
+ 'label-message' => 'allmessages-prefix',
+ ],
+
+ 'filter' => [
+ 'type' => 'radio',
+ 'name' => 'filter',
+ 'label-message' => 'allmessages-filter',
+ 'options' => [
+ $this->msg( 'allmessages-filter-unmodified' )->text() => 'unmodified',
+ $this->msg( 'allmessages-filter-all' )->text() => 'all',
+ $this->msg( 'allmessages-filter-modified' )->text() => 'modified',
+ ],
+ 'default' => 'all',
+ 'flatlist' => true,
+ ],
+
+ 'lang' => [
+ 'type' => 'language',
+ 'name' => 'lang',
+ 'label-message' => 'allmessages-language',
+ 'default' => $opts->getValue( 'lang' ),
+ ],
+
+ 'limit' => [
+ 'type' => 'limitselect',
+ 'name' => 'limit',
+ 'label-message' => 'table_pager_limit_label',
+ 'options' => [
+ $lang->formatNum( 20 ) => 20,
+ $lang->formatNum( 50 ) => 50,
+ $lang->formatNum( 100 ) => 100,
+ $lang->formatNum( 250 ) => 250,
+ $lang->formatNum( 500 ) => 500,
+ $lang->formatNum( 5000 ) => 5000,
+ ],
+ 'default' => $opts->getValue( 'limit' ),
+ ],
+ ];
+
+ $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
+ $htmlForm
+ ->setMethod( 'get' )
+ ->setIntro( $this->msg( 'allmessagestext' ) )
+ ->setWrapperLegendMsg( 'allmessages' )
+ ->setSubmitTextMsg( 'allmessages-filter-submit' )
+ ->prepareForm()
+ ->displayForm( false );
- $out->addHTML( $this->table->buildForm() );
- $out->addParserOutputContent( $this->table->getFullOutput() );
+ $out->addParserOutputContent( $pager->getFullOutput() );
}
protected function getGroupName() {
*/
class AllMessagesTablePager extends TablePager {
- protected $filter, $prefix, $langcode, $displayPrefix;
+ /**
+ * @var string
+ */
+ protected $langcode;
+
+ /**
+ * @var bool
+ */
+ protected $foreign;
- public $mLimitsShown;
+ /**
+ * @var string
+ */
+ protected $prefix;
/**
* @var Language
*/
public $custom;
- public function __construct( $page, $conds, Language $langObj = null ) {
- parent::__construct( $page->getContext() );
+ /**
+ * @param IContextSource|null $context
+ * @param FormOptions $opts
+ */
+ public function __construct( IContextSource $context = null, FormOptions $opts ) {
+ parent::__construct( $context );
+
$this->mIndexField = 'am_title';
- $this->mPage = $page;
- $this->mConds = $conds;
// FIXME: Why does this need to be set to DIR_DESCENDING to produce ascending ordering?
$this->mDefaultDirection = IndexPager::DIR_DESCENDING;
- $this->mLimitsShown = [ 20, 50, 100, 250, 500, 5000 ];
-
- $this->talk = $this->msg( 'talkpagelinktext' )->escaped();
+ $langObj = wfGetLangObj( $opts->getValue( 'lang' ) );
$contLang = MediaWikiServices::getInstance()->getContentLanguage();
$this->lang = $langObj ?? $contLang;
+
$this->langcode = $this->lang->getCode();
$this->foreign = !$this->lang->equals( $contLang );
- $request = $this->getRequest();
-
- $this->filter = $request->getVal( 'filter', 'all' );
- if ( $this->filter === 'all' ) {
+ $filter = $opts->getValue( 'filter' );
+ if ( $filter === 'all' ) {
$this->custom = null; // So won't match in either case
} else {
- $this->custom = ( $this->filter === 'unmodified' );
+ $this->custom = ( $filter === 'unmodified' );
}
- $prefix = $this->getLanguage()->ucfirst( $request->getVal( 'prefix', '' ) );
+ $prefix = $this->getLanguage()->ucfirst( $opts->getValue( 'prefix' ) );
$prefix = $prefix !== '' ?
- Title::makeTitleSafe( NS_MEDIAWIKI, $request->getVal( 'prefix', null ) ) :
+ Title::makeTitleSafe( NS_MEDIAWIKI, $opts->getValue( 'prefix' ) ) :
null;
if ( $prefix !== null ) {
- $this->displayPrefix = $prefix->getDBkey();
- $this->prefix = '/^' . preg_quote( $this->displayPrefix, '/' ) . '/i';
+ $displayPrefix = $prefix->getDBkey();
+ $this->prefix = '/^' . preg_quote( $displayPrefix, '/' ) . '/i';
} else {
- $this->displayPrefix = false;
$this->prefix = false;
}
}
}
- function buildForm() {
- $attrs = [ 'id' => 'mw-allmessages-form-lang', 'name' => 'lang' ];
- $msg = wfMessage( 'allmessages-language' );
- $langSelect = Xml::languageSelector( $this->langcode, false, null, $attrs, $msg );
-
- $out = Xml::openElement( 'form', [
- 'method' => 'get',
- 'action' => $this->getConfig()->get( 'Script' ),
- 'id' => 'mw-allmessages-form'
- ] ) .
- Xml::fieldset( $this->msg( 'allmessages-filter-legend' )->text() ) .
- Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
- Xml::openElement( 'table', [ 'class' => 'mw-allmessages-table' ] ) . "\n" .
- '<tr>
- <td class="mw-label">' .
- Xml::label( $this->msg( 'allmessages-prefix' )->text(), 'mw-allmessages-form-prefix' ) .
- "</td>\n
- <td class=\"mw-input\">" .
- Xml::input(
- 'prefix',
- 20,
- str_replace( '_', ' ', $this->displayPrefix ),
- [ 'id' => 'mw-allmessages-form-prefix' ]
- ) .
- "</td>\n
- </tr>
- <tr>\n
- <td class='mw-label'>" .
- $this->msg( 'allmessages-filter' )->escaped() .
- "</td>\n
- <td class='mw-input'>" .
- Xml::radioLabel( $this->msg( 'allmessages-filter-unmodified' )->text(),
- 'filter',
- 'unmodified',
- 'mw-allmessages-form-filter-unmodified',
- ( $this->filter === 'unmodified' )
- ) .
- Xml::radioLabel( $this->msg( 'allmessages-filter-all' )->text(),
- 'filter',
- 'all',
- 'mw-allmessages-form-filter-all',
- ( $this->filter === 'all' )
- ) .
- Xml::radioLabel( $this->msg( 'allmessages-filter-modified' )->text(),
- 'filter',
- 'modified',
- 'mw-allmessages-form-filter-modified',
- ( $this->filter === 'modified' )
- ) .
- "</td>\n
- </tr>
- <tr>\n
- <td class=\"mw-label\">" . $langSelect[0] . "</td>\n
- <td class=\"mw-input\">" . $langSelect[1] . "</td>\n
- </tr>" .
-
- '<tr>
- <td class="mw-label">' .
- Xml::label( $this->msg( 'table_pager_limit_label' )->text(), 'mw-table_pager_limit_label' ) .
- '</td>
- <td class="mw-input">' .
- $this->getLimitSelect( [ 'id' => 'mw-table_pager_limit_label' ] ) .
- '</td>
- <tr>
- <td></td>
- <td>' .
- Xml::submitButton( $this->msg( 'allmessages-filter-submit' )->text() ) .
- "</td>\n
- </tr>" .
-
- Xml::closeElement( 'table' ) .
- $this->getHiddenFields( [ 'title', 'prefix', 'filter', 'lang', 'limit' ] ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' );
-
- return $out;
- }
-
function getAllMessages( $descending ) {
$messageNames = Language::getLocalisationCache()->getSubitemList( 'en', 'messages' );
] ),
$this->msg( 'allmessages-filter-translate' )->text()
);
+ $talkLink = $this->msg( 'talkpagelinktext' )->escaped();
if ( $this->mCurrentRow->am_customised ) {
$title = $linkRenderer->makeKnownLink( $title, $this->getLanguage()->lcfirst( $value ) );
);
}
if ( $this->mCurrentRow->am_talk_exists ) {
- $talk = $linkRenderer->makeKnownLink( $talk, $this->talk );
+ $talk = $linkRenderer->makeKnownLink( $talk, $talkLink );
} else {
$talk = $linkRenderer->makeBrokenLink(
$talk,
- $this->talk
+ $talkLink
);
}
use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
use MediaWiki\Linker\LinkTarget;
use Wikimedia\Assert\Assert;
-use Wikimedia\Rdbms\LBFactory;
use Wikimedia\ScopedCallback;
use Wikimedia\Rdbms\ILBFactory;
use Wikimedia\Rdbms\LoadBalancer;
$this->addOption( 'query',
'Run a single query instead of running interactively', false, true );
$this->addOption( 'json', 'Output the results as JSON instead of PHP objects' );
+ $this->addOption( 'status', 'Return successful exit status only if the query succeeded '
+ . '(selected or altered rows), otherwise 1 for errors, 2 for no rows' );
$this->addOption( 'cluster', 'Use an external cluster by name', false, true );
$this->addOption( 'wikidb',
'The database wiki ID to use if not the current one', false, true );
if ( $this->hasOption( 'query' ) ) {
$query = $this->getOption( 'query' );
- $this->sqlDoQuery( $db, $query, /* dieOnError */ true );
+ $res = $this->sqlDoQuery( $db, $query, /* dieOnError */ true );
wfWaitForSlaves();
+ if ( $this->hasOption( 'status' ) ) {
+ exit( $res ? 0 : 2 );
+ }
return;
}
$newPrompt = '> ';
$prompt = $newPrompt;
$doDie = !Maintenance::posix_isatty( 0 );
+ $res = 1;
while ( ( $line = Maintenance::readconsole( $prompt ) ) !== false ) {
if ( !$line ) {
# User simply pressed return key
readline_add_history( $wholeLine . ';' );
readline_write_history( $historyFile );
}
- $this->sqlDoQuery( $db, $wholeLine, $doDie );
+ $res = $this->sqlDoQuery( $db, $wholeLine, $doDie );
$prompt = $newPrompt;
$wholeLine = '';
}
wfWaitForSlaves();
+ if ( $this->hasOption( 'status' ) ) {
+ exit( $res ? 0 : 2 );
+ }
}
+ /**
+ * @param IDatabase $db
+ * @param string $line The SQL text of the query
+ * @param bool $dieOnError
+ * @return int|null Number of rows selected or updated, or null if the query was unsuccessful.
+ */
protected function sqlDoQuery( IDatabase $db, $line, $dieOnError ) {
try {
$res = $db->query( $line );
- $this->sqlPrintResult( $res, $db );
+ return $this->sqlPrintResult( $res, $db );
} catch ( DBQueryError $e ) {
if ( $dieOnError ) {
$this->fatalError( $e );
$this->error( $e );
}
}
+ return null;
}
/**
* Print the results, callback for $db->sourceStream()
* @param ResultWrapper|bool $res
* @param IDatabase $db
+ * @return int|null Number of rows selected or updated, or null if the query was unsuccessful.
*/
public function sqlPrintResult( $res, $db ) {
if ( !$res ) {
// Do nothing
- return;
+ return null;
} elseif ( is_object( $res ) ) {
$out = '';
$rows = [];
$out = 'Query OK, 0 row(s) affected';
}
$this->output( $out . "\n" );
+ return count( $rows );
} else {
$affected = $db->affectedRows();
if ( $this->hasOption( 'json' ) ) {
} else {
$this->output( "Query OK, $affected row(s) affected\n" );
}
+ return $affected;
}
}
// Bind functions so they're checked whenever stuff changes
blockTargetWidget.on( 'change', updateBlockOptions );
expiryWidget.on( 'change', updateBlockOptions );
- editingRestrictionWidget.on( 'change', updateBlockOptions );
+ if ( editingRestrictionWidget ) {
+ editingRestrictionWidget.on( 'change', updateBlockOptions );
+ }
// Call them now to set initial state (ie. Special:Block/Foobar?wpBlockExpiry=2+hours)
updateBlockOptions();