'Wikimedia\\Rdbms\\Blob' => __DIR__ . '/includes/libs/rdbms/encasing/Blob.php',
'Wikimedia\\Rdbms\\ChronologyProtector' => __DIR__ . '/includes/libs/rdbms/ChronologyProtector.php',
'Wikimedia\\Rdbms\\ConnectionManager' => __DIR__ . '/includes/libs/rdbms/connectionmanager/ConnectionManager.php',
+ 'Wikimedia\\Rdbms\\DBAccessError' => __DIR__ . '/includes/libs/rdbms/exception/DBAccessError.php',
'Wikimedia\\Rdbms\\DBConnRef' => __DIR__ . '/includes/libs/rdbms/database/DBConnRef.php',
+ 'Wikimedia\\Rdbms\\DBConnectionError' => __DIR__ . '/includes/libs/rdbms/exception/DBConnectionError.php',
+ 'Wikimedia\\Rdbms\\DBError' => __DIR__ . '/includes/libs/rdbms/exception/DBError.php',
+ 'Wikimedia\\Rdbms\\DBExpectedError' => __DIR__ . '/includes/libs/rdbms/exception/DBExpectedError.php',
'Wikimedia\\Rdbms\\DBMasterPos' => __DIR__ . '/includes/libs/rdbms/database/position/DBMasterPos.php',
+ 'Wikimedia\\Rdbms\\DBQueryError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryError.php',
+ 'Wikimedia\\Rdbms\\DBReadOnlyError' => __DIR__ . '/includes/libs/rdbms/exception/DBReadOnlyError.php',
+ 'Wikimedia\\Rdbms\\DBReplicationWaitError' => __DIR__ . '/includes/libs/rdbms/exception/DBReplicationWaitError.php',
+ 'Wikimedia\\Rdbms\\DBTransactionError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionError.php',
+ 'Wikimedia\\Rdbms\\DBTransactionSizeError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionSizeError.php',
+ 'Wikimedia\\Rdbms\\DBUnexpectedError' => __DIR__ . '/includes/libs/rdbms/exception/DBUnexpectedError.php',
'Wikimedia\\Rdbms\\Database' => __DIR__ . '/includes/libs/rdbms/database/Database.php',
'Wikimedia\\Rdbms\\DatabaseDomain' => __DIR__ . '/includes/libs/rdbms/database/DatabaseDomain.php',
'Wikimedia\\Rdbms\\DatabaseMssql' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMssql.php',
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\Session\SessionManager;
use Wikimedia\ScopedCallback;
+use Wikimedia\Rdbms\DBReplicationWaitError;
// Hide compatibility functions from Doxygen
/// @cond
use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\ChronologyProtector;
use Wikimedia\Rdbms\LBFactory;
+use Wikimedia\Rdbms\DBConnectionError;
/**
* The MediaWiki class is the helper class for the index.php entry point.
use Wikimedia\Assert\Assert;
use Wikimedia\ScopedCallback;
use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\Rdbms\DBUnexpectedError;
/**
* Storage layer class for WatchedItems.
} else {
$msg = new RawMessage( '$1' );
if ( !isset( $options['code'] ) ) {
- $options['code'] = 'internal_api_error_' . get_class( $exception );
+ $class = preg_replace( '#^Wikimedia\\\Rdbms\\\#', '', get_class( $exception ) );
+ $options['code'] = 'internal_api_error_' . $class;
}
}
$params = [ wfEscapeWikiText( $exception->getMessage() ) ];
<?php
/**
- *
- *
* Created on Sep 4, 2006
*
* Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use Wikimedia\Timestamp\TimestampException;
+use Wikimedia\Rdbms\DBQueryError;
+use Wikimedia\Rdbms\DBError;
/**
* This is the main API class, used for both external and internal processing.
} else {
// Something is seriously wrong
$config = $this->getConfig();
- $code = 'internal_api_error_' . get_class( $e );
+ $class = preg_replace( '#^Wikimedia\\\Rdbms\\\#', '', get_class( $e ) );
+ $code = 'internal_api_error_' . $class;
if ( ( $e instanceof DBQueryError ) && !$config->get( 'ShowSQLErrors' ) ) {
$params = [ 'apierror-databaseerror', WebRequest::getRequestId() ];
} else {
*/
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBQueryError;
/**
* LCStore implementation which uses the standard DB functions to store data.
use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\Blob;
use Wikimedia\Rdbms\ResultWrapper;
+use Wikimedia\Rdbms\DBConnectionError;
+use Wikimedia\Rdbms\DBUnexpectedError;
/**
* @ingroup Database
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use Psr\Log\LogLevel;
+use Wikimedia\Rdbms\DBError;
/**
* Handler class for MWExceptions
* @author Aaron Schulz
*/
+use Wikimedia\Rdbms\DBConnectionError;
+use Wikimedia\Rdbms\DBError;
+use Wikimedia\Rdbms\DBReadOnlyError;
+use Wikimedia\Rdbms\DBExpectedError;
+
/**
* Class to expose exceptions to the client (API bots, users, admins using CLI scripts)
* @since 1.28
use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
/**
* Version of FileJournal that logs to a DB table
<?php
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
/**
* MySQL version of DBLockManager that supports shared locks.
* @ingroup FileAbstraction
*/
+use Wikimedia\Rdbms\DBUnexpectedError;
+
/**
* Foreign file with an accessible MediaWiki database
*
*/
use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\DBQueryError;
+use Wikimedia\Rdbms\DBConnectionError;
/**
* Class for setting up the MediaWiki database using Microsoft SQL Server.
*/
use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\DBQueryError;
+use Wikimedia\Rdbms\DBConnectionError;
/**
* Class for setting up the MediaWiki database using MySQL.
* @ingroup Deployment
*/
+use Wikimedia\Rdbms\DBConnectionError;
+
/**
* Class for setting up the MediaWiki database using Oracle.
*
*/
use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\DBQueryError;
+use Wikimedia\Rdbms\DBConnectionError;
/**
* Class for setting up the MediaWiki database using Postgres.
use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\DatabaseSqlite;
+use Wikimedia\Rdbms\DBConnectionError;
/**
* Class for setting up the MediaWiki database using SQLLite.
* @author Aaron Schulz
*/
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBConnRef;
+use Wikimedia\Rdbms\DBConnectionError;
+use Wikimedia\Rdbms\DBError;
use MediaWiki\MediaWikiServices;
use Wikimedia\ScopedCallback;
-use Wikimedia\Rdbms\DBConnRef;
/**
* Class to handle job queues stored in the DB
use Psr\Log\LoggerInterface;
use Wikimedia\ScopedCallback;
use Wikimedia\Rdbms\LBFactory;
+use Wikimedia\Rdbms\DBError;
+use Wikimedia\Rdbms\DBReplicationWaitError;
/**
* Job queue runner utility methods
* @ingroup JobQueue
*/
use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\DBReplicationWaitError;
/**
* Job for pruning recent changes
* @ingroup JobQueue
*/
use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\DBReplicationWaitError;
/**
* Job to update link tables for pages
use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
/**
* Version of LockManager based on using named/row DB locks.
<?php
+
+use Wikimedia\Rdbms\DBError;
+
/**
* PostgreSQL version of DBLockManager that supports shared locks.
* All locks are non-blocking, which avoids deadlocks.
use BagOStuff;
use HashBagOStuff;
use InvalidArgumentException;
-use DBQueryError;
-use DBUnexpectedError;
-use DBConnectionError;
-use DBReadOnlyError;
use Exception;
use RuntimeException;
namespace Wikimedia\Rdbms;
use MediaWiki;
-use DBConnectionError;
-use DBUnexpectedError;
-use DBQueryError;
use Exception;
use stdClass;
*/
namespace Wikimedia\Rdbms;
-use DBConnectionError;
-
/**
* Database abstraction object for PHP extension mysql.
*
use DateTimeZone;
use MediaWiki;
use InvalidArgumentException;
-use DBError;
-use DBExpectedError;
-use DBUnexpectedError;
-use DBConnectionError;
use Exception;
use stdClass;
namespace Wikimedia\Rdbms;
use mysqli;
-use DBConnectionError;
use IP;
/**
use Wikimedia\Timestamp\ConvertibleTimestamp;
use Wikimedia\WaitConditionLoop;
use MediaWiki;
-use DBUnexpectedError;
-use DBConnectionError;
use Exception;
/**
use PDOException;
use LockManager;
use FSLockManager;
-use DBConnectionError;
-use DBReadOnlyError;
use InvalidArgumentException;
use RuntimeException;
-use DBError;
use stdClass;
/**
namespace Wikimedia\Rdbms;
use Wikimedia\ScopedCallback;
-use DBError;
-use DBConnectionError;
-use DBUnexpectedError;
-use DBQueryError;
use Exception;
use RuntimeException;
use UnexpectedValueException;
use Exception;
use RuntimeException;
-use DBUnexpectedError;
/**
* Advanced database interface for IDatabase handles that include maintenance methods
namespace Wikimedia\Rdbms;
use Iterator;
-use DBUnexpectedError;
use stdClass;
/**
* @ingroup Database
*/
+namespace Wikimedia\Rdbms;
+
/**
* Exception class for attempted DB access
* @ingroup Database
parent::__construct( null, "Database access has been disabled." );
}
}
+
+class_alias( DBAccessError::class, 'DBAccessError' );
* @file
* @ingroup Database
*/
-use Wikimedia\Rdbms\IDatabase;
+namespace Wikimedia\Rdbms;
/**
* @ingroup Database
parent::__construct( $db, $msg );
}
}
+
+class_alias( DBConnectionError::class, 'DBConnectionError' );
* @file
* @ingroup Database
*/
-use Wikimedia\Rdbms\IDatabase;
+
+namespace Wikimedia\Rdbms;
+
+use Exception;
/**
* Database error base class
parent::__construct( $error );
}
}
+
+class_alias( DBError::class, 'DBError' );
* @file
* @ingroup Database
*/
-use Wikimedia\Rdbms\IDatabase;
+
+namespace Wikimedia\Rdbms;
+
+use MessageSpecifier;
+use ILocalizedException;
+use Message;
/**
* Base class for the more common types of database errors. These are known to occur
return Message::newFromSpecifier( $this );
}
}
+
+class_alias( DBExpectedError::class, 'DBExpectedError' );
* @file
* @ingroup Database
*/
-use Wikimedia\Rdbms\Database;
-use Wikimedia\Rdbms\IDatabase;
+
+namespace Wikimedia\Rdbms;
/**
* @ingroup Database
$this->fname = $fname;
}
}
+
+class_alias( DBQueryError::class, 'DBQueryError' );
* @ingroup Database
*/
+namespace Wikimedia\Rdbms;
+
/**
* @ingroup Database
*/
class DBReadOnlyError extends DBExpectedError {
}
+
+class_alias( DBReadOnlyError::class, 'DBReadOnlyError' );
* @ingroup Database
*/
+namespace Wikimedia\Rdbms;
+
/**
* Exception class for replica DB wait timeouts
* @ingroup Database
*/
class DBReplicationWaitError extends DBExpectedError {
}
+
+class_alias( DBReplicationWaitError::class, 'DBReplicationWaitError' );
* @ingroup Database
*/
+namespace Wikimedia\Rdbms;
+
/**
* @ingroup Database
*/
class DBTransactionError extends DBExpectedError {
}
+
+class_alias( DBTransactionError::class, 'DBTransactionError' );
+
* @ingroup Database
*/
+namespace Wikimedia\Rdbms;
+
/**
* @ingroup Database
*/
return 'transaction-duration-limit-exceeded';
}
}
+
+class_alias( DBTransactionSizeError::class, 'DBTransactionSizeError' );
* @ingroup Database
*/
+namespace Wikimedia\Rdbms;
+
/**
* @ingroup Database
*/
class DBUnexpectedError extends DBError {
}
+
+class_alias( DBUnexpectedError::class, 'DBUnexpectedError' );
namespace Wikimedia\Rdbms;
use InvalidArgumentException;
-use DBTransactionError;
-use DBReplicationWaitError;
/**
* An interface for generating database load balancers
use WANObjectCache;
use Exception;
use RuntimeException;
-use DBTransactionError;
-use DBReplicationWaitError;
/**
* An interface for generating database load balancers
*/
namespace Wikimedia\Rdbms;
-use DBError;
-use DBAccessError;
-use DBTransactionError;
-use DBExpectedError;
use Exception;
use InvalidArgumentException;
use EmptyBagOStuff;
use WANObjectCache;
use ArrayUtils;
-use DBError;
-use DBAccessError;
-use DBExpectedError;
-use DBUnexpectedError;
-use DBTransactionError;
-use DBTransactionSizeError;
-use DBConnectionError;
use InvalidArgumentException;
use RuntimeException;
use Exception;
public function getReaderIndex( $group = false, $domain = false ) {
if ( count( $this->mServers ) == 1 ) {
- # Skip the load balancing if there's only one server
+ // Skip the load balancing if there's only one server
return $this->getWriterIndex();
} elseif ( $group === false && $this->mReadIndex >= 0 ) {
- # Shortcut if generic reader exists already
+ // Shortcut if the generic reader index was already cached
return $this->mReadIndex;
}
- # Find the relevant load array
if ( $group !== false ) {
+ // Use the server weight array for this load group
if ( isset( $this->mGroupLoads[$group] ) ) {
- $nonErrorLoads = $this->mGroupLoads[$group];
+ $loads = $this->mGroupLoads[$group];
} else {
- # No loads for this group, return false and the caller can use some other group
+ // No loads for this group, return false and the caller can use some other group
$this->connLogger->info( __METHOD__ . ": no loads for group $group" );
return false;
}
} else {
- $nonErrorLoads = $this->mLoads;
+ // Use the generic load group
+ $loads = $this->mLoads;
}
- if ( !count( $nonErrorLoads ) ) {
- throw new InvalidArgumentException( "Empty server array given to LoadBalancer" );
+ // Scale the configured load ratios according to each server's load and state
+ $this->getLoadMonitor()->scaleLoads( $loads, $domain );
+
+ // Pick a server to use, accounting for weights, load, lag, and mWaitForPos
+ list( $i, $laggedReplicaMode ) = $this->pickReaderIndex( $loads, $domain );
+ if ( $i === false ) {
+ // Replica DB connection unsuccessful
+ return false;
}
- # Scale the configured load ratios according to the dynamic load if supported
- $this->getLoadMonitor()->scaleLoads( $nonErrorLoads, $domain );
+ if ( $this->mWaitForPos && $i != $this->getWriterIndex() ) {
+ // Before any data queries are run, wait for the server to catch up to the
+ // specified position. This is used to improve session consistency. Note that
+ // when LoadBalancer::waitFor() sets mWaitForPos, the waiting triggers here,
+ // so update laggedReplicaMode as needed for consistency.
+ if ( !$this->doWait( $i ) ) {
+ $laggedReplicaMode = true;
+ }
+ }
- $laggedReplicaMode = false;
+ if ( $this->mReadIndex <= 0 && $this->mLoads[$i] > 0 && $group === false ) {
+ // Cache the generic reader index for future ungrouped DB_REPLICA handles
+ $this->mReadIndex = $i;
+ // Record if the generic reader index is in "lagged replica DB" mode
+ if ( $laggedReplicaMode ) {
+ $this->laggedReplicaMode = true;
+ }
+ }
+
+ $serverName = $this->getServerName( $i );
+ $this->connLogger->debug( __METHOD__ . ": using server $serverName for group '$group'" );
+
+ return $i;
+ }
+
+ /**
+ * @param array $loads List of server weights
+ * @param string|bool $domain
+ * @return array (reader index, lagged replica mode) or false on failure
+ */
+ private function pickReaderIndex( array $loads, $domain = false ) {
+ if ( !count( $loads ) ) {
+ throw new InvalidArgumentException( "Empty server array given to LoadBalancer" );
+ }
- # No server found yet
+ /** @var $i int|bool Index of selected server */
$i = false;
- # First try quickly looking through the available servers for a server that
- # meets our criteria
- $currentLoads = $nonErrorLoads;
+ /** @var $laggedReplicaMode bool Whether server is considered lagged */
+ $laggedReplicaMode = false;
+
+ // Quickly look through the available servers for a server that meets criteria...
+ $currentLoads = $loads;
while ( count( $currentLoads ) ) {
if ( $this->mAllowLagged || $laggedReplicaMode ) {
$i = ArrayUtils::pickRandom( $currentLoads );
} else {
$i = false;
if ( $this->mWaitForPos && $this->mWaitForPos->asOfTime() ) {
- # ChronologyProtecter causes mWaitForPos to be set via sessions.
- # This triggers doWait() after connect, so it's especially good to
- # avoid lagged servers so as to avoid just blocking in that method.
+ // ChronologyProtecter sets mWaitForPos for session consistency.
+ // This triggers doWait() after connect, so it's especially good to
+ // avoid lagged servers so as to avoid excessive delay in that method.
$ago = microtime( true ) - $this->mWaitForPos->asOfTime();
- # Aim for <= 1 second of waiting (being too picky can backfire)
+ // Aim for <= 1 second of waiting (being too picky can backfire)
$i = $this->getRandomNonLagged( $currentLoads, $domain, $ago + 1 );
}
if ( $i === false ) {
- # Any server with less lag than it's 'max lag' param is preferable
+ // Any server with less lag than it's 'max lag' param is preferable
$i = $this->getRandomNonLagged( $currentLoads, $domain );
}
if ( $i === false && count( $currentLoads ) != 0 ) {
- # All replica DBs lagged. Switch to read-only mode
+ // All replica DBs lagged. Switch to read-only mode
$this->replLogger->error( "All replica DBs lagged. Switch to read-only mode" );
$i = ArrayUtils::pickRandom( $currentLoads );
$laggedReplicaMode = true;
}
if ( $i === false ) {
- # pickRandom() returned false
- # This is permanent and means the configuration or the load monitor
- # wants us to return false.
+ // pickRandom() returned false.
+ // This is permanent and means the configuration or the load monitor
+ // wants us to return false.
$this->connLogger->debug( __METHOD__ . ": pickRandom() returned false" );
- return false;
+ return [ false, false ];
}
$serverName = $this->getServerName( $i );
$conn = $this->openConnection( $i, $domain );
if ( !$conn ) {
$this->connLogger->warning( __METHOD__ . ": Failed connecting to $i/$domain" );
- unset( $nonErrorLoads[$i] );
- unset( $currentLoads[$i] );
+ unset( $currentLoads[$i] ); // avoid this server next iteration
$i = false;
continue;
}
$this->reuseConnection( $conn );
}
- # Return this server
+ // Return this server
break;
}
- # If all servers were down, quit now
- if ( !count( $nonErrorLoads ) ) {
+ // If all servers were down, quit now
+ if ( !count( $currentLoads ) ) {
$this->connLogger->error( "All servers down" );
}
- if ( $i !== false ) {
- # Replica DB connection successful.
- # Wait for the session master pos for a short time.
- if ( $this->mWaitForPos && $i > 0 ) {
- # When LoadBalancer::waitFor() set mWaitForPos, the wait will happen here.
- # Be sure to update laggedReplicaMode accordingly for consistency.
- if ( !$this->doWait( $i ) ) {
- $laggedReplicaMode = true;
- }
- }
- if ( $this->mReadIndex <= 0 && $this->mLoads[$i] > 0 && $group === false ) {
- $this->mReadIndex = $i;
- # Record if the generic reader index is in "lagged replica DB" mode
- if ( $laggedReplicaMode ) {
- $this->laggedReplicaMode = true;
- }
- }
- $serverName = $this->getServerName( $i );
- $this->connLogger->debug(
- __METHOD__ . ": using server $serverName for group '$group'" );
- }
-
- return $i;
+ return [ $i, $laggedReplicaMode ];
}
public function waitFor( $pos ) {
use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
+use Wikimedia\Rdbms\DBQueryError;
+use Wikimedia\Rdbms\DBConnectionError;
use \MediaWiki\MediaWikiServices;
use \Wikimedia\WaitConditionLoop;
use \Wikimedia\Rdbms\TransactionProfiler;
use \MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\FakeResultWrapper;
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
+use Wikimedia\Rdbms\DBUnexpectedError;
/**
* Class representing a MediaWiki article and history.
* @ingroup Profiler
*/
+use Wikimedia\Rdbms\DBError;
+
/**
* Logs profiling data into the local DB
*
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use WrappedString\WrappedString;
+use Wikimedia\Rdbms\DBConnectionError;
/**
* Dynamic JavaScript and CSS resource loading system.
use Wikimedia\Rdbms\ResultWrapper;
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
/**
* This is a class for doing query pages; since they're almost all the same,
use MediaWiki\Auth\AuthenticationRequest;
use Wikimedia\ScopedCallback;
use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\DBExpectedError;
/**
* String Some punctuation to prevent editing from broken text-mangling proxies.
require_once __DIR__ . '/../includes/PHPVersionCheck.php';
wfEntryPointCheck( 'cli' );
+use Wikimedia\Rdbms\DBReplicationWaitError;
+
/**
* @defgroup MaintenanceArchive Maintenance archives
* @ingroup Maintenance
* @ingroup Maintenance
*/
+use Wikimedia\Rdbms\DBQueryError;
+
/**
* When using shared tables that are referenced by foreign keys on local
* tables you have to change the constraints on local tables.
use Wikimedia\Rdbms\ResultWrapper;
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBQueryError;
/**
* Maintenance script that sends SQL queries from the specified file to the database.
*/
use Wikimedia\Rdbms\DatabaseSqlite;
+use Wikimedia\Rdbms\DBError;
/**
* This class contains code common to different SQLite-related maintenance scripts
* @see wfWaitForSlaves()
*/
+use Wikimedia\Rdbms\DBConnectionError;
+
require __DIR__ . '/../commandLine.inc';
if ( count( $args ) < 1 ) {
z-index: auto;
max-width: 650px;
+ &.oo-ui-menuSelectWidget-invisible {
+ display: block;
+ }
+
+ &-noresults {
+ display: none;
+ padding: 0.5em;
+ color: #666;
+
+ .oo-ui-menuSelectWidget-invisible & {
+ display: inline-block;
+ }
+ }
+
&-body {
max-height: 70vh;
}
.mw-rcfilters-ui-filterTagMultiselectWidget {
max-width: none;
+ .oo-ui-tagMultiselectWidget-input input {
+ // Make sure this uses the interface direction, not the content direction
+ direction: ltr;
+ }
+
&.oo-ui-widget-enabled .oo-ui-tagMultiselectWidget-handle {
border: 1px solid #a2a9b1;
border-bottom: 0;
width: 100%;
// Make sure this uses the interface direction, not the content direction
direction: ltr;
-
- &-search {
- max-width: none;
- margin-top: -1px;
-
- input {
- // We need to reiterate the directionality
- // for the input as well to literally override
- // a MediaWiki CSS rule that turns it 'ltr'
- direction: ltr;
- }
- }
}
}
);
+ this.noResults = new OO.ui.LabelWidget( {
+ label: mw.msg( 'rcfilters-filterlist-noresults' ),
+ classes: [ 'mw-rcfilters-ui-filterFloatingMenuSelectWidget-noresults' ]
+ } );
+
this.$element
.addClass( 'mw-rcfilters-ui-filterFloatingMenuSelectWidget' )
.append(
this.$body
- .append( header.$element, this.$group )
+ .append( header.$element, this.$group, this.noResults.$element )
);
if ( this.$footer ) {
*/
mw.rcfilters.ui.FilterTagMultiselectWidget.prototype.onTagSelect = function ( tagItem ) {
var widget = this,
- menuOption = this.menu.getItemFromData( tagItem.getData() );
+ menuOption = this.menu.getItemFromData( tagItem.getData() ),
+ oldInputValue = this.input.getValue();
// Reset input
this.input.setValue( '' );
this.menu.selectItem( menuOption );
// Scroll to the item
- // We're binding a 'once' to the itemVisibilityChange event
- // so this happens when the menu is ready after the items
- // are visible again, in case this is done right after the
- // user filtered the results
- this.getMenu().once(
- 'itemVisibilityChange',
- function () { widget.scrollToTop( menuOption.$element ); }
- );
+ if ( oldInputValue ) {
+ // We're binding a 'once' to the itemVisibilityChange event
+ // so this happens when the menu is ready after the items
+ // are visible again, in case this is done right after the
+ // user filtered the results
+ this.getMenu().once(
+ 'itemVisibilityChange',
+ function () { widget.scrollToTop( menuOption.$element ); }
+ );
+ } else {
+ this.scrollToTop( menuOption.$element );
+ }
};
/**