the SQL query. The ActorMigration class may also be used to get feature-flagged
information needed to access actor-related fields during the migration
period.
+* Added Wikimedia\Rdbms\IDatabase::cancelAtomic(), to roll back an atomic
+ section without having to roll back the whole transaction.
+* Wikimedia\Rdbms\IDatabase::doAtomicSection(), non-native ::insertSelect(),
+ and non-MySQL ::replace() and ::upsert() no longer roll back the whole
+ transaction on failure.
=== External library changes in 1.31 ===
* The global function wfOutputHandler() was removed, use the its replacement
MediaWiki\OutputHandler::handle() instead. The global function was only sometimes defined.
Its replacement is always available via the autoloader.
+* ChangeTags::listExtensionActivatedTags and ::listExtensionDefinedTags, deprecated
+ in 1.28, have been removed. Use ::listSoftwareActivatedTags() and
+ ::listSoftwareDefinedTags() instead.
== Compatibility ==
MediaWiki 1.31 requires PHP 5.5.9 or later. Although HHVM 3.18.5 or later is supported,
'CleanupUsersWithNoId' => __DIR__ . '/maintenance/cleanupUsersWithNoId.php',
'ClearInterwikiCache' => __DIR__ . '/maintenance/clearInterwikiCache.php',
'ClearUserWatchlistJob' => __DIR__ . '/includes/jobqueue/jobs/ClearUserWatchlistJob.php',
+ 'ClearWatchlistNotificationsJob' => __DIR__ . '/includes/jobqueue/jobs/ClearWatchlistNotificationsJob.php',
'CliInstaller' => __DIR__ . '/includes/installer/CliInstaller.php',
'CloneDatabase' => __DIR__ . '/includes/db/CloneDatabase.php',
'CodeCleanerGlobalsPass' => __DIR__ . '/maintenance/CodeCleanerGlobalsPass.inc',
"ext-xml": "*",
"liuggio/statsd-php-client": "1.0.18",
"mediawiki/at-ease": "1.2.0",
- "oojs/oojs-ui": "0.26.0",
+ "oojs/oojs-ui": "0.26.1",
"oyejorge/less.php": "1.7.0.14",
"php": ">=5.5.9",
"psr/log": "1.0.2",
'categoryMembershipChange' => CategoryMembershipChangeJob::class,
'clearUserWatchlist' => ClearUserWatchlistJob::class,
'cdnPurge' => CdnPurgeJob::class,
- 'enqueue' => EnqueueJob::class, // local queue for multi-DC setups
'userGroupExpiry' => UserGroupExpiryJob::class,
+ 'clearWatchlistNotifications' => ClearWatchlistNotificationsJob::class,
+ 'enqueue' => EnqueueJob::class, // local queue for multi-DC setups
'null' => NullJob::class,
];
}
/**
- * Wrap status errors in an errorbox for increased visiblity
+ * Wrap status errors in an errorbox for increased visibility
*
* @param Status $status
* @return string Wikitext
<?php
namespace MediaWiki;
+use ActorMigration;
use CommentStore;
use Config;
use ConfigFactory;
$res['id'] = $block->getId();
} else {
# should be unreachable
- $res['expiry'] = '';
- $res['id'] = '';
+ $res['expiry'] = ''; // @codeCoverageIgnore
+ $res['id'] = ''; // @codeCoverageIgnore
}
$res['reason'] = $params['reason'];
$hasHistory = false;
$reason = $page->getAutoDeleteReason( $hasHistory );
if ( $reason === false ) {
- return Status::newFatal( 'cannotdelete', $title->getPrefixedText() );
+ // Should be reachable only if the page has no revisions
+ return Status::newFatal( 'cannotdelete', $title->getPrefixedText() ); // @codeCoverageIgnore
}
}
$userIter = call_user_func( function () use ( $dbSecondary, $sort, $op, $fname ) {
global $wgActorTableSchemaMigrationStage;
- $from = $fromName = false;
+ $fromName = false;
if ( !is_null( $this->params['continue'] ) ) {
$continue = explode( '|', $this->params['continue'] );
$this->dieContinueUsageIf( count( $continue ) != 4 );
$this->dieContinueUsageIf( $continue[0] !== 'name' );
$fromName = $continue[1];
- $from = "$op= " . $dbSecondary->addQuotes( $fromName );
}
$like = $dbSecondary->buildLike( $this->params['userprefix'], $dbSecondary->anyString() );
$limit = 501;
do {
+ $from = $fromName ? "$op= " . $dbSecondary->addQuotes( $fromName ) : false;
+
// For the new schema, pull from the actor table. For the
// old, pull from rev_user. For migration a FULL [OUTER]
// JOIN would be what we want, except MySQL doesn't support
}
$count = 0;
- $from = null;
+ $fromName = false;
foreach ( $res as $row ) {
if ( ++$count >= $limit ) {
- $from = $row->user_name;
+ $fromName = $row->user_name;
break;
}
yield User::newFromRow( $row );
}
- } while ( $from !== null );
+ } while ( $fromName !== false );
} );
// Do the actual sorting client-side, because otherwise
// prepareQuery might try to sort by actor and confuse everything.
);
}
- /**
- * @see listSoftwareActivatedTags
- * @deprecated since 1.28 call listSoftwareActivatedTags directly
- * @return array
- */
- public static function listExtensionActivatedTags() {
- wfDeprecated( __METHOD__, '1.28' );
- return self::listSoftwareActivatedTags();
- }
-
/**
* Basically lists defined tags which count even if they aren't applied to anything.
- * It returns a union of the results of listExplicitlyDefinedTags() and
- * listExtensionDefinedTags().
+ * It returns a union of the results of listExplicitlyDefinedTags()
*
* @return string[] Array of strings: tags
*/
);
}
- /**
- * Call listSoftwareDefinedTags directly
- *
- * @see listSoftwareDefinedTags
- * @deprecated since 1.28
- * @return array
- */
- public static function listExtensionDefinedTags() {
- wfDeprecated( __METHOD__, '1.28' );
- return self::listSoftwareDefinedTags();
- }
-
/**
* Invalidates the short-term cache of defined tags used by the
* list*DefinedTags functions, as well as the tag statistics cache.
[ 'log_timestamp', 'timestamptz_ops', 'btree', 0 ],
],
'CREATE INDEX "logging_times" ON "logging" USING "btree" ("log_timestamp")' ],
- [ 'dropIndex', 'oldimage', 'oi_name' ],
+ [ 'dropPgIndex', 'oldimage', 'oi_name' ],
[ 'checkIndex', 'oi_name_archive_name', [
[ 'oi_name', 'text_ops', 'btree', 0 ],
[ 'oi_archive_name', 'text_ops', 'btree', 0 ],
[ 'checkOiNameConstraint' ],
[ 'checkPageDeletedTrigger' ],
[ 'checkRevUserFkey' ],
- [ 'dropIndex', 'ipblocks', 'ipb_address' ],
+ [ 'dropPgIndex', 'ipblocks', 'ipb_address' ],
[ 'checkIndex', 'ipb_address_unique', [
[ 'ipb_address', 'text_ops', 'btree', 0 ],
[ 'ipb_user', 'int4_ops', 'btree', 0 ],
}
}
- protected function dropIndex( $table, $index, $patch = '', $fullpath = false ) {
+ protected function dropPgIndex( $table, $index ) {
if ( $this->db->indexExists( $table, $index ) ) {
$this->output( "Dropping obsolete index '$index'\n" );
$this->db->query( "DROP INDEX \"" . $index . "\"" );
"config-extensions": "Olekeni",
"config-skins": "Temey",
"config-install-step-done": "qeyd ke",
- "config-install-step-failed": "nêbı",
+ "config-install-step-failed": "ebe ser nêkewt",
"config-install-schema": "Şema dek",
"config-install-pg-commit": "Vırnayışa cemaati",
"config-install-tables": "Tabloy dek",
/**
* Job for updating user activity like "last viewed" timestamps
*
+ * Job parameters include:
+ * - type: one of (updateWatchlistNotification) [required]
+ * - userid: affected user ID [required]
+ * - notifTime: timestamp to set watchlist entries to [required]
+ * - curTime: UNIX timestamp of the event that triggered this job [required]
+ *
* @ingroup JobQueue
* @since 1.26
*/
function __construct( Title $title, array $params ) {
parent::__construct( 'activityUpdateJob', $title, $params );
- if ( !isset( $params['type'] ) ) {
- throw new InvalidArgumentException( "Missing 'type' parameter." );
+ static $required = [ 'type', 'userid', 'notifTime', 'curTime' ];
+ $missing = implode( ', ', array_diff( $required, array_keys( $this->params ) ) );
+ if ( $missing != '' ) {
+ throw new InvalidArgumentException( "Missing paramter(s) $missing" );
}
$this->removeDuplicates = true;
if ( $this->params['type'] === 'updateWatchlistNotification' ) {
$this->updateWatchlistNotification();
} else {
- throw new InvalidArgumentException(
- "Invalid 'type' parameter '{$this->params['type']}'." );
+ throw new InvalidArgumentException( "Invalid 'type' '{$this->params['type']}'." );
}
return true;
--- /dev/null
+<?php
+/**
+ * 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 JobQueue
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Job for clearing all of the "last viewed" timestamps for a user's watchlist
+ *
+ * Job parameters include:
+ * - userId: affected user ID [required]
+ * - casTime: UNIX timestamp of the event that triggered this job [required]
+ *
+ * @ingroup JobQueue
+ * @since 1.31
+ */
+class ClearWatchlistNotificationsJob extends Job {
+ function __construct( Title $title, array $params ) {
+ parent::__construct( 'clearWatchlistNotifications', $title, $params );
+
+ static $required = [ 'userId', 'casTime' ];
+ $missing = implode( ', ', array_diff( $required, array_keys( $this->params ) ) );
+ if ( $missing != '' ) {
+ throw new InvalidArgumentException( "Missing paramter(s) $missing" );
+ }
+
+ $this->removeDuplicates = true;
+ }
+
+ public function run() {
+ $services = MediaWikiServices::getInstance();
+ $lbFactory = $services->getDBLoadBalancerFactory();
+ $rowsPerQuery = $services->getMainConfig()->get( 'UpdateRowsPerQuery' );
+
+ $dbw = $lbFactory->getMainLB()->getConnection( DB_MASTER );
+ $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
+
+ $asOfTimes = array_unique( $dbw->selectFieldValues(
+ 'watchlist',
+ 'wl_notificationtimestamp',
+ [ 'wl_user' => $this->params['userId'], 'wl_notificationtimestamp IS NOT NULL' ],
+ __METHOD__,
+ [ 'ORDER BY' => 'wl_notificationtimestamp DESC' ]
+ ) );
+
+ foreach ( array_chunk( $asOfTimes, $rowsPerQuery ) as $asOfTimeBatch ) {
+ $dbw->update(
+ 'watchlist',
+ [ 'wl_notificationtimestamp' => null ],
+ [
+ 'wl_user' => $this->params['userId'],
+ 'wl_notificationtimestamp' => $asOfTimeBatch,
+ // New notifications since the reset should not be cleared
+ 'wl_notificationtimestamp < ' .
+ $dbw->addQuotes( $dbw->timestamp( $this->params['casTime'] ) )
+ ],
+ __METHOD__
+ );
+ $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
+ }
+ }
+}
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function fieldInfo( $table, $field ) {
- return $this->__call( __FUNCTION__, func_get_args() );
- }
-
public function affectedRows() {
return $this->__call( __FUNCTION__, func_get_args() );
}
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function reportConnectionError( $error = 'Unknown error' ) {
- return $this->__call( __FUNCTION__, func_get_args() );
- }
-
public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- return $this->__call( __FUNCTION__, func_get_args() );
- }
-
public function freeResult( $res ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function indexUnique( $table, $index ) {
- return $this->__call( __FUNCTION__, func_get_args() );
- }
-
public function insert( $table, $a, $fname = __METHOD__, $options = [] ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function startAtomic( $fname = __METHOD__ ) {
+ public function startAtomic(
+ $fname = __METHOD__, $cancelable = IDatabase::ATOMIC_NOT_CANCELABLE
+ ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
return $this->__call( __FUNCTION__, func_get_args() );
}
+ public function cancelAtomic( $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
public function doAtomicSection( $fname, callable $callback ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function listTables( $prefix = null, $fname = __METHOD__ ) {
- return $this->__call( __FUNCTION__, func_get_args() );
- }
-
public function timestamp( $ts = 0 ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
* @see Database::trxLevel
*/
private $trxAutomatic = false;
+ /**
+ * Counter for atomic savepoint identifiers. Reset when a new transaction begins.
+ *
+ * @var int
+ */
+ private $trxAtomicCounter = 0;
/**
* Array of levels of atomicity within transactions
*
return $res;
}
- /**
- * Turns on (false) or off (true) the automatic generation and sending
- * of a "we're sorry, but there has been a database error" page on
- * database errors. Default is on (false). When turned off, the
- * code should use lastErrno() and lastError() to handle the
- * situation as appropriate.
- *
- * Do not use this function outside of the Database classes.
- *
- * @param null|bool $ignoreErrors
- * @return bool The previous value of the flag.
- */
- protected function ignoreErrors( $ignoreErrors = null ) {
- $res = $this->getFlag( self::DBO_IGNORE );
- if ( $ignoreErrors !== null ) {
- // setFlag()/clearFlag() do not allow DBO_IGNORE changes for sanity
- if ( $ignoreErrors ) {
- $this->flags |= self::DBO_IGNORE;
- } else {
- $this->flags &= ~self::DBO_IGNORE;
- }
- }
-
- return $res;
- }
-
public function trxLevel() {
return $this->trxLevel;
}
*/
abstract protected function closeConnection();
+ /**
+ * @param string $error Fallback error message, used if none is given by DB
+ * @throws DBConnectionError
+ */
public function reportConnectionError( $error = 'Unknown error' ) {
$myError = $this->lastError();
if ( $myError ) {
*/
private function handleSessionLoss() {
$this->trxLevel = 0;
+ $this->trxAtomicCounter = 0;
$this->trxIdleCallbacks = []; // T67263; transaction already lost
$this->trxPreCommitCallbacks = []; // T67263; transaction already lost
$this->sessionTempTables = [];
return false;
}
+ /**
+ * Report a query error. Log the error, and if neither the object ignore
+ * flag nor the $tempIgnore flag is set, throw a DBQueryError.
+ *
+ * @param string $error
+ * @param int $errno
+ * @param string $sql
+ * @param string $fname
+ * @param bool $tempIgnore
+ * @throws DBQueryError
+ */
public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- if ( $this->ignoreErrors() || $tempIgnore ) {
+ if ( $this->getFlag( self::DBO_IGNORE ) || $tempIgnore ) {
$this->queryLogger->debug( "SQL ERROR (ignored): $error\n" );
} else {
$sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
}
try {
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
$affectedRowCount = 0;
foreach ( $rows as $row ) {
// Delete rows which collide with this one
$this->endAtomic( $fname );
$this->affectedRowCount = $affectedRowCount;
} catch ( Exception $e ) {
- $this->rollback( $fname, self::FLUSHING_INTERNAL );
+ $this->cancelAtomic( $fname );
throw $e;
}
}
$affectedRowCount = 0;
try {
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
# Update any existing conflicting row(s)
if ( $where !== false ) {
$ok = $this->update( $table, $set, $where, $fname );
$this->endAtomic( $fname );
$this->affectedRowCount = $affectedRowCount;
} catch ( Exception $e ) {
- $this->rollback( $fname, self::FLUSHING_INTERNAL );
+ $this->cancelAtomic( $fname );
throw $e;
}
try {
$affectedRowCount = 0;
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
$rows = [];
$ok = true;
foreach ( $res as $row ) {
$this->endAtomic( $fname );
$this->affectedRowCount = $affectedRowCount;
} else {
- $this->rollback( $fname, self::FLUSHING_INTERNAL );
+ $this->cancelAtomic( $fname );
}
return $ok;
} catch ( Exception $e ) {
- $this->rollback( $fname, self::FLUSHING_INTERNAL );
+ $this->cancelAtomic( $fname );
throw $e;
}
}
$this->trxPreCommitCallbacks[] = [ $callback, $fname ];
} else {
// No transaction is active nor will start implicitly, so make one for this callback
- $this->startAtomic( __METHOD__ );
+ $this->startAtomic( __METHOD__, self::ATOMIC_CANCELABLE );
try {
call_user_func( $callback );
$this->endAtomic( __METHOD__ );
} catch ( Exception $e ) {
- $this->rollback( __METHOD__, self::FLUSHING_INTERNAL );
+ $this->cancelAtomic( __METHOD__ );
throw $e;
}
}
}
}
- final public function startAtomic( $fname = __METHOD__ ) {
+ /**
+ * Create a savepoint
+ *
+ * This is used internally to implement atomic sections. It should not be
+ * used otherwise.
+ *
+ * @since 1.31
+ * @param string $identifier Identifier for the savepoint
+ * @param string $fname Calling function name
+ */
+ protected function doSavepoint( $identifier, $fname ) {
+ $this->query( 'SAVEPOINT ' . $this->addIdentifierQuotes( $identifier ), $fname );
+ }
+
+ /**
+ * Release a savepoint
+ *
+ * This is used internally to implement atomic sections. It should not be
+ * used otherwise.
+ *
+ * @since 1.31
+ * @param string $identifier Identifier for the savepoint
+ * @param string $fname Calling function name
+ */
+ protected function doReleaseSavepoint( $identifier, $fname ) {
+ $this->query( 'RELEASE SAVEPOINT ' . $this->addIdentifierQuotes( $identifier ), $fname );
+ }
+
+ /**
+ * Rollback to a savepoint
+ *
+ * This is used internally to implement atomic sections. It should not be
+ * used otherwise.
+ *
+ * @since 1.31
+ * @param string $identifier Identifier for the savepoint
+ * @param string $fname Calling function name
+ */
+ protected function doRollbackToSavepoint( $identifier, $fname ) {
+ $this->query( 'ROLLBACK TO SAVEPOINT ' . $this->addIdentifierQuotes( $identifier ), $fname );
+ }
+
+ final public function startAtomic(
+ $fname = __METHOD__, $cancelable = self::ATOMIC_NOT_CANCELABLE
+ ) {
+ $savepointId = $cancelable === self::ATOMIC_CANCELABLE ? 'n/a' : null;
if ( !$this->trxLevel ) {
$this->begin( $fname, self::TRANSACTION_INTERNAL );
// If DBO_TRX is set, a series of startAtomic/endAtomic pairs will result
if ( !$this->getFlag( self::DBO_TRX ) ) {
$this->trxAutomaticAtomic = true;
}
+ } elseif ( $cancelable === self::ATOMIC_CANCELABLE ) {
+ $savepointId = 'wikimedia_rdbms_atomic' . ++$this->trxAtomicCounter;
+ if ( strlen( $savepointId ) > 30 ) { // 30 == Oracle's identifier length limit (pre 12c)
+ $this->queryLogger->warning(
+ 'There have been an excessively large number of atomic sections in a transaction'
+ . " started by $this->trxFname, reusing IDs (at $fname)",
+ [ 'trace' => ( new RuntimeException() )->getTraceAsString() ]
+ );
+ $this->trxAtomicCounter = 0;
+ $savepointId = 'wikimedia_rdbms_atomic' . ++$this->trxAtomicCounter;
+ }
+ $this->doSavepoint( $savepointId, $fname );
}
- $this->trxAtomicLevels[] = $fname;
+ $this->trxAtomicLevels[] = [ $fname, $savepointId ];
}
final public function endAtomic( $fname = __METHOD__ ) {
if ( !$this->trxLevel ) {
throw new DBUnexpectedError( $this, "No atomic transaction is open (got $fname)." );
}
- if ( !$this->trxAtomicLevels ||
- array_pop( $this->trxAtomicLevels ) !== $fname
- ) {
+
+ list( $savedFname, $savepointId ) = $this->trxAtomicLevels
+ ? array_pop( $this->trxAtomicLevels ) : [ null, null ];
+ if ( $savedFname !== $fname ) {
throw new DBUnexpectedError( $this, "Invalid atomic section ended (got $fname)." );
}
if ( !$this->trxAtomicLevels && $this->trxAutomaticAtomic ) {
$this->commit( $fname, self::FLUSHING_INTERNAL );
+ } elseif ( $savepointId && $savepointId !== 'n/a' ) {
+ $this->doReleaseSavepoint( $savepointId, $fname );
}
}
+ final public function cancelAtomic( $fname = __METHOD__ ) {
+ if ( !$this->trxLevel ) {
+ throw new DBUnexpectedError( $this, "No atomic transaction is open (got $fname)." );
+ }
+
+ list( $savedFname, $savepointId ) = $this->trxAtomicLevels
+ ? array_pop( $this->trxAtomicLevels ) : [ null, null ];
+ if ( $savedFname !== $fname ) {
+ throw new DBUnexpectedError( $this, "Invalid atomic section ended (got $fname)." );
+ }
+ if ( !$savepointId ) {
+ throw new DBUnexpectedError( $this, "Uncancelable atomic section canceled (got $fname)." );
+ }
+
+ if ( !$this->trxAtomicLevels && $this->trxAutomaticAtomic ) {
+ $this->rollback( $fname, self::FLUSHING_INTERNAL );
+ } elseif ( $savepointId !== 'n/a' ) {
+ $this->doRollbackToSavepoint( $savepointId, $fname );
+ }
+
+ $this->affectedRowCount = 0; // for the sake of consistency
+ }
+
final public function doAtomicSection( $fname, callable $callback ) {
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
try {
$res = call_user_func_array( $callback, [ $this, $fname ] );
} catch ( Exception $e ) {
- $this->rollback( $fname, self::FLUSHING_INTERNAL );
+ $this->cancelAtomic( $fname );
throw $e;
}
$this->endAtomic( $fname );
// Protect against mismatched atomic section, transaction nesting, and snapshot loss
if ( $this->trxLevel ) {
if ( $this->trxAtomicLevels ) {
- $levels = implode( ', ', $this->trxAtomicLevels );
+ $levels = array_reduce( $this->trxAtomicLevels, function ( $accum, $v ) {
+ return $accum === null ? $v[0] : "$accum, " . $v[0];
+ } );
$msg = "$fname: Got explicit BEGIN while atomic section(s) $levels are open.";
throw new DBUnexpectedError( $this, $msg );
} elseif ( !$this->trxAutomatic ) {
$this->assertOpen();
$this->doBegin( $fname );
+ $this->trxAtomicCounter = 0;
$this->trxTimestamp = microtime( true );
$this->trxFname = $fname;
$this->trxDoneWrites = false;
final public function commit( $fname = __METHOD__, $flush = '' ) {
if ( $this->trxLevel && $this->trxAtomicLevels ) {
// There are still atomic sections open. This cannot be ignored
- $levels = implode( ', ', $this->trxAtomicLevels );
+ $levels = array_reduce( $this->trxAtomicLevels, function ( $accum, $v ) {
+ return $accum === null ? $v[0] : "$accum, " . $v[0];
+ } );
throw new DBUnexpectedError(
$this,
"$fname: Got COMMIT while atomic sections $levels are still open."
}
final public function rollback( $fname = __METHOD__, $flush = '' ) {
- if ( $flush === self::FLUSHING_INTERNAL || $flush === self::FLUSHING_ALL_PEERS ) {
- if ( !$this->trxLevel ) {
- return; // nothing to do
- }
- } else {
- if ( !$this->trxLevel ) {
- $this->queryLogger->error(
- "$fname: No transaction to rollback, something got out of sync." );
- return; // nothing to do
- } elseif ( $this->getFlag( self::DBO_TRX ) ) {
+ $trxActive = $this->trxLevel;
+
+ if ( $flush !== self::FLUSHING_INTERNAL && $flush !== self::FLUSHING_ALL_PEERS ) {
+ if ( $this->getFlag( self::DBO_TRX ) ) {
throw new DBUnexpectedError(
$this,
"$fname: Expected mass rollback of all peer transactions (DBO_TRX set)."
}
}
- // Avoid fatals if close() was called
- $this->assertOpen();
+ if ( $trxActive ) {
+ // Avoid fatals if close() was called
+ $this->assertOpen();
- $this->doRollback( $fname );
- $this->trxAtomicLevels = [];
- if ( $this->trxDoneWrites ) {
- $this->trxProfiler->transactionWritingOut(
- $this->server,
- $this->dbName,
- $this->trxShortId
- );
+ $this->doRollback( $fname );
+ $this->trxAtomicLevels = [];
+ if ( $this->trxDoneWrites ) {
+ $this->trxProfiler->transactionWritingOut(
+ $this->server,
+ $this->dbName,
+ $this->trxShortId
+ );
+ }
}
- $this->trxIdleCallbacks = []; // clear
- $this->trxPreCommitCallbacks = []; // clear
- try {
- $this->runOnTransactionIdleCallbacks( self::TRIGGER_ROLLBACK );
- } catch ( Exception $e ) {
- // already logged; finish and let LoadBalancer move on during mass-rollback
- }
- try {
- $this->runTransactionListenerCallbacks( self::TRIGGER_ROLLBACK );
- } catch ( Exception $e ) {
- // already logged; let LoadBalancer move on during mass-rollback
- }
+ // Clear any commit-dependant callbacks. They might even be present
+ // only due to transaction rounds, with no SQL transaction being active
+ $this->trxIdleCallbacks = [];
+ $this->trxPreCommitCallbacks = [];
- $this->affectedRowCount = 0; // for the sake of consistency
+ if ( $trxActive ) {
+ try {
+ $this->runOnTransactionIdleCallbacks( self::TRIGGER_ROLLBACK );
+ } catch ( Exception $e ) {
+ // already logged; finish and let LoadBalancer move on during mass-rollback
+ }
+ try {
+ $this->runTransactionListenerCallbacks( self::TRIGGER_ROLLBACK );
+ } catch ( Exception $e ) {
+ // already logged; let LoadBalancer move on during mass-rollback
+ }
+
+ $this->affectedRowCount = 0; // for the sake of consistency
+ }
}
/**
return false;
}
+ protected function doSavepoint( $identifier, $fname ) {
+ $this->query( 'SAVE TRANSACTION ' . $this->addIdentifierQuotes( $identifier ), $fname );
+ }
+
+ protected function doReleaseSavepoint( $identifier, $fname ) {
+ // Not supported. Also not really needed, a new doSavepoint() for the
+ // same identifier will overwrite the old.
+ }
+
+ protected function doRollbackToSavepoint( $identifier, $fname ) {
+ $this->query( 'ROLLBACK TRANSACTION ' . $this->addIdentifierQuotes( $identifier ), $fname );
+ }
+
/**
* Begin a transaction, committing any previously open transaction
* @param string $fname
/** @var stdClass|null */
private $replicationInfoRow = null;
+ // Cache getServerId() for 24 hours
+ const SERVER_ID_CACHE_TTL = 86400;
+
/**
* Additional $params include:
* - lagDetectionMethod : set to one of (Seconds_Behind_Master,pt-heartbeat).
}
// Wait on the GTID set (MariaDB only)
$gtidArg = $this->addQuotes( implode( ',', $gtidsWait ) );
- $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" );
+ if ( strpos( $gtidArg, ':' ) !== false ) {
+ // MySQL GTIDs, e.g "source_id:transaction_id"
+ $res = $this->doQuery( "SELECT WAIT_FOR_EXECUTED_GTID_SET($gtidArg, $timeout)" );
+ } else {
+ // MariaDB GTIDs, e.g."domain:server:sequence"
+ $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" );
+ }
} else {
// Wait on the binlog coordinates
$encFile = $this->addQuotes( $pos->getLogFile() );
- $encPos = intval( $pos->pos[1] );
+ $encPos = intval( $pos->getLogPosition()[$pos::CORD_EVENT] );
$res = $this->doQuery( "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)" );
}
$row = $res ? $this->fetchRow( $res ) : false;
if ( !$row ) {
- throw new DBExpectedError( $this,
- "MASTER_POS_WAIT() or MASTER_GTID_WAIT() failed: {$this->lastError()}" );
+ throw new DBExpectedError( $this, "Replication wait failed: {$this->lastError()}" );
}
// Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
* @return MySQLMasterPos|bool
*/
public function getReplicaPos() {
- $now = microtime( true );
-
- if ( $this->useGTIDs ) {
- $res = $this->query( "SELECT @@global.gtid_slave_pos AS Value", __METHOD__ );
- $gtidRow = $this->fetchObject( $res );
- if ( $gtidRow && strlen( $gtidRow->Value ) ) {
- return new MySQLMasterPos( $gtidRow->Value, $now );
+ $now = microtime( true ); // as-of-time *before* fetching GTID variables
+
+ if ( $this->useGTIDs() ) {
+ // Try to use GTIDs, fallbacking to binlog positions if not possible
+ $data = $this->getServerGTIDs( __METHOD__ );
+ // Use gtid_current_pos for MariaDB and gtid_executed for MySQL
+ foreach ( [ 'gtid_current_pos', 'gtid_executed' ] as $name ) {
+ if ( isset( $data[$name] ) && strlen( $data[$name] ) ) {
+ return new MySQLMasterPos( $data[$name], $now );
+ }
}
}
- $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__ );
- $row = $this->fetchObject( $res );
- if ( $row && strlen( $row->Relay_Master_Log_File ) ) {
+ $data = $this->getServerRoleStatus( 'SLAVE', __METHOD__ );
+ if ( $data && strlen( $data['Relay_Master_Log_File'] ) ) {
return new MySQLMasterPos(
- "{$row->Relay_Master_Log_File}/{$row->Exec_Master_Log_Pos}",
+ "{$data['Relay_Master_Log_File']}/{$data['Exec_Master_Log_Pos']}",
$now
);
}
* @return MySQLMasterPos|bool
*/
public function getMasterPos() {
- $now = microtime( true );
+ $now = microtime( true ); // as-of-time *before* fetching GTID variables
+
+ $pos = false;
+ if ( $this->useGTIDs() ) {
+ // Try to use GTIDs, fallbacking to binlog positions if not possible
+ $data = $this->getServerGTIDs( __METHOD__ );
+ // Use gtid_current_pos for MariaDB and gtid_executed for MySQL
+ foreach ( [ 'gtid_current_pos', 'gtid_executed' ] as $name ) {
+ if ( isset( $data[$name] ) && strlen( $data[$name] ) ) {
+ $pos = new MySQLMasterPos( $data[$name], $now );
+ break;
+ }
+ }
+ // Filter domains that are inactive or not relevant to the session
+ if ( $pos ) {
+ $pos->setActiveOriginServerId( $this->getServerId() );
+ $pos->setActiveOriginServerUUID( $this->getServerUUID() );
+ if ( isset( $data['gtid_domain_id'] ) ) {
+ $pos->setActiveDomain( $data['gtid_domain_id'] );
+ }
+ }
+ }
- if ( $this->useGTIDs ) {
- $res = $this->query( "SELECT @@global.gtid_binlog_pos AS Value", __METHOD__ );
- $gtidRow = $this->fetchObject( $res );
- if ( $gtidRow && strlen( $gtidRow->Value ) ) {
- return new MySQLMasterPos( $gtidRow->Value, $now );
+ if ( !$pos ) {
+ $data = $this->getServerRoleStatus( 'MASTER', __METHOD__ );
+ if ( $data && strlen( $data['File'] ) ) {
+ $pos = new MySQLMasterPos( "{$data['File']}/{$data['Position']}", $now );
}
}
- $res = $this->query( 'SHOW MASTER STATUS', __METHOD__ );
- $row = $this->fetchObject( $res );
- if ( $row && strlen( $row->File ) ) {
- return new MySQLMasterPos( "{$row->File}/{$row->Position}", $now );
+ return $pos;
+ }
+
+ /**
+ * @return int
+ * @throws DBQueryError If the variable doesn't exist for some reason
+ */
+ protected function getServerId() {
+ return $this->srvCache->getWithSetCallback(
+ $this->srvCache->makeGlobalKey( 'mysql-server-id', $this->getServer() ),
+ self::SERVER_ID_CACHE_TTL,
+ function () {
+ $res = $this->query( "SELECT @@server_id AS id", __METHOD__ );
+ return intval( $this->fetchObject( $res )->id );
+ }
+ );
+ }
+
+ /**
+ * @return string|null
+ */
+ protected function getServerUUID() {
+ return $this->srvCache->getWithSetCallback(
+ $this->srvCache->makeGlobalKey( 'mysql-server-uuid', $this->getServer() ),
+ self::SERVER_ID_CACHE_TTL,
+ function () {
+ $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'server_uuid'" );
+ $row = $this->fetchObject( $res );
+
+ return $row ? $row->Value : null;
+ }
+ );
+ }
+
+ /**
+ * @param string $fname
+ * @return string[]
+ */
+ protected function getServerGTIDs( $fname = __METHOD__ ) {
+ $map = [];
+ // Get global-only variables like gtid_executed
+ $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'gtid_%'", $fname );
+ foreach ( $res as $row ) {
+ $map[$row->Variable_name] = $row->Value;
+ }
+ // Get session-specific (e.g. gtid_domain_id since that is were writes will log)
+ $res = $this->query( "SHOW SESSION VARIABLES LIKE 'gtid_%'", $fname );
+ foreach ( $res as $row ) {
+ $map[$row->Variable_name] = $row->Value;
}
- return false;
+ return $map;
+ }
+
+ /**
+ * @param string $role One of "MASTER"/"SLAVE"
+ * @param string $fname
+ * @return string[] Latest available server status row
+ */
+ protected function getServerRoleStatus( $role, $fname = __METHOD__ ) {
+ return $this->query( "SHOW $role STATUS", $fname )->fetchRow() ?: [];
}
public function serverIsReadOnly() {
return 'CAST( ' . $field . ' AS SIGNED )';
}
+ /*
+ * @return bool Whether GTID support is used (mockable for testing)
+ */
+ protected function useGTIDs() {
+ return $this->useGTIDs;
+ }
}
class_alias( DatabaseMysqlBase::class, 'DatabaseMysqlBase' );
/** @var string Transaction is requested internally via DBO_TRX/startAtomic() */
const TRANSACTION_INTERNAL = 'implicit';
+ /** @var string Atomic section is not cancelable */
+ const ATOMIC_NOT_CANCELABLE = '';
+ /** @var string Atomic section is cancelable */
+ const ATOMIC_CANCELABLE = 'cancelable';
+
/** @var string Transaction operation comes from service managing all DBs */
const FLUSHING_ALL_PEERS = 'flush';
/** @var string Transaction operation comes from the database class internally */
* Should return true if unsure.
*
* @return bool
+ * @deprecated Since 1.31; use lastDoneWrites()
*/
public function doneWrites();
*/
public function lastError();
- /**
- * mysql_fetch_field() wrapper
- * Returns false if the field doesn't exist
- *
- * @param string $table Table name
- * @param string $field Field name
- *
- * @return Field
- */
- public function fieldInfo( $table, $field );
-
/**
* Get the number of rows affected by the last write query
* @see https://secure.php.net/mysql_affected_rows
*/
public function close();
- /**
- * @param string $error Fallback error message, used if none is given by DB
- * @throws DBConnectionError
- */
- public function reportConnectionError( $error = 'Unknown error' );
-
/**
* Run an SQL query and return the result. Normally throws a DBQueryError
* on failure. If errors are ignored, returns false instead.
*/
public function query( $sql, $fname = __METHOD__, $tempIgnore = false );
- /**
- * Report a query error. Log the error, and if neither the object ignore
- * flag nor the $tempIgnore flag is set, throw a DBQueryError.
- *
- * @param string $error
- * @param int $errno
- * @param string $sql
- * @param string $fname
- * @param bool $tempIgnore
- * @throws DBQueryError
- */
- public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false );
-
/**
* Free a result object returned by query() or select(). It's usually not
* necessary to call this, just use unset() or let the variable holding
*/
public function tableExists( $table, $fname = __METHOD__ );
- /**
- * Determines if a given index is unique
- *
- * @param string $table
- * @param string $index
- *
- * @return bool
- */
- public function indexUnique( $table, $index );
-
/**
* INSERT wrapper, inserts an array into a table.
*
/**
* Begin an atomic section of statements
*
- * If a transaction has been started already, just keep track of the given
- * section name to make sure the transaction is not committed pre-maturely.
- * This function can be used in layers (with sub-sections), so use a stack
- * to keep track of the different atomic sections. If there is no transaction,
- * start one implicitly.
+ * If a transaction has been started already, (optionally) sets a savepoint
+ * and tracks the given section name to make sure the transaction is not
+ * committed pre-maturely. This function can be used in layers (with
+ * sub-sections), so use a stack to keep track of the different atomic
+ * sections. If there is no transaction, one is started implicitly.
*
* The goal of this function is to create an atomic section of SQL queries
* without having to start a new transaction if it already exists.
*
- * All atomic levels *must* be explicitly closed using IDatabase::endAtomic(),
- * and any database transactions cannot be began or committed until all atomic
- * levels are closed. There is no such thing as implicitly opening or closing
- * an atomic section.
+ * All atomic levels *must* be explicitly closed using IDatabase::endAtomic()
+ * or IDatabase::cancelAtomic(), and any database transactions cannot be
+ * began or committed until all atomic levels are closed. There is no such
+ * thing as implicitly opening or closing an atomic section.
*
* @since 1.23
* @param string $fname
+ * @param string $cancelable Pass self::ATOMIC_CANCELABLE to use a
+ * savepoint and enable self::cancelAtomic() for this section.
* @throws DBError
*/
- public function startAtomic( $fname = __METHOD__ );
+ public function startAtomic( $fname = __METHOD__, $cancelable = self::ATOMIC_NOT_CANCELABLE );
/**
* Ends an atomic section of SQL statements
*/
public function endAtomic( $fname = __METHOD__ );
+ /**
+ * Cancel an atomic section of SQL statements
+ *
+ * This will roll back only the statements executed since the start of the
+ * most recent atomic section, and close that section. If a transaction was
+ * open before the corresponding startAtomic() call, any statements before
+ * that call are *not* rolled back and the transaction remains open. If the
+ * corresponding startAtomic() implicitly started a transaction, that
+ * transaction is rolled back.
+ *
+ * Note that a call to IDatabase::rollback() will also roll back any open
+ * atomic sections.
+ *
+ * @note As a micro-optimization to save a few DB calls, this method may only
+ * be called when startAtomic() was called with the ATOMIC_CANCELABLE flag.
+ * @since 1.31
+ * @see IDatabase::startAtomic
+ * @param string $fname
+ * @throws DBError
+ */
+ public function cancelAtomic( $fname = __METHOD__ );
+
/**
* Run a callback to do an atomic set of updates for this database
*
* - This database object
* - The value of $fname
*
- * If any exception occurs in the callback, then rollback() will be called and the error will
- * be re-thrown. It may also be that the rollback itself fails with an exception before then.
- * In any case, such errors are expected to terminate the request, without any outside caller
- * attempting to catch errors and commit anyway. Note that any rollback undoes all prior
- * atomic section and uncommitted updates, which trashes the current request, requiring an
- * error to be displayed.
+ * If any exception occurs in the callback, then cancelAtomic() will be
+ * called to back out any statements executed by the callback and the error
+ * will be re-thrown. It may also be that the cancel itself fails with an
+ * exception before then. In any case, such errors are expected to
+ * terminate the request, without any outside caller attempting to catch
+ * errors and commit anyway.
*
- * This can be an alternative to explicit startAtomic()/endAtomic() calls.
+ * This can be an alternative to explicit startAtomic()/endAtomic()/cancelAtomic() calls.
*
* @see Database::startAtomic
* @see Database::endAtomic
+ * @see Database::cancelAtomic
*
* @param string $fname Caller name (usually __METHOD__)
* @param callable $callback Callback that issues DB updates
* @throws DBError
* @throws RuntimeException
* @throws UnexpectedValueException
- * @since 1.27
+ * @since 1.27; prior to 1.31 this did a rollback() instead of
+ * cancelAtomic(), and assumed no callers up the stack would ever try to
+ * catch the exception.
*/
public function doAtomicSection( $fname, callable $callback );
*/
public function flushSnapshot( $fname = __METHOD__ );
- /**
- * List all tables on the database
- *
- * @param string $prefix Only show tables with this prefix, e.g. mw_
- * @param string $fname Calling function name
- * @throws DBError
- * @return array
- */
- public function listTables( $prefix = null, $fname = __METHOD__ );
-
/**
* Convert a timestamp in one of the formats accepted by wfTimestamp()
* to the format used for inserting into timestamp fields in this DBMS.
* @since 1.29
*/
public function unlockTables( $method );
+
+ /**
+ * List all tables on the database
+ *
+ * @param string $prefix Only show tables with this prefix, e.g. mw_
+ * @param string $fname Calling function name
+ * @throws DBError
+ * @return array
+ */
+ public function listTables( $prefix = null, $fname = __METHOD__ );
+
+ /**
+ * Determines if a given index is unique
+ *
+ * @param string $table
+ * @param string $index
+ *
+ * @return bool
+ */
+ public function indexUnique( $table, $index );
+
+ /**
+ * mysql_fetch_field() wrapper
+ * Returns false if the field doesn't exist
+ *
+ * @param string $table Table name
+ * @param string $field Field name
+ *
+ * @return Field
+ */
+ public function fieldInfo( $table, $field );
}
class_alias( IMaintainableDatabase::class, 'IMaintainableDatabase' );
public function unlockTables( $method ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
+
+ public function indexUnique( $table, $index ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function listTables( $prefix = null, $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function fieldInfo( $table, $field ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
}
class_alias( MaintainableDBConnRef::class, 'MaintainableDBConnRef' );
* - Binlog-based usage assumes single-source replication and non-hierarchical replication.
* - GTID-based usage allows getting/syncing with multi-source replication. It is assumed
* that GTID sets are complete (e.g. include all domains on the server).
+ *
+ * @see https://mariadb.com/kb/en/library/gtid/
+ * @see https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html
*/
class MySQLMasterPos implements DBMasterPos {
- /** @var string|null Binlog file base name */
- public $binlog;
- /** @var int[]|null Binglog file position tuple */
- public $pos;
- /** @var string[] GTID list */
- public $gtids = [];
+ /** @var int One of (BINARY_LOG, GTID_MYSQL, GTID_MARIA) */
+ private $style;
+ /** @var string|null Base name of all Binary Log files */
+ private $binLog;
+ /** @var int[]|null Binary Log position tuple (index number, event number) */
+ private $logPos;
+ /** @var string[] Map of (server_uuid/gtid_domain_id => GTID) */
+ private $gtids = [];
+ /** @var int|null Active GTID domain ID */
+ private $activeDomain;
+ /** @var int|null ID of the server were DB writes originate */
+ private $activeServerId;
+ /** @var string|null UUID of the server were DB writes originate */
+ private $activeServerUUID;
/** @var float UNIX timestamp */
- public $asOfTime = 0.0;
+ private $asOfTime = 0.0;
+
+ const BINARY_LOG = 'binary-log';
+ const GTID_MARIA = 'gtid-maria';
+ const GTID_MYSQL = 'gtid-mysql';
+
+ /** @var int Key name of the binary log index number of a position tuple */
+ const CORD_INDEX = 0;
+ /** @var int Key name of the binary log event number of a position tuple */
+ const CORD_EVENT = 1;
/**
* @param string $position One of (comma separated GTID list, <binlog file>/<integer>)
protected function init( $position, $asOfTime ) {
$m = [];
if ( preg_match( '!^(.+)\.(\d+)/(\d+)$!', $position, $m ) ) {
- $this->binlog = $m[1]; // ideally something like host name
- $this->pos = [ (int)$m[2], (int)$m[3] ];
+ $this->binLog = $m[1]; // ideally something like host name
+ $this->logPos = [ self::CORD_INDEX => (int)$m[2], self::CORD_EVENT => (int)$m[3] ];
+ $this->style = self::BINARY_LOG;
} else {
$gtids = array_filter( array_map( 'trim', explode( ',', $position ) ) );
foreach ( $gtids as $gtid ) {
- if ( !self::parseGTID( $gtid ) ) {
+ $components = self::parseGTID( $gtid );
+ if ( !$components ) {
throw new InvalidArgumentException( "Invalid GTID '$gtid'." );
}
- $this->gtids[] = $gtid;
+
+ list( $domain, $pos ) = $components;
+ if ( isset( $this->gtids[$domain] ) ) {
+ // For MySQL, handle the case where some past issue caused a gap in the
+ // executed GTID set, e.g. [last_purged+1,N-1] and [N+1,N+2+K]. Ignore the
+ // gap by using the GTID with the highest ending sequence number.
+ list( , $otherPos ) = self::parseGTID( $this->gtids[$domain] );
+ if ( $pos > $otherPos ) {
+ $this->gtids[$domain] = $gtid;
+ }
+ } else {
+ $this->gtids[$domain] = $gtid;
+ }
+
+ if ( is_int( $domain ) ) {
+ $this->style = self::GTID_MARIA; // gtid_domain_id
+ } else {
+ $this->style = self::GTID_MYSQL; // server_uuid
+ }
}
if ( !$this->gtids ) {
- throw new InvalidArgumentException( "Got empty GTID set." );
+ throw new InvalidArgumentException( "GTID set cannot be empty." );
}
}
}
// Prefer GTID comparisons, which work with multi-tier replication
- $thisPosByDomain = $this->getGtidCoordinates();
- $thatPosByDomain = $pos->getGtidCoordinates();
+ $thisPosByDomain = $this->getActiveGtidCoordinates();
+ $thatPosByDomain = $pos->getActiveGtidCoordinates();
if ( $thisPosByDomain && $thatPosByDomain ) {
$comparisons = [];
// Check that this has positions reaching those in $pos for all domains in common
}
// Prefer GTID comparisons, which work with multi-tier replication
- $thisPosDomains = array_keys( $this->getGtidCoordinates() );
- $thatPosDomains = array_keys( $pos->getGtidCoordinates() );
+ $thisPosDomains = array_keys( $this->getActiveGtidCoordinates() );
+ $thatPosDomains = array_keys( $pos->getActiveGtidCoordinates() );
if ( $thisPosDomains && $thatPosDomains ) {
// Check that $this has a GTID for at least one domain also in $pos; due to MariaDB
// quirks, prior master switch-overs may result in inactive garbage GTIDs that cannot
}
/**
- * @return string|null
+ * @return string|null Base name of binary log files
+ * @since 1.31
+ */
+ public function getLogName() {
+ return $this->gtids ? null : $this->binLog;
+ }
+
+ /**
+ * @return int[]|null Tuple of (binary log file number, event number)
+ * @since 1.31
+ */
+ public function getLogPosition() {
+ return $this->gtids ? null : $this->logPos;
+ }
+
+ /**
+ * @return string|null Name of the binary log file for this position
+ * @since 1.31
*/
public function getLogFile() {
- return $this->gtids ? null : "{$this->binlog}.{$this->pos[0]}";
+ return $this->gtids ? null : "{$this->binLog}.{$this->logPos[self::CORD_INDEX]}";
}
/**
- * @return string[]
+ * @return string[] Map of (server_uuid/gtid_domain_id => GTID)
+ * @since 1.31
*/
public function getGTIDs() {
return $this->gtids;
}
/**
- * @return string GTID set or <binlog file>/<position> (e.g db1034-bin.000976/843431247)
+ * @param int|null $id @@gtid_domain_id of the active replication stream
+ * @since 1.31
*/
- public function __toString() {
- return $this->gtids
- ? implode( ',', $this->gtids )
- : $this->getLogFile() . "/{$this->pos[1]}";
+ public function setActiveDomain( $id ) {
+ $this->activeDomain = (int)$id;
+ }
+
+ /**
+ * @param int|null $id @@server_id of the server were writes originate
+ * @since 1.31
+ */
+ public function setActiveOriginServerId( $id ) {
+ $this->activeServerId = (int)$id;
+ }
+
+ /**
+ * @param string|null $id @@server_uuid of the server were writes originate
+ * @since 1.31
+ */
+ public function setActiveOriginServerUUID( $id ) {
+ $this->activeServerUUID = $id;
}
/**
* @param MySQLMasterPos $pos
* @param MySQLMasterPos $refPos
* @return string[] List of GTIDs from $pos that have domains in $refPos
+ * @since 1.31
*/
public static function getCommonDomainGTIDs( MySQLMasterPos $pos, MySQLMasterPos $refPos ) {
- $gtidsCommon = [];
-
- $relevantDomains = $refPos->getGtidCoordinates(); // (domain => unused)
- foreach ( $pos->gtids as $gtid ) {
- list( $domain ) = self::parseGTID( $gtid );
- if ( isset( $relevantDomains[$domain] ) ) {
- $gtidsCommon[] = $gtid;
- }
- }
-
- return $gtidsCommon;
+ return array_values(
+ array_intersect_key( $pos->gtids, $refPos->getActiveGtidCoordinates() )
+ );
}
/**
* @see https://mariadb.com/kb/en/mariadb/gtid
* @see https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html
- * @return array Map of (domain => integer position); possibly empty
+ * @return array Map of (server_uuid/gtid_domain_id => integer position); possibly empty
*/
- protected function getGtidCoordinates() {
+ protected function getActiveGtidCoordinates() {
$gtidInfos = [];
- foreach ( $this->gtids as $gtid ) {
- list( $domain, $pos ) = self::parseGTID( $gtid );
- $gtidInfos[$domain] = $pos;
+
+ foreach ( $this->gtids as $domain => $gtid ) {
+ list( $domain, $pos, $server ) = self::parseGTID( $gtid );
+
+ $ignore = false;
+ // Filter out GTIDs from non-active replication domains
+ if ( $this->style === self::GTID_MARIA && $this->activeDomain !== null ) {
+ $ignore |= ( $domain !== $this->activeDomain );
+ }
+ // Likewise for GTIDs from non-active replication origin servers
+ if ( $this->style === self::GTID_MARIA && $this->activeServerId !== null ) {
+ $ignore |= ( $server !== $this->activeServerId );
+ } elseif ( $this->style === self::GTID_MYSQL && $this->activeServerUUID !== null ) {
+ $ignore |= ( $server !== $this->activeServerUUID );
+ }
+
+ if ( !$ignore ) {
+ $gtidInfos[$domain] = $pos;
+ }
}
return $gtidInfos;
}
/**
- * @param string $gtid
- * @return array|null [domain, integer position] or null
+ * @param string $id GTID
+ * @return array|null [domain ID or server UUID, sequence number, server ID/UUID] or null
*/
- protected static function parseGTID( $gtid ) {
+ protected static function parseGTID( $id ) {
$m = [];
- if ( preg_match( '!^(\d+)-\d+-(\d+)$!', $gtid, $m ) ) {
+ if ( preg_match( '!^(\d+)-(\d+)-(\d+)$!', $id, $m ) ) {
// MariaDB style: <domain>-<server id>-<sequence number>
- return [ (int)$m[1], (int)$m[2] ];
- } elseif ( preg_match( '!^(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}):(\d+)$!', $gtid, $m ) ) {
- // MySQL style: <UUID domain>:<sequence number>
- return [ $m[1], (int)$m[2] ];
+ return [ (int)$m[1], (int)$m[3], (int)$m[2] ];
+ } elseif ( preg_match( '!^(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}):(?:\d+-|)(\d+)$!', $id, $m ) ) {
+ // MySQL style: <server UUID>:<sequence number>-<sequence number>
+ // Normally, the first number should reflect the point (gtid_purged) where older
+ // binary logs where purged to save space. When doing comparisons, it may as well
+ // be 1 in that case. Assume that this is generally the situation.
+ return [ $m[1], (int)$m[2], $m[1] ];
}
return null;
/**
* @see https://dev.mysql.com/doc/refman/5.7/en/show-master-status.html
* @see https://dev.mysql.com/doc/refman/5.7/en/show-slave-status.html
- * @return array|bool (binlog, (integer file number, integer position)) or false
+ * @return array|bool Map of (binlog:<string>, pos:(<integer>, <integer>)) or false
*/
protected function getBinlogCoordinates() {
- return ( $this->binlog !== null && $this->pos !== null )
- ? [ 'binlog' => $this->binlog, 'pos' => $this->pos ]
+ return ( $this->binLog !== null && $this->logPos !== null )
+ ? [ 'binlog' => $this->binLog, 'pos' => $this->logPos ]
: false;
}
$this->init( $data['position'], $data['asOfTime'] );
}
+
+ /**
+ * @return string GTID set or <binary log file>/<position> (e.g db1034-bin.000976/843431247)
+ */
+ public function __toString() {
+ return $this->gtids
+ ? implode( ',', $this->gtids )
+ : $this->getLogFile() . "/{$this->logPos[self::CORD_EVENT]}";
+ }
}
$e = null; // first exception
$this->forEachOpenMasterConnection( function ( Database $conn ) use ( $type, &$e ) {
$conn->setTrxEndCallbackSuppression( false );
- if ( $conn->writesOrCallbacksPending() ) {
- // This happens if onTransactionIdle() callbacks leave callbacks on *another* DB
- // (which finished its callbacks already). Warn and recover in this case. Let the
- // callbacks run in the final commitMasterChanges() in LBFactory::shutdown().
- $this->queryLogger->info( __METHOD__ . ": found writes/callbacks pending." );
+ // Callbacks run in AUTO-COMMIT mode, so make sure no transactions are pending...
+ if ( $conn->writesPending() ) {
+ // This happens if onTransactionIdle() callbacks write to *other* handles
+ // (which already finished their callbacks). Let any callbacks run in the final
+ // commitMasterChanges() in LBFactory::shutdown(), when the transaction is gone.
+ $this->queryLogger->warning( __METHOD__ . ": found writes pending." );
return;
} elseif ( $conn->trxLevel() ) {
// This happens for single-DB setups where DB_REPLICA uses the master DB,
$this->trxRoundId = false;
$this->forEachOpenMasterConnection(
function ( IDatabase $conn ) use ( $fname, $restore ) {
- if ( $conn->writesOrCallbacksPending() || $conn->explicitTrxActive() ) {
- $conn->rollback( $fname, $conn::FLUSHING_ALL_PEERS );
- }
+ $conn->rollback( $fname, $conn::FLUSHING_ALL_PEERS );
if ( $restore ) {
$this->undoTransactionRoundFlags( $conn );
}
$this->request = $request;
$this->logger = $resourceLoader->getLogger();
- // Future developers: Avoid use of getVal() in this class, which performs
- // expensive UTF normalisation by default. Use getRawVal() instead.
- // Values here are either one of a finite number of internal IDs,
- // or previously-stored user input (e.g. titles, user names) that were passed
- // to this endpoint by ResourceLoader itself from the canonical value.
- // Values do not come directly from user input and need not match.
+ // Future developers: Use WebRequest::getRawVal() instead getVal().
+ // The getVal() method performs slow Language+UTF logic. (f303bb9360)
// List of modules
$modules = $request->getRawVal( 'modules' );
return [
'digitTransformTable' => $language->digitTransformTable(),
'separatorTransformTable' => $language->separatorTransformTable(),
+ 'minimumGroupingDigits' => $language->minimumGroupingDigits(),
'grammarForms' => $language->getGrammarForms(),
'grammarTransformations' => $language->getGrammarTransformations(),
'pluralRules' => $language->getPluralRules(),
<?php
/**
- * Module for ResourceLoader initialization.
- *
* 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
* @author Roan Kattouw
*/
+/**
+ * Module for ResourceLoader initialization.
+ *
+ * See also <https://www.mediawiki.org/wiki/ResourceLoader/Features#Startup_Module>
+ *
+ * The startup module, as being called only from ResourceLoaderClientHtml, has
+ * the ability to vary based extra query parameters, in addition to those
+ * from ResourceLoaderContext:
+ *
+ * - target: Only register modules in the client allowed within this target.
+ * Default: "desktop".
+ * See also: OutputPage::setTarget(), ResourceLoaderModule::getTargets().
+ */
class ResourceLoaderStartUpModule extends ResourceLoaderModule {
// Cache for getConfigSettings() as it's called by multiple methods
*/
public function getModuleRegistrations( ResourceLoaderContext $context ) {
$resourceLoader = $context->getResourceLoader();
- $target = $context->getRequest()->getVal( 'target', 'desktop' );
+ // Future developers: Use WebRequest::getRawVal() instead getVal().
+ // The getVal() method performs slow Language+UTF logic. (f303bb9360)
+ $target = $context->getRequest()->getRawVal( 'target', 'desktop' );
// Bypass target filter if this request is Special:JavaScriptTest.
// To prevent misuse in production, this is only allowed if testing is enabled server-side.
$byPassTargetFilter = $this->getConfig()->get( 'EnableJavaScriptTest' ) && $target === 'test';
'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
&$query_options, &$join_conds
) {
- $conds[] = 'rc_patrolled = 1';
+ $conds[] = 'rc_patrolled != 0';
},
'cssClassSuffix' => 'unpatrolled',
'isRowApplicableCallable' => function ( $ctx, $rc ) {
$this->mHideName = $block->mHideName;
$this->mAllowUsertalk = !$block->prevents( 'editownusertalk' );
} else {
+ $this->mBlock = null;
$this->mBlockedby = '';
+ $this->mBlockreason = '';
$this->mHideName = 0;
$this->mAllowUsertalk = false;
}
* @param string $oname The option to check
* @param string $defaultOverride A default value returned if the option does not exist
* @param bool $ignoreHidden Whether to ignore the effects of $wgHiddenPrefs
- * @return string|null User's current value for the option
+ * @return string|array|int|null User's current value for the option
* @see getBoolOption()
* @see getIntOption()
*/
return;
}
- $dbw = wfGetDB( DB_MASTER );
- $asOfTimes = array_unique( $dbw->selectFieldValues(
- 'watchlist',
- 'wl_notificationtimestamp',
- [ 'wl_user' => $id, 'wl_notificationtimestamp IS NOT NULL' ],
- __METHOD__,
- [ 'ORDER BY' => 'wl_notificationtimestamp DESC', 'LIMIT' => 500 ]
- ) );
- if ( !$asOfTimes ) {
- return;
- }
- // Immediately update the most recent touched rows, which hopefully covers what
- // the user sees on the watchlist page before pressing "mark all pages visited"....
- $dbw->update(
- 'watchlist',
- [ 'wl_notificationtimestamp' => null ],
- [ 'wl_user' => $id, 'wl_notificationtimestamp' => $asOfTimes ],
- __METHOD__
- );
- // ...and finish the older ones in a post-send update with lag checks...
- DeferredUpdates::addUpdate( new AutoCommitUpdate(
- $dbw,
- __METHOD__,
- function () use ( $dbw, $id ) {
- global $wgUpdateRowsPerQuery;
-
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
- $asOfTimes = array_unique( $dbw->selectFieldValues(
- 'watchlist',
- 'wl_notificationtimestamp',
- [ 'wl_user' => $id, 'wl_notificationtimestamp IS NOT NULL' ],
- __METHOD__
- ) );
- foreach ( array_chunk( $asOfTimes, $wgUpdateRowsPerQuery ) as $asOfTimeBatch ) {
- $dbw->update(
- 'watchlist',
- [ 'wl_notificationtimestamp' => null ],
- [ 'wl_user' => $id, 'wl_notificationtimestamp' => $asOfTimeBatch ],
- __METHOD__
- );
- $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
- }
- }
- ) );
+ $watchedItemStore = MediaWikiServices::getInstance()->getWatchedItemStore();
+ $watchedItemStore->resetAllNotificationTimestampsForUser( $this );
+
// We also need to clear here the "you have new message" notification for the own
// user_talk page; it's cleared one page view later in WikiPage::doViewUpdates().
}
throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
}
+ public function resetAllNotificationTimestampsForUser( User $user ) {
+ throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+ }
+
public function resetNotificationTimestamp(
User $user,
Title $title,
* @since 1.27
* @param User $user
* @param LinkTarget $target
- * @return bool
+ * @return WatchedItem|bool
*/
public function loadWatchedItem( User $user, LinkTarget $target ) {
// Only loggedin user can have a watchlist
return $success;
}
+ public function resetAllNotificationTimestampsForUser( User $user ) {
+ // Only loggedin user can have a watchlist
+ if ( $user->isAnon() ) {
+ return;
+ }
+
+ // If the page is watched by the user (or may be watched), update the timestamp
+ $job = new ClearWatchlistNotificationsJob(
+ $user->getUserPage(),
+ [ 'userId' => $user->getId(), 'casTime' => time() ]
+ );
+
+ // Try to run this post-send
+ // Calls DeferredUpdates::addCallableUpdate in normal operation
+ call_user_func(
+ $this->deferredUpdatesAddCallableUpdateCallback,
+ function () use ( $job ) {
+ $job->run();
+ }
+ );
+ }
+
/**
* @since 1.27
* @param User $editor
* @param LinkTarget $target
* @param string|int $timestamp
- * @return int
+ * @return int[]
*/
public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp ) {
$dbw = $this->getConnectionRef( DB_MASTER );
/**
* @since 1.31
*
- * @param User $user The user to set the timestamp for
+ * @param User $user The user to set the timestamps for
* @param string|null $timestamp Set the update timestamp to this value
* @param LinkTarget[] $targets List of targets to update. Default to all targets
*
array $targets = []
);
+ /**
+ * Reset all watchlist notificaton timestamps for a user using the job queue
+ *
+ * @since 1.31
+ *
+ * @param User $user The user to reset the timestamps for
+ */
+ public function resetAllNotificationTimestampsForUser( User $user );
+
/**
* @since 1.31
*
* @param int $oldid The revision id being viewed. If not given or 0, latest revision is
* assumed.
*
- * @return bool success
+ * @return bool success Whether a job was enqueued
*/
public function resetNotificationTimestamp( User $user, Title $title, $force = '', $oldid = 0 );
'ks-arab' => 'کٲشُر', # Kashmiri (Perso-Arabic script)
'ks-deva' => 'कॉशुर', # Kashmiri (Devanagari script)
'ksh' => 'Ripoarisch', # Ripuarian
- 'ku' => 'Kurdî', # Kurdish (multiple scripts - defaults to Latin)
- 'ku-latn' => "Kurdî (latînî)\xE2\x80\x8E", # Northern Kurdish (Latin script)
+ 'ku' => 'kurdî', # Kurdish (multiple scripts - defaults to Latin)
+ 'ku-latn' => "kurdî (latînî)\xE2\x80\x8E", # Northern Kurdish (Latin script)
'ku-arab' => "كوردي (عەرەبی)\xE2\x80\x8F", # Northern Kurdish (Arabic script) (falls back to ckb)
'kum' => 'къумукъ', # Kumyk (Cyrillic, 'kum-latn' for Latin script)
'kv' => 'коми', # Komi-Zyrian (Cyrillic is common script but also written in Latin script)
"right-patrol": "Пазначэньне рэдагаваньняў як «патруляваных»",
"right-autopatrol": "Аўтаматычнае пазначэньне рэдагаваньняў як «патруляваных»",
"right-patrolmarks": "Прагляд пазначэньняў пра патруляваньне ў апошніх зьменах",
- "right-unwatchedpages": "прагляд сьпісу старонак, за якімі ніхто не назірае",
- "right-mergehistory": "аб’яднаньне гісторыі старонак",
- "right-userrights": "рэдагаваньне правоў усіх удзельнікаў",
+ "right-unwatchedpages": "Ð\9fрагляд сьпісу старонак, за якімі ніхто не назірае",
+ "right-mergehistory": "Ð\90б’яднаньне гісторыі старонак",
+ "right-userrights": "Рэдагаваньне ўсіх правоў удзельнікаў",
"right-userrights-interwiki": "рэдагаваньне правоў удзельнікаў у іншых вікі",
"right-siteadmin": "блякаваньне і разблякаваньне базы зьвестак",
"right-override-export-depth": "экспартаваньне старонак, уключаючы зьвязаныя старонкі з глыбінёй да 5",
"databaseerror-query": "অনুসন্ধান: $1",
"databaseerror-function": "ফাংশন: $1",
"databaseerror-error": "ত্রুটি: $1",
- "transaction-duration-limit-exceeded": "দীর্ঘ পুনঃসৃষ্টি বিলম্ব এড়ানোর জন্য এই ট্রানজাকশনটি বাতিল করা হল, কারণ লিখনের স্থায়িত্ব ($1) $2 সেকেন্ড সীমাটিকে অতিক্রম করে গিয়েছিল। \nযদি আপনি অনেকগুলি আইটেম একসাথে পরিবর্তন করতে চান, তাহলে একাধিক ক্ষুদ্রতর অপারেশন সম্পন্ন করার চেষ্টা করুন।",
+ "transaction-duration-limit-exceeded": "দীর্ঘ পুনঃসৃষ্টি বিলম্ব এড়ানোর জন্য, এই কার্যটি বাতিল করা হল কারণ তা লিখনের স্থায়িত্ব ($1) $2 সেকেন্ড সীমাটিকে অতিক্রম করে গিয়েছিল। \nযদি আপনি অনেকগুলি আইটেম একসাথে পরিবর্তন করছিলেন, তাহলে একাধিক ক্ষুদ্রতর অপারেশন সম্পন্ন করার চেষ্টা করুন।",
"laggedslavemode": "<strong>সতর্ক বার্তা:</strong> পাতাটি সম্ভবত সম্প্রতি হালনাগাদ করা হয়নি।",
"readonly": "ডাটাবেজ অবরুদ্ধ",
"enterlockreason": "অবরুদ্ধ করার কারণ কী তা বলুন, সাথে কখন অবরোধ খুলবেন তার আনুমানিক সময় উল্লেখ করুন",
"timezoneregion-indian": "Indijski okean",
"timezoneregion-pacific": "Tihi okean",
"allowemail": "Dozvoli e-poštu od ostalih korisnika",
+ "email-allow-new-users-label": "Dozvoli e-poštu od potpuno novih korisnika",
"email-blacklist-label": "Zabrani sljedećim korisnicima da mi šalju e-poštu:",
"prefs-searchoptions": "Pretraga",
"prefs-namespaces": "Imenski prostori",
"rcfilters-view-namespaces-tooltip": "Φιλτράρισμα αποτελεσμάτων κατά ονοματοχώρο",
"rcfilters-liveupdates-button": "Ζωντανή ανανέωση",
"rcfilters-liveupdates-button-title-on": "Απενεργοποίηση ζωντανής ανανέωσης",
+ "rcfilters-watchlist-markseen-button": "Σημειώστε όλες τις αλλαγές ως εξετασμένες",
+ "rcfilters-watchlist-edit-watchlist-button": "Διορθώστε τη λίστα παρακολούθησης",
+ "rcfilters-watchlist-showupdated": "Σελίδες που έχουν υποστεί αλλαγές από την τελευταία φορά που τις επισκεφθήκατε εμφανίζονται με '''έντονους χαρακτήρες'''.",
"rcfilters-preference-label": "Απόκρυψη της βελτιωμένης έκδοσης των Πρόσφατων Αλλαγών",
"rcfilters-preference-help": "Αναστέλλει τον επανασχεδιασμό διεπαφής 2017 και όλα τα εργαλεία που προστέθηκαν στη συνέχεια και από τότε.",
"rcnotefrom": "Παρακάτω {{PLURAL:$5|είναι η αλλαγή|είναι οι αλλαγές}} από <strong>$3, $4</strong> (έως <strong>$1</strong> που εμφανίζεται).",
"fileduplicatesearch-info": "$1 × $2 píxeles<br />Tamaño: $3<br />Tipo MIME: $4",
"fileduplicatesearch-result-1": "El archivo «$1» no tiene duplicados idénticos.",
"fileduplicatesearch-result-n": "El archivo «$1» tiene {{PLURAL:$2|1 duplicado idéntico|$2 duplicados idénticos}}.",
- "fileduplicatesearch-noresults": "Ningún archivo con el nombre «$1» encontrado.",
+ "fileduplicatesearch-noresults": "No se encontró ningún archivo denominado «$1».",
"specialpages": "Páginas especiales",
"specialpages-note-top": "Leyenda",
"specialpages-note-restricted": "* Páginas especiales ordinarias.\n* <span class=\"mw-specialpagerestricted\">Páginas especiales restringidas.</span>",
"tog-prefershttps": "תמיד להשתמש בתקשורת מאובטחת לאחר הכניסה לחשבון",
"underline-always": "תמיד",
"underline-never": "לעולם לא",
- "underline-default": "ברירת המחדל של העיצוב או הדפדפן",
+ "underline-default": "×\91ר×\99רת ×\94×\9e×\97×\93×\9c ש×\9c ×\94×¢×\99צ×\95×\91 ×\90×\95 ש×\9c ×\94×\93פ×\93פ×\9f",
"editfont-style": "הגופן בתיבת העריכה:",
"editfont-monospace": "גופן ברוחב קבוע (monospace)",
"editfont-sansserif": "גופן לא מעוצב (sans-serif)",
"delete-hook-aborted": "המחיקה הופסקה על־ידי מבנה Hook.\nלא ניתן הסבר.",
"no-null-revision": "לא ניתן היה ליצור גרסת־דמה בדף \"$1\"",
"badtitle": "כותרת שגויה",
- "badtitletext": "כותרת הדף המבוקש הייתה בלתי תקינה, ריקה, או קישור שגוי לשפה אחרת או למיזם אחר.\nייתכן שהיא מכילה תו אחד או יותר שאינו יכול לשמש בכותרות.",
+ "badtitletext": "כותרת הדף המבוקש הייתה בלתי־תקינה, ריקה, או קישור שגוי לשפה אחרת או למיזם אחר.\nייתכן שהיא מכילה תו אחד או יותר שאינו יכול לשמש בכותרות.",
"title-invalid-empty": "כותרת הדף המבוקש ריקה או מכילה רק שם של מרחב שם.",
"title-invalid-utf8": "כותרת הדף המבוקש מכילה רצף UTF-8 בלתי תקין.",
"title-invalid-interwiki": "כותרת הדף המבוקש מכילה קישור בינוויקי, שלא ניתן להשתמש בו בכותרות.",
"title-invalid-talk-namespace": "כותרת הדף המבוקש מפנה לדף שיחה שאינו יכול להתקיים.",
- "title-invalid-characters": "כותרת הדף המבוקש מכילה תווים בלתי תקינים: \"$1\".",
+ "title-invalid-characters": "כותרת הדף המבוקש מכילה תווים בלתי־תקינים: \"$1\".",
"title-invalid-relative": "בכותרת יש נתיב יחסי. כותרות דפים יחסיות (./, ../) אינן תקינות, כיוון שלעתים קרובות לא ניתן יהיה לגשת אליהן אם הן יטופלו בידי הדפדפן של המשתמש.",
"title-invalid-magic-tilde": "כותרת הדף המבוקש מכילה רצף טילדות מיוחד שאינו תקין (<nowiki>~~~</nowiki>).",
"title-invalid-too-long": "כותרת הדף המבוקש ארוכה מדי. היא צריכה להיות לכל היותר באורך של {{PLURAL:$1|בית אחד|$1 בתים}} בקידוד UTF-8.",
- "title-invalid-leading-colon": "כותרת הדף המבוקש מכילה תו נקודתיים בלתי תקין בתחילתה.",
+ "title-invalid-leading-colon": "כותרת הדף המבוקש מכילה תו נקודתיים בלתי־תקין בתחילתה.",
"perfcached": "המידע הבא הוא עותק שמור בזיכרון המטמון, ועשוי שלא להיות מעודכן. לכל היותר {{PLURAL:$1|תוצאה אחת נשמרת|$1 תוצאות נשמרות}} בזיכרון המטמון.",
"perfcachedts": "המידע הבא הוא עותק שמור בזיכרון המטמון, שעודכן לאחרונה ב־$1. לכל היותר {{PLURAL:$4|תוצאה אחת נשמרת|$4 תוצאות נשמרות}} בזיכרון המטמון.",
- "querypage-no-updates": "×\94×¢×\93×\9b×\95× ×\99×\9d ×\9c×\93×£ ×\96×\94 ×\9bר×\92×¢ ×\9e×\95פסק×\99×\9d, ×\95המידע לא יעודכן באופן שוטף.",
+ "querypage-no-updates": "×\94×¢×\93×\9b×\95× ×\99×\9d ×\9c×\93×£ ×\94×\96×\94 ×\9e×\95פסק×\99×\9d ×\9bר×\92×¢.\nהמידע לא יעודכן באופן שוטף.",
"viewsource": "הצגת מקור",
"viewsource-title": "הצגת המקור של הדף \"$1\"",
"actionthrottled": "הפעולה הוגבלה",
"editinginterface": "<strong>אזהרה:</strong> דף זה הוא אחד הדפים המספקים הודעות מערכת לתוכנה שמפעילה את {{SITENAME}}.\nשינויים בדף הזה ישפיעו על ממשק המשתמש של משתמשים אחרים באתר.",
"translateinterface": "כדי להוסיף או לשנות תרגומים של הודעות מערכת עבור כל אתרי הוויקי, יש להשתמש ב־[https://translatewiki.net/ translatewiki.net], פרויקט התרגום של מדיה־ויקי.",
"cascadeprotected": "דף זה מוגן מעריכה כי הוא מוכלל {{PLURAL:$1|בדף הבא, שמופעלת עליו|בדפים הבאים, שמופעלת עליהם}} הגנה מדורגת:\n$2",
- "namespaceprotected": "אין {{GENDER:|לך|לך|לכם}} הרשאה לערוך דפים במרחב השם <strong>$1</strong>.",
- "customcssprotected": "אין {{GENDER:|לך|לך|לכם}} הרשאה לערוך את דף ה־CSS הזה, משום שהוא מכיל הגדרות אישיות של משתמש אחר.",
- "customjsprotected": "אין {{GENDER:|לך|לך|לכם}} הרשאה לערוך את דף ה־JavaScript הזה, משום שהוא מכיל הגדרות אישיות של משתמש אחר.",
- "mycustomcssprotected": "אין {{GENDER:|לך|לך|לכם}} הרשאה לערוך את דף ה־CSS הזה.",
- "mycustomjsprotected": "אין {{GENDER:|לך|לך|לכם}} הרשאה לערוך את דף ה־JavaScript הזה.",
- "myprivateinfoprotected": "אין {{GENDER:|לך|לך|לכם}} הרשאה לערוך את המידע הפרטי {{GENDER:|שלך|שלך|שלכם}}.",
- "mypreferencesprotected": "אין {{GENDER:|לך|לך|לכם}} הרשאה לערוך את ההעדפות {{GENDER:|שלך|שלך|שלכם}}.",
+ "namespaceprotected": "אין לך הרשאה לערוך דפים במרחב השם <strong>$1</strong>.",
+ "customcssprotected": "אין לך הרשאה לערוך את דף ה־CSS הזה, משום שהוא מכיל הגדרות אישיות של משתמש אחר.",
+ "customjsprotected": "אין לך הרשאה לערוך את דף ה־JavaScript הזה, משום שהוא מכיל הגדרות אישיות של משתמש אחר.",
+ "mycustomcssprotected": "אין לך הרשאה לערוך את דף ה־CSS הזה.",
+ "mycustomjsprotected": "אין לך הרשאה לערוך את דף ה־JavaScript הזה.",
+ "myprivateinfoprotected": "אין לך הרשאה לערוך את המידע הפרטי שלך.",
+ "mypreferencesprotected": "אין לך הרשאה לערוך את ההעדפות שלך.",
"ns-specialprotected": "לא ניתן לערוך דפים מיוחדים.",
"titleprotected": "[[User:$1|$1]] {{GENDER:$1|הפעיל|הפעילה}} על הדף הזה הגנה מפני יצירה.\nהסיבה שניתנה להגנה היא: <em>$2</em>.",
- "filereadonlyerror": "לא ניתן לשנות את הקובץ \"$1\" כיוון שמאגר הקבצים \"$2\" במצב קריאה בלבד.\n\nמנהל המערכת שנעל את המאגר סיפק את ההסבר הבא: \"'''$3'''\".",
- "invalidtitle-knownnamespace": "×\9b×\95תרת ×\91×\9cת×\99־תק×\99× ×\94 ×¢×\9d ×\9eר×\97×\91 ×\94ש×\9d \"$2\" ×\95ש×\9d דף \"$3\"",
- "invalidtitle-unknownnamespace": "×\9b×\95תרת ×\91×\9cת×\99־תק×\99× ×\94 ×¢×\9d ×\9eר×\97×\91 ש×\9d ×\91×\9cת×\99Ö¾×\99×\93×\95×¢ ×\9eספר $1 ×\95ש×\9d דף \"$2\"",
+ "filereadonlyerror": "לא ניתן לשנות את הקובץ \"$1\" כיוון שמאגר הקבצים \"$2\" במצב קריאה בלבד.\n\nמנהל המערכת שנעל את המאגר סיפק את ההסבר הבא: \"$3\".",
+ "invalidtitle-knownnamespace": "×\9b×\95תרת ×\91×\9cת×\99־תק×\99× ×\94 ×¢×\9d ×\9eר×\97×\91 ×\94ש×\9d \"$2\" ×\95×¢×\9d ש×\9d ×\94דף \"$3\"",
+ "invalidtitle-unknownnamespace": "×\9b×\95תרת ×\91×\9cת×\99־תק×\99× ×\94 ×¢×\9d ×\9eר×\97×\91 ש×\9d ×\91×\9cת×\99Ö¾×\99×\93×\95×¢ ×\9eספר $1 ×\95×¢×\9d ש×\9d ×\94דף \"$2\"",
"exception-nologin": "לא בחשבון",
"exception-nologin-text": "נדרשת כניסה לחשבון כדי לראות את הדף הזה או לבצע את הפעולה הזאת.",
"exception-nologin-text-manual": "נדרשת $1 כדי לראות את הדף הזה או לבצע את הפעולה הזאת.",
- "virus-badscanner": "הגדרות שגויות: סורק הווירוסים אינו ידוע: ''$1''",
+ "virus-badscanner": "הגדרות שגויות: סורק הווירוסים אינו ידוע: <em>$1</em>",
"virus-scanfailed": "הסריקה נכשלה (קוד: $1)",
"virus-unknownscanner": "אנטי־וירוס בלתי ידוע:",
"logouttext": "<strong>יצאתם מהחשבון.</strong>\n\nשימו לב שייתכן שדפים מסוימים ימשיכו להיות מוצגים כאילו אתם עדיין מחוברים לחשבון, עד שתנקו את המטמון של הדפדפן שלכם.",
"cannotlogoutnow-title": "לא ניתן לצאת מהחשבון עכשיו",
- "cannotlogoutnow-text": "היציאה אינה אפשרית בעת שימוש ב{{GRAMMAR:תחילית|$1}}.",
+ "cannotlogoutnow-text": "×\94×\99צ×\99×\90×\94 ×\9e×\94×\97ש×\91×\95×\9f ×\90×\99× ×\94 ×\90פשר×\99ת ×\91עת ש×\99×\9e×\95ש ×\91{{GRAMMAR:ת×\97×\99×\9c×\99ת|$1}}.",
"welcomeuser": "ברוך בואך, $1!",
- "welcomecreation-msg": "חשבונך נוצר.\nבאפשרותך להתאים את [[Special:Preferences|ההעדפות]] שלך ב{{grammar:תחילית|{{SITENAME}}}}.",
+ "welcomecreation-msg": "חשבונך נוצר.\nבאפשרותך להתאים את ה[[Special:Preferences|העדפות]] שלך ב{{grammar:תחילית|{{SITENAME}}}}.",
"yourname": "שם משתמש:",
"userlogin-yourname": "שם משתמש",
"userlogin-yourname-ph": "יש להקליד את שם המשתמש",
"userlogin-signwithsecure": "שימוש בחיבור מאובטח",
"cannotlogin-title": "לא ניתן להיכנס לחשבון",
"cannotlogin-text": "הכניסה לחשבון אינה אפשרית.",
- "cannotloginnow-title": "לא ניתן להיכנס עכשיו",
- "cannotloginnow-text": "הכניסה אינה אפשרית בעת שימוש ב{{GRAMMAR:תחילית|$1}}.",
+ "cannotloginnow-title": "×\9c×\90 × ×\99ת×\9f ×\9c×\94×\99×\9b× ×¡ ×\9c×\97ש×\91×\95×\9f ×¢×\9bש×\99×\95",
+ "cannotloginnow-text": "×\94×\9b× ×\99ס×\94 ×\9c×\97ש×\91×\95×\9f ×\90×\99× ×\94 ×\90פשר×\99ת ×\91עת ש×\99×\9e×\95ש ×\91{{GRAMMAR:ת×\97×\99×\9c×\99ת|$1}}.",
"cannotcreateaccount-title": "לא ניתן ליצור חשבונות",
"cannotcreateaccount-text": "יצירת חשבונות באופן ישיר אינה מותרת באתר זה.",
"yourdomainname": "המתחם שלך:",
"createacct-email-ph": "יש להקליד את כתובת הדוא\"ל שלך",
"createacct-another-email-ph": "יש להקליד כתובת דוא\"ל",
"createaccountmail": "שימוש בסיסמה זמנית אקראית ושליחתה לכתובת הדוא\"ל שצוינה",
- "createaccountmail-help": "×\99×\9b×\95×\9c ×\9cש×\9eש ×\9c×\99צ×\99רת ×\97ש×\91×\95×\9f ×\9c×\90×\93×\9d ×\90×\97ר ×\91×\9c×\99 ×\9c×\91רר ×\9e×\94 ×\94ססמה.",
+ "createaccountmail-help": "×\99×\9b×\95×\9c ×\9cש×\9eש ×\9c×\99צ×\99רת ×\97ש×\91×\95×\9f ×¢×\91×\95ר ×\90×\93×\9d ×\90×\97ר ×\91×\9c×\99 ×\9c×\9c×\9e×\95×\93 ×\90ת ×\94ס×\99סמה.",
"createacct-realname": "שם אמיתי (לא חובה)",
"createacct-reason": "סיבה",
"createacct-reason-ph": "סיבה ליצירת חשבון נוסף",
"createacct-benefit-body1": "{{PLURAL:$1|עריכה|עריכות}}",
"createacct-benefit-body2": "{{PLURAL:$1|דף|דפים}}",
"createacct-benefit-body3": "{{PLURAL:$1|תורם|תורמים}} לאחרונה",
- "badretype": "×\94ס×\99ס×\9e×\90×\95ת ש×\94×\96× ×ª ×\90×\99× ×\9f ×\9eת×\90×\99מות.",
+ "badretype": "×\94ס×\99ס×\9e×\90×\95ת ש×\94×\96× ×ª ×\90×\99× ×\9f ת×\95×\90מות.",
"usernameinprogress": "יצירת חשבון עבור שם המשתמש הזה כבר התחילה.\nנא להמתין.",
"userexists": "שם המשתמש שבחרת כבר נמצא בשימוש.\nנא לבחור שם אחר.",
"loginerror": "שגיאה בכניסה לחשבון",
"rcfilters-group-results-by-page": "חלוקה התוצאות לקבוצות לפי דף",
"rcfilters-activefilters": "מסננים פעילים",
"rcfilters-advancedfilters": "מסננים מתקדמים",
- "rcfilters-limit-title": "×\90×\99×\9c×\95 תוצאות להראות",
+ "rcfilters-limit-title": "×\9b×\9e×\94 תוצאות להראות",
"rcfilters-limit-and-date-label": "{{PLURAL:$1|שינוי אחד|$1 שינויים}}, $2",
"rcfilters-date-popup-title": "משך הזמן לחיפוש",
"rcfilters-days-title": "ימים אחרונים",
"ipb_expiry_invalid": "זמן פקיעת החסימה אינו תקין.",
"ipb_expiry_old": "זמן התפוגה כבר עבר.",
"ipb_expiry_temp": "חסימות הכוללות הסתרת שם משתמש חייבות להיות לזמן בלתי מוגבל.",
- "ipb_hide_invalid": "לא ניתן להעלים את החשבון הזה; {{PLURAL:$1|בוצעה ממנו יותר מעריכה אחת|בוצעו ממנו יותר מ֫־$1 עריכות}}.",
+ "ipb_hide_invalid": "לא ניתן להעלים את החשבון הזה; {{PLURAL:$1|בוצעה ממנו יותר מעריכה אחת|בוצעו ממנו יותר מ־$1 עריכות}}.",
"ipb_already_blocked": "המשתמש \"$1\" כבר נחסם.",
"ipb-needreblock": "$1 כבר {{GENDER:$1|חסום|חסומה}}. האם ברצונך לשנות את הגדרות החסימה?",
"ipb-otherblocks-header": "{{PLURAL:$1|חסימה אחרת|חסימות אחרות}}",
"tooltip-n-recentchanges": "רשימת השינויים האחרונים באתר",
"tooltip-n-randompage": "טעינת דף אקראי",
"tooltip-n-help": "המקום למצוא מידע",
- "tooltip-t-whatlinkshere": "רש×\99×\9e×\94 ש×\9c ×\9b×\9c ×\93פ×\99 ×\94×\95×\95×\99ק×\99 ש×\9eקשר×\99×\9d ×\94× ה",
+ "tooltip-t-whatlinkshere": "רש×\99×\9e×\94 ש×\9c ×\9b×\9c ×\93פ×\99 ×\94×\95×\95×\99ק×\99 ש×\9eקשר×\99×\9d ×\9c×\93×£ ×\94×\96ה",
"tooltip-t-recentchangeslinked": "השינויים האחרונים שבוצעו בדפים המקושרים מדף זה",
"tooltip-feed-rss": "הזנת RSS עבור דף זה",
"tooltip-feed-atom": "הזנת Atom עבור דף זה",
"wrongpasswordempty": "Nem adtál meg jelszót. Próbáld meg újra.",
"passwordtooshort": "A jelszónak legalább $1 karakterből kell állnia.",
"passwordtoolong": "A jelszó nem lehet hosszabb $1 karakternél.",
- "passwordtoopopular": "A gyakori jelszavak nem használhatók. Válassz egy egyedibb jelszót.",
+ "passwordtoopopular": "A gyakran használt jelszavak nem használhatók. Válassz olyan jelszót, amit nehezebb kitalálni.",
"password-name-match": "A jelszavadnak különböznie kell a szerkesztőnevedtől.",
"password-login-forbidden": "Ezen felhasználónév és jelszó használata tiltott.",
"mailmypassword": "Jelszó alaphelyzetbe állítása",
"permissionserrorstext": "Ձեզ չի թույլատրվում դա անել հետևյալ {{PLURAL:$1|պատճառով|պատճառներով}}.",
"permissionserrorstext-withaction": "Ձեզ չի թույլատրվում $2 հետևյալ {{PLURAL:$1|պատճառով|պատճառներով}}.",
"recreate-moveddeleted-warn": "'''Զգուշացում. դուք փորձում եք վերստեղծել մի էջ, որը ջնջվել է նախկինում։'''\n\nԽնդրում ենք վերանայել ձեր խմբագրման նպատակահարմարությունը։ Հարմարության համար ստորև բերված են այս էջի ջնջման և տեղափոխման տեղեկամատյանները։",
- "moveddeleted-notice": "Այս էջը հեռացված է։\nԷջի մասին գրառումները տեղափոխման և ջնջման տեղեկամատյանից բերված են ստորև տեղեկության համար։",
+ "moveddeleted-notice": "Այս էջը հեռացված է։\nԷջի մասին գրառումները տեղափոխման, պաշտպանման և ջնջման տեղեկամատյանից բերված են ստորև տեղեկության համար։",
"log-fulllog": "Դիտել ամբողջական տեղեկամատյանը",
"edit-conflict": "Խմբագրման ընհարում։",
"edit-no-change": "Ձեր խմբագրումը անտեսվել է, քանի որ ոչ մի փոփոխություն չի կատարվել տեքստի մեջ։",
"statistics-files": "Adkargita arkivi",
"statistics-edits": "Quanto di redakti pos ke {{SITENAME}} kreesis",
"statistics-edits-average": "Mezavalora quanto di redakti per pagino",
+ "statistics-users": "Enrejistrita [[Special:ListUsers|uzeri]]",
"statistics-users-active": "Aktiva uzeri",
"statistics-users-active-desc": "Uzeri qui facis ula agado dum la lasta {{PLURAL:$1|dio|$1 dii}}",
"pageswithprop": "Pagini kun atributo di pagino",
"booksources": "Fonti di libri",
"booksources-search-legend": "Serchez librala fonti",
"booksources-search": "Serchar",
+ "booksources-text": "Infre vu povas vidar listo di ligili ad altra retsitui qui vendas nova ed uzata libri, ed anke povas havar informi pri la libri quin vu serchabas:\nLa {{SITENAME}} ne mantenas komercala relati kun ta vendeyi mencionata, e la listo ne povas konsideresar rekomendo o vend-anunco.",
"magiclink-tracking-isbn": "Pagini qui uzas ligili ISBN",
"specialloguserlabel": "Agero:",
"speciallogtitlelabel": "Skopo (titulo od {{ns:user}}:uzernomo por uzero):",
"alllogstext": "Kombinata montro di omna 'log'-i di {{SITENAME}} disponebla.\nVu povas stretigar la vidado per la selekto di la tipo di protoloko (log type), l'uzantonomo (case-sensitive), o la pagino afektita (also case-sensitive).",
"logempty": "Nula kombinuri trovesis en la protokolo.",
"showhideselectedlogentries": "Modifikar la videbleso di la selektita eniri di 'log'",
+ "checkbox-select": "Selektez: $1",
+ "checkbox-all": "Omna",
+ "checkbox-none": "Nula",
+ "checkbox-invert": "Inversigar",
"allpages": "Omna pagini",
"nextpage": "Sequanta pagino ($1)",
"prevpage": "Antea pagino ($1)",
"delete-confirm": "Efacar \"$1\"",
"delete-legend": "Efacar",
"historywarning": "<strong>Averto:</strong> La pagino quan vu efaceskas havas historio kun $1 {{PLURAL:$1|revizo|revizi}}:",
+ "historyaction-submit": "Montrez",
"confirmdeletetext": "Vu selektis efacar ica pagino komplete, inkluzite omna modifiki en ol e la kronologio di la modifiki.\n\nVoluntez konfirmar ke vu fakte deziras facar to, ke vu komprenas omna konsequi dil efaco, e ke vu efacos ol segun [[{{MediaWiki:Policy-url}}|la normi pri l'efaco di artikli]].",
"actioncomplete": "Ago kompletigita",
"deletedtext": "\"$1\" efacesis.\nVidez $2 por obtenar registro di recenta efaci.",
"rollback": "Retrorulez redakti",
"rollbacklink": "retrorulez",
"rollbacklinkcount": "nuligar $1 {{PLURAL:$1|modifiko|modifiki}}",
+ "rollbacklinkcount-morethan": "nuligar nemediate plua kam $1 {{PLURAL:$1|redakto|redakti}}",
"rollbackfailed": "Retrorular ne sucesis",
"cantrollback": "Ne esas posibla retrorular. La lasta kontributanto esas la nura autoro di ica pagino.",
"alreadyrolled": "Vu ne povas retrorular la lasta chanjo di [[:$1]] da [[User:$2|$2]] ([[User talk:$2|Diskutez]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nulu pluse ja redaktis o retrorulis ica pagino.\n\nLa lasta chanjo a la pagino esis da [[User:$3|$3]] ([[User talk:$3|Diskutez]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"uctop": "(aktuala)",
"month": "De monato (e plu frue):",
"year": "De yaro (e plu frue):",
- "sp-contributions-newbies": "Montrez nur kontributadi di nova konti",
+ "sp-contributions-newbies": "Montrez nur kontributadi di la nova uzeri",
"sp-contributions-newbies-sub": "Di nova konti",
"sp-contributions-blocklog": "blokusar-registraro",
"sp-contributions-deleted": "efacita {{GENDER:$1|uzero}}-kontributadi",
"pageinfo-toolboxlink": "Informo di ca pagino",
"pageinfo-contentpage": "Konsiderita kontenajo-pagino",
"pageinfo-contentpage-yes": "Yes",
+ "markaspatrolledtext": "Patroliar ica pagino",
"patrol-log-page": "Protokolo pri patroliado",
"previousdiff": "← Plu anciena versiono",
"nextdiff": "Plu recenta versiono →",
"table_pager_prev": "Antea pagino",
"table_pager_first": "Unesma pagino",
"table_pager_last": "Lasta pagino",
+ "table_pager_limit": "Montrez $1 artiklo per pagino",
"table_pager_limit_submit": "Irar",
"table_pager_empty": "Nula rezultajo",
"autosumm-blank": "Pagino vakuigesis",
"wrongpasswordempty": "パスワードを空欄にはできません。\nもう一度やり直してください。",
"passwordtooshort": "パスワードは {{PLURAL:$1|$1 文字}}以上にしてください。",
"passwordtoolong": "パスワードは {{PLURAL:$1|$1 文字}}以下にしてください。",
- "passwordtoopopular": "選択したパスワードはありきたりであるため使用することはできません。誰も思いつかないようなパスワードを選択してください。",
+ "passwordtoopopular": "選択したパスワードはありきたりであるため使用することはできません。簡単に思いつかないようなパスワードを選択してください。",
"password-name-match": "パスワードは利用者名とは異なる必要があります。",
"password-login-forbidden": "この利用者名とパスワードの使用は禁止されています。",
"mailmypassword": "パスワードを再設定",
"Nuevo Paso"
]
},
- "tog-underline": "링크에 밑줄:",
+ "tog-underline": "링크에 밑줄 긋기:",
"tog-hideminor": "최근 바뀜에서 사소한 편집을 숨기기",
"tog-hidepatrolled": "최근 바뀜에서 점검한 편집을 숨기기",
"tog-newpageshidepatrolled": "새 문서 목록에서 검토한 문서를 숨기기",
"tog-enotifminoredits": "문서나 파일의 사소한 편집도 이메일로 알림",
"tog-enotifrevealaddr": "알림 메일에 내 이메일 주소를 밝히기",
"tog-shownumberswatching": "주시하는 사용자 수 보이기",
- "tog-oldsig": "당신의 기존 서명:",
+ "tog-oldsig": "기존 서명:",
"tog-fancysig": "서명을 위키텍스트로 취급 (자동으로 링크를 걸지 않음)",
"tog-uselivepreview": "페이지를 다시 불러오지 않고 미리 보기 표시",
"tog-forceeditsummary": "편집 요약을 쓰지 않았을 때 내게 물어보기",
"tog-useeditwarning": "바꾼 내용을 저장하지 않고 편집 페이지를 벗어날 때 내게 알리기",
"tog-prefershttps": "로그인하는 동안 항상 보안 연결 사용",
"underline-always": "항상",
- "underline-never": "항상 치지 않기",
+ "underline-never": "항상 긋지 않기",
"underline-default": "스킨 또는 브라우저 기본값",
"editfont-style": "편집 영역의 글꼴 형식:",
"editfont-monospace": "고정폭 글꼴",
"prefs-watchlist": "주시문서 목록",
"prefs-editwatchlist": "주시문서 목록 편집",
"prefs-editwatchlist-label": "주시문서 목록의 항목을 편집합니다:",
- "prefs-editwatchlist-edit": "주시문서의 제목을 보고 지우기",
+ "prefs-editwatchlist-edit": "주시문서 목록의 제목 보기 및 지우기",
"prefs-editwatchlist-raw": "주시문서 목록 직접 편집하기",
- "prefs-editwatchlist-clear": "주시문서 목록 지우기",
+ "prefs-editwatchlist-clear": "주시문서 목록 비우기",
"prefs-watchlist-days": "주시문서 목록에서 볼 날짜 수:",
"prefs-watchlist-days-max": "최대 $1{{PLURAL:$1|일}}",
"prefs-watchlist-edits": "주시문서 목록에서 볼 최대 변경사항의 수:",
"prefs-email": "이메일 옵션",
"prefs-rendering": "보이기",
"saveprefs": "저장",
- "restoreprefs": "(모든 부분에서) 모두 기본 설정으로 되돌리기",
+ "restoreprefs": "모두 기본 설정으로 되돌리기(모든 부문)",
"prefs-editing": "편집",
"searchresultshead": "검색",
- "stub-threshold": "링크를 토막글 형식으로 보여줄 문서 크기 ($1):",
- "stub-threshold-sample-link": "ì\83\98í\94\8c",
+ "stub-threshold": "토막글 링크의 형식으로 보여줄 최소 수치($1):",
+ "stub-threshold-sample-link": "ì\98\88ì\8b\9c",
"stub-threshold-disabled": "비활성화됨",
"recentchangesdays": "최근 바뀜에 보여줄 날짜 수:",
"recentchangesdays-max": "최대 $1{{PLURAL:$1|일}}",
"timezoneregion-pacific": "태평양",
"allowemail": "다른 사용자가 내게 이메일을 보낼 수 있게 허용",
"email-allow-new-users-label": "처음 온 사용자들로부터 오는 이메일 허용",
- "email-blacklist-label": "이 사용자들이 내게 이메일을 보내는 것을 금지합니다:",
+ "email-blacklist-label": "이 사용자가 내게 이메일을 보내지 못하게 합니다:",
"prefs-searchoptions": "검색",
"prefs-namespaces": "이름공간",
"default": "기본값",
"prefs-help-signature": "토론 문서에 글을 쓴 후에는 마지막에 서명을 해야 합니다. “<nowiki>~~~~</nowiki>” 기호를 추가하면 서명과 글 작성 시각이 자동으로 입력됩니다.",
"badsig": "서명이 잘못되었습니다.\nHTML 태그를 확인하세요.",
"badsiglength": "서명이 너무 깁니다.\n서명은 $1 {{PLURAL:$1|글자}}보다 짧아야 합니다.",
- "yourgender": "ì\96´ë\96¤ ì\84±ë³\84ë¡\9c í\91\9cì\8b\9cë\90\98ë\8a\94 ê²\83ì\9d\84 ì\84 í\98¸í\95©니까?",
- "gender-unknown": "당신을 언급할 때, 소프트웨어는 가능한 한 성 중립적인 단어를 사용할 것입니다.",
- "gender-male": "위키 문서를 편집하는 남자입니다",
- "gender-female": "ì\9c\84í\82¤ 문ì\84\9c를 í\8e¸ì§\91í\95\98ë\8a\94 ì\97¬ì\9e\90ì\9e\85ë\8b\88ë\8b¤",
+ "yourgender": "ì\96´ë\8a\90 ì\84±ë³\84ë¡\9c ë¬\98ì\82¬í\95\98기를 ì\9b\90í\95\98ì\8b니까?",
+ "gender-unknown": "언급할 때 소프트웨어는 가능한 항상 중성적인 단어를 사용합니다.",
+ "gender-male": "남성이 위키 문서를 편집합니다.",
+ "gender-female": "ì\97¬ì\84±ì\9d´ ì\9c\84í\82¤ 문ì\84\9c를 í\8e¸ì§\91í\95©ë\8b\88ë\8b¤.",
"prefs-help-gender": "이 환경 설정은 선택 사항입니다.\n소프트웨어는 적절한 성별 문법을 사용하여 다른 사용자에게 당신을 언급하는 것을 해결하기 위해 사용됩니다.\n이 정보는 공개됩니다.",
"email": "이메일",
"prefs-help-realname": "실명은 선택 사항입니다.\n실명을 입력하면 당신의 기여에 대한 저작자 표시에 쓰이게 될 수 있습니다.",
"anoneditwarning": "<strong>Hişyarî:</strong> Tu netêketî yî! Navnîşana IP'ya te wê di dîroka guherandina vê rûpelê de bê tomarkirin. Heke tu <strong>[$1 têkevî]</strong> an jî <strong>[$2 hesabekî çêbikî]</strong>, li gel sûdên te yên din guhertinên ku tu bikî jî wê ji nasnavê te re bê atfkirin.",
"anonpreviewwarning": "''Tu ne têketî yî. Tomarkirin wê navnîşana IP'ya te di dîroka guhertinan de nîşan bide.''",
"missingsummary": "<span style=\"color:#990000;\">'''Zanibe:'''</span> Te nivîsekî kurt ji bo guherandinê ra nenivîsand. Eger tu niha carekî din li Tomar xê, guherandinê te vê nivîsekî kurt yê were tomarkirin.",
- "missingcommenttext": "Ji kerema xwe kurteya naverokê li jêr binivisîne.",
+ "missingcommenttext": "Ji kerema xwe kurteya naverokê binivîsîne.",
"missingcommentheader": "<strong>Zanibe:</strong> Te sernav/mijarek nenivîsandîye. Heke tu niha carekî din li ser \"$1\" bitikînî, ev guherandina te bê sernav/mijar wê were tomarkirin.",
"summary-preview": "Pêşdîtina kurtenivîsa guherandinê:",
"subject-preview": "Pêşdîtina mijarê:",
"history-feed-empty": "Rûpela xwestî tune ye. Belkî ew rûpel jê hatibe birîn an jî sernavê wê hatibe guherandin. [[Special:Search|Di wîkîyê de li rûpelên nêzîkî wê bigere]].",
"rev-deleted-comment": "(kurteya guherandinê hate jêbirin)",
"rev-deleted-user": "(navê bikarhêner hate jêbirin)",
- "rev-deleted-event": "(pêkhatin hate jêbirin)",
- "rev-deleted-text-permission": "Ev guhertoya vê rûpelê hatiye jêbirin. Belkî agahî di [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jêbirina têketinê] de hebe.",
+ "rev-deleted-event": "(dêtayên qeydê hate jêbirin)",
+ "rev-deleted-text-permission": "Guhertoya vê rûpelê <strong>hatiye jêbirin</strong>. Dêtayên vê di [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} qeyda jêbirinê] de dikarî bibînî.",
"rev-delundel": "xuyakirinê biguherîne",
"rev-showdeleted": "nîşan bide",
"revisiondelete": "Guhertoyan jê bibe/nebe",
"search-category": "(kategorî $1)",
"search-file-match": "(bi naveroka dosye re lê te)",
"search-suggest": "Gelo mebesta te ev bû: $1",
- "search-interwiki-caption": "Projeyên hevçeng",
+ "search-interwiki-caption": "Netîceyên ji projeyên hevçeng",
"search-interwiki-default": "Encamên ji $1:",
"search-interwiki-more": "(bêhtir)",
"search-relatedarticle": "Pêwendîdar",
"prefs-editwatchlist-clear": "Lîsteya xwe ya şopandinê paqij bike",
"prefs-watchlist-days": "Hejmara rojên ku di lîsteya şopandinê de bê nîşandan:",
"prefs-watchlist-days-max": "Herî zêde $1 {{PLURAL:$1|roj|rojan}}",
- "prefs-watchlist-edits": "Hejmara maximum guhertinê ê di lîsteya şopandinê ya berfirehkirî de bê nîşandanː",
+ "prefs-watchlist-edits": "Hejmara maximum yê guhertinan wê di lîsteya şopandinê de bê nîşandanː",
"prefs-watchlist-edits-max": "Hejmara mezintirîn: 1000",
"prefs-misc": "Eyarên cuda",
"prefs-resetpass": "Şifreyê biguherîne",
- "prefs-changeemail": "Navnîşana e-nameyê biguherîne",
+ "prefs-changeemail": "Navnîşana e-nameyê biguherîne an jî rake",
"prefs-setemail": "Navnîşana e-nameyê binivîse",
"prefs-email": "Vebijarkên Enameyê",
"prefs-rendering": "Rû",
"prefs-registration": "Dema xweqeydkirinê:",
"yourrealname": "Navê te yê rast:",
"yourlanguage": "Ziman:",
- "yourvariant": "Cuda:",
+ "yourvariant": "Varyanta zimanê naverokê:",
"yournick": "Bernavkê nû (ji bo îmzeyê):",
"badsig": "Îmzeya ne derbasdar! Li HTML binêre ka sedema şaşbûnê çiye.",
"badsiglength": "Navê te zêde dirêj e; pêwîst e di bin {{PLURAL:$1|nîşanekê|nîşanan}} de be.",
"prefs-displaywatchlist": "Vebijarkan nîşan bide",
"prefs-diffs": "Cudahî",
"userrights": "Îdarekirina mafên bikarhêneran",
- "userrights-lookup-user": "Birêvebirina koman",
+ "userrights-lookup-user": "Bikarhênerek bibijêre",
"userrights-user-editname": "Navekî bikarhêneriyê binivîse:",
- "editusergroup": "Komên bikarhêneran biguherîne",
+ "editusergroup": "Komên bikarhêneran nîşan bide",
"editinguser": "Mafên bikarhêner '''[[User:$1|$1]]''' ([[User talk:$1|{{int:talkpagelinktext}}]]{{int:pipe-separator}}[[Special:Contributions/$1|{{int:contribslink}}]]) tên guhertin",
"userrights-editusergroup": "Komên bikarhêneran biguherîne",
"saveusergroups": "Komên {{GENDER:$1|bikarhêneran}} tomar bike",
"action-movefile": "vê daneyê bigerîne",
"action-upload": "vê daneyê bar bike",
"action-delete": "vê rûpelê jê bibe",
- "action-deleterevision": "Vê revîzyonê je bibe",
+ "action-deleterevision": "revîzyonan jê bibe",
"action-deletedhistory": "dîroka vê rûpelê jêbirî bibîne",
"action-browsearchive": "li rûpelên jêbirî bigere",
"action-undelete": "vê rûpelê jê nebe",
"notanarticle": "Ne gotar e",
"watchlist-details": "{{PLURAL:$1|Rûpelekî|$1 rûpel}} li ser lîsteya te ya şopandinê ye (xeynî rûpelên gotûbêjê).",
"wlheader-enotif": "Agahdariya e-nameyan hate çalakkirin",
- "wlheader-showupdated": "Ev rûpela hatî guhertin dema te lê meyzand bi <strong>nivîsa stûr<strong> tê xuyakirin.",
- "wlnote": "Ji $3, $4 heta niha {{PLURAL:$1|guherandinê|</strong>$1</strong> guherandinên}} dawî yê {{PLURAL:$2|saetê|</strong>$2</strong> saetên}} dawî {{PLURAL:$1|tê|tên}} dîtin.",
+ "wlheader-showupdated": "Ev rûpela hatî guhertin dema te lê meyzand bi <strong>nivîsa stûr</strong> tê xuyakirin.",
+ "wlnote": "Ji $3, $4 heta niha {{PLURAL:$1|guherandinê|<strong>$1</strong> guherandinên}} dawî yê {{PLURAL:$2|saetê|<strong>$2</strong> saetên}} dawî {{PLURAL:$1|tê|tên}} dîtin.",
"wlshowlast": "Guhertinên berî $1 saetan, $2 rojan nîşan bide",
"watchlist-hide": "Veşêre",
"watchlist-submit": "Nîşan bide",
"newimages-summary": "Op dees speciaal pazjena waere de meis recènt toegevoogde bestenj weergegaeve.",
"newimages-legend": "Bestandjsnaam",
"newimages-label": "Bestandjsnaam (of deel daarvan):",
+ "newimages-user": "IP-adres of gebroekersnaam",
+ "newimages-newbies": "Tuin allein de biedrage van nuuj gebroekers",
+ "newimages-showbots": "Tuin botuploads",
+ "newimages-hidepatrolled": "Versjtaek gecontroleerde uploads",
+ "newimages-mediatype": "Mediaformaot:",
"noimages": "Niks te zeen.",
+ "gallery-slideshow-toggle": "Sjakel miniature",
"ilsubmit": "Zeuk",
"bydate": "op datum",
"sp-newimages-showfrom": "Tuin nuuj besjtande vanaaf $2, $1",
"confirmemail_body_set": "Emes, waersjienlik doe, met 't IP-adres $1,\nhaet 't e-mailadres geregistreerd veur gebroeker \"$2\" op {{SITENAME}} ingesteld óp dit e-mailadres.\n\nÄöpen de volgende verwiezing in diene webbrowser om te bevestige des toe deze gebroeker bis en om de e-mailmeugelikhejen op {{SITENAME}} opnuuj te activere:\n\n$3\n\nEs se dichzelf *neet* haes aangemeld, volg den de volgende verwiezing om de bevestiging van dien e-mailadres te annulere:\n\n$5\n\nDe bevestigingscode vervilt op $4.",
"confirmemail_invalidated": "De e-mailbevestiging is geannuleerdj",
"invalidateemail": "E-mailbevestiging annulere",
+ "notificationemail_subject_changed": "geregistreerd e-mailadres van {{SITENAME}} is verangerd",
+ "notificationemail_subject_removed": "geregistreerd e-mailadres van {{SITENAME}} is eweggehaold",
"scarytranscludedisabled": "[Interwikitransclusie is oetgesjakeld]",
"scarytranscludefailed": "[Sjabloon $1 kós neet opgehaold waer]",
"scarytranscludetoolong": "[URL is te lank]",
"version-ext-colheader-description": "Besjrieving",
"version-ext-colheader-credits": "Sjrievers",
"version-license-title": "Licentie veur $1",
+ "version-credits-title": "Vermeljinge veur $1",
+ "version-credits-not-found": "Gein gedetailleerde meljinge zint aangetroffe veur dees oetbreijing.",
"version-poweredby-credits": "Deze wiki weurt aangedreve door '''[https://www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
"version-poweredby-others": "anger",
+ "version-poweredby-translators": "translatewiki.net-euverzètters",
"version-license-info": "MediaWiki is vrieje sofware; de kins MediaWiki verspreien en/of aanpassen onger de veurwaerde van de GNU General Public License wie gepubliceerd door de Free Software Foundation; ofwaal versie 2 van de Licentie, of - nao diene wönsj - innig later versie.\n\nMediaWiki weurd verspreid in de haop det 't nuttig is, mer ZONGER INNIG GARANTIE; zonger zelfs de implicitiete garantie van VERKOUPBAARHEID of GESJIKHEID VEUR INNIG DOEL IN 'T BIEZÖNJER. Zuuch de GNU General Public License veur mier informatie.\n\nSame mit dit programma heurs se 'n [{{SERVER}}{{SCRIPTPATH}}/COPYING kopie van de GNU General Public License] te höbben ontvange; zo neet, sjrief den nao de Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA of [//www.gnu.org/licenses/old-licenses/gpl-2.0.html laes de licentie online].",
"version-software": "Geïnstallieërde sofwaer",
"version-software-product": "Perduk",
"tags-active-no": "Nae",
"tags-edit": "bewerking",
"tags-hitcount": "$1 {{PLURAL:$1|wieziging|wieziginge}}",
+ "tags-deactivate-reason": "Raeje:",
+ "tags-deactivate-submit": "Deaktiveer",
"comparepages": "Vergeliek pazjena's",
"compare-page1": "Paasj 1",
"compare-page2": "Paasj 2",
"Macofe",
"V6rg",
"Nemo bis",
- "S4b1nuz E.656"
+ "S4b1nuz E.656",
+ "Ruthven"
]
},
"tog-underline": "Sottolinia 'e jonte:",
"permissionserrorstext-withaction": "Nun haje premmesse abbastante pe' $2, {{PLURAL:$1|'o mutivo è chesto|'e mutive so' chiste}}:",
"contentmodelediterror": "Vuje nun putite cagnà sta verziona pecché 'o mudell' 'e cuntenute è <code>$1</code>, ca cagnasse nu poco nfacc' 'o mudell' 'e mò d' 'a paggena è <code>$2</code>.",
"recreate-moveddeleted-warn": "'''Attenziò: staje a crià na paggena scancellata già.'''\n\nVire si è bbuono 'e cuntinuà a cagnà sta paggena. L'elenco ch' 'e relative scancellamiente e spustamente s'è scritto ccà abbascio pe' ffà comodo:",
- "moveddeleted-notice": "Sta paggena è stata scancellata.\nL'elenco d' 'e relative scancellamiente e spustamente s'è scritto ccà abbascio pe' n'avé nfurmazione.",
+ "moveddeleted-notice": "Sta paggena è stata scancellata.\n'A lista d' 'e relative scancellamiente e spustamente sta cca 'bbascio pe' n'avé 'nfurmazione.",
"moveddeleted-notice-recent": "Scusate, sta mmasciata è stata scancellata mo mo (dint'a sti 24 ore).\n\nL'aziune 'e scancellazione e spustamento pe' sta paggena so dispunibbele ccà p' 'a cumpretezza.",
"log-fulllog": "Vide log sano",
"edit-hook-aborted": "'O cagnamiento è stato annullato 'a 'o «hook».\nNun dette spiegazione nisciuna.",
"rcshowhidecategorization": "$1 categorizzaziona d' 'a paggena",
"rcshowhidecategorization-show": "Faje vedé",
"rcshowhidecategorization-hide": "Annascunne",
- "rclinks": "Faje vedé ll'urdeme $1 cagnamiente dint' ll'urdeme $2 juorne",
+ "rclinks": "Faje vedé ll'urdeme $1 cagnamienti dint' ll'urdeme $2 juorne",
"diff": "diff",
"hist": "cron",
"hide": "annascunne",
"unwatchthispage": "Nun cuntrullà cchiù sta paggena",
"notanarticle": "Chesta paggena nun è na voce",
"notvisiblerev": "'A verzione è stata scancellata",
- "watchlist-details": "L'elenco 'e paggene cuntrullate cuntene {{PLURAL:$1|na paggena (e pure 'a paggena 'e chiacchiera)|$1 paggene (e pure 'e paggene 'e chiacchiera}}.",
+ "watchlist-details": "L'elenco 'e paggene cuntrullate tene {{PLURAL:$1|na paggena (e pure 'a paggena 'e chiacchiera)|$1 paggene (e pure 'e ppaggene 'e chiacchiera}}.",
"wlheader-enotif": "'A funzione 'e notifiche e-mail è appicciata.",
"wlheader-showupdated": "* 'E paggene cca so' state cagnate a l'urdema visita avevano so' nzignate ccà 'n '''grassetto'''.",
"wlnote": "Ccà abbascio {{PLURAL:$1|è elencato 'o cagnamiento cchiù ricente|songo elencate 'e <strong>$1</strong> cagnamiente cchiù recente}} {{PLURAL:$2|int'a ll'urdema ora|int' 'e ll'urdeme <strong>$2</strong> ore}}; 'e date songo agghiurnate 'o $3, $4.",
"wrongpasswordempty": "Du oppga ikke noe passord. Prøv igjen.",
"passwordtooshort": "Passord må ha minst {{PLURAL:$1|ett tegn|$1 tegn}}.",
"passwordtoolong": "Passord kan ikke overskride {{PLURAL:$1|1 character|$1 characters}}.",
- "passwordtoopopular": "Nylig valgt passord kan ikke brukes. Vennligst bruk et mer unikt passord.",
+ "passwordtoopopular": "Hyppig brukte passord kan ikke brukes. Vennligst bruk et mer unikt passord.",
"password-name-match": "Passord og brukernavn kan ikke være det samme.",
"password-login-forbidden": "Bruken av dette brukernavnet og passordet er forbudt.",
"mailmypassword": "Tilbakestill passord",
"expansion-depth-exceeded-warning": "Sida har overskredet ekspansjonsdybden",
"parser-unstrip-loop-warning": "«Unstrip»-loop påvist",
"unstrip-depth-warning": "Rekursjonsgrense for taggfjerning overskredet ($1)",
+ "unstrip-depth-category": "Sider hvor dybdegrensen for unstrip er nådd",
+ "unstrip-size-warning": "Størrelsesgrensen for unstrip er nådd ($1)",
+ "unstrip-size-category": "Sider hvor størrelsesgrensen for unstrip er nådd",
"converter-manual-rule-error": "En feil ble oppdaget i en manuell språkkonverteringsregel",
"undo-success": "Redigeringen kan omgjøres. Sjekk sammenligningen under for å bekrefte at du vil gjøre dette, og lagre endringene for å fullføre omgjøringen.",
"undo-failure": "Redigeringen kunne ikke omgjøres på grunn av konflikterende etterfølgende redigeringer.",
"stub-threshold-disabled": "Deaktivert",
"recentchangesdays": "Antall dager som skal vises i siste endringer:",
"recentchangesdays-max": "Maks $1 {{PLURAL:$1|dag|dager}}",
- "recentchangescount": "Antall redigeringer som skal vises som standard:",
+ "recentchangescount": "Antall redigeringer som skal vises som standard i siste endringer, sidehistorikker og logger:",
"prefs-help-recentchangescount": "Maksimalt antall: 1000",
"prefs-help-watchlist-token2": "Dette er den hemmelige nøkkelen til webmatingen for din overvåkningsliste.\nEnhver som kjenner nøkkelen vil kunne lese din overvåkningsliste, så ikke vis den til andre.\nOm du trenger å gjøre det kan du [[Special:ResetTokens|nullstille nøkkelen]].",
"savedprefs": "Innstillingene ble lagret.",
"limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|byte|bytes}}",
"limitreport-expansiondepth": "Største ekspansjonsdybde",
"limitreport-expensivefunctioncount": "Antall kostbare parserfunksjoner",
+ "limitreport-unstrip-depth": "Rekursjonsdybde for unstrip",
+ "limitreport-unstrip-size": "Størrelse for unstrip etter utvidelse",
"limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|byte}}",
"expandtemplates": "Utvid maler",
"expand_templates_intro": "Denne spesialsiden tar wikitekst og utvider rekusivt alle maler brukt i teksten. \nDen utvider også alle parserfunksjoner som \n<code><nowiki>{{</nowiki>#language:…}}</code>, og variabler som \n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nFaktisk utvider den det meste innkapslet i doble krøllparenteser.",
"apisandbox-sending-request": "Wysyłanie zapytania API…",
"apisandbox-loading-results": "Pobieranie wyników API...",
"apisandbox-results-error": "Wystąpił błąd podczas pobierania odpowiedzi na zapytanie API: $1.",
+ "apisandbox-results-login-suppressed": "To żądanie zostało przetworzone jako wylogowany użytkownik, ponieważ można go obejść w zabezpieczeniach przeglądarki Same-Origin. Zauważ, że automatyczna obsługa tokenów API piaskownicy nie działa poprawnie z takimi żądaniami, proszę wypełnić je ręcznie.",
"apisandbox-request-selectformat-label": "Pokaż dane z zapytania jako:",
"apisandbox-request-format-url-label": "zapytanie w adresie URL",
"apisandbox-request-url-label": "URL zapytania:",
"ip_range_invalid": "Niepoprawny zakres adresów IP.",
"ip_range_toolarge": "Zakresy IP większe niż /$1 są niedozwolone.",
"ip_range_exceeded": "Zakres IP przekracza zakres maksymalny. Dozwolony zakres to /$1.",
+ "ip_range_toolow": "Zakresy adresów IP są niedozwolone.",
"proxyblocker": "Blokowanie proxy",
"proxyblockreason": "Twój adres IP został zablokowany, ponieważ jest to adres otwartego proxy.\nO tym poważnym problemie dotyczącym bezpieczeństwa należy poinformować dostawcę Internetu lub pomoc techniczną.",
"sorbsreason": "Twój adres IP znajduje się na liście serwerów open proxy w DNSBL, używanej przez {{GRAMMAR:B.lp|{{SITENAME}}}}.",
"authmanager-create-disabled": "Utworzenie konta jest wyłączone.",
"authmanager-create-from-login": "Aby utworzyć konto, wypełnij odpowiednie pola.",
"authmanager-create-not-in-progress": "Tworzenie konta nie jest wykonywane lub dane sesji zostały utracone. Zacznij od początku.",
+ "authmanager-create-no-primary": "Podanych danych uwierzytelniających nie można użyć do utworzenia konta.",
"authmanager-link-not-in-progress": "Tworzenie konta nie jest wykonywane lub dane sesji zostały utracone. Zacznij od początku.",
"authmanager-authplugin-setpass-failed-title": "Zmiana hasła nie powiodła się",
"authmanager-authplugin-setpass-failed-message": "Wtyczka do uwierzytelniania uniemożliwiła zmianę hasła.",
"undelete-cantedit": "Nie możesz odtworzyć tej strony, ponieważ nie masz uprawnień do edytowania tej strony.",
"undelete-cantcreate": "Nie możesz odtworzyć tej strony, ponieważ nie istnieje strona o tej nazwie, a nie masz uprawnień do jej utworzenia.",
"pagedata-title": "Dane ze strony",
+ "pagedata-text": "Ta strona udostępnia interfejs danych do stron. Podaj tytuł strony w adresie URL, używając składni podstrony.\n* Negocjacja treści obowiązuje w oparciu o nagłówek Accept Twojego klienta. Oznacza to, że dane strony będą dostarczane w formacie preferowanym przez klienta.",
"pagedata-not-acceptable": "Nie znaleziono pasującego formatu. Obsługiwane typy MIME: $1",
"pagedata-bad-title": "Niepoprawny tytuł: $1."
}
"wrongpasswordempty": "A palavra-passe não foi introduzida. \nIntroduza-a, por favor.",
"passwordtooshort": "A palavra-passe deve ter no mínimo $1 {{PLURAL:$1|carácter|caracteres}}.",
"passwordtoolong": "A palavra-passe não pode exceder $1 {{PLURAL:$1|carácter|caracteres}}.",
- "passwordtoopopular": "Não podem ser usadas palavras-passe vulgares. Escolha uma palavra-passe mais original, por favor.",
+ "passwordtoopopular": "Não podem ser usadas palavras-passe vulgares. Escolha uma palavra-passe mais difícil de adivinhar, por favor.",
"password-name-match": "A sua palavra-passe tem de ser diferente do seu nome de utilizador.",
"password-login-forbidden": "Foi proibido o uso deste nome de utilizador e palavra-passe.",
"mailmypassword": "Reiniciar a palavra-passe",
"watchlistedit-normal-done": "{{PLURAL:$1|Foi removida uma página|Foram removidas $1 páginas}} da sua lista de páginas vigiadas:",
"watchlistedit-raw-title": "Editar a lista de páginas vigiadas em forma de texto",
"watchlistedit-raw-legend": "Editar a lista de páginas vigiadas em forma de texto",
- "watchlistedit-raw-explain": "A lista de páginas vigiadas é apresentada abaixo.\nPode adicionar ou remover linhas, para aumentar ou reduzir a lista.\nListe uma só página por linha.\nQuando terminar, clique \"{{int:Watchlistedit-raw-submit}}\".\nTambém pode [[Special:EditWatchlist|editar a lista da maneira convencional]].",
+ "watchlistedit-raw-explain": "A lista das páginas vigiadas é apresentada abaixo.\nPode adicionar ou remover linhas, para aumentar ou reduzir a lista.\nListe uma só página por linha.\nQuando terminar, clique \"{{int:Watchlistedit-raw-submit}}\".\nTambém pode [[Special:EditWatchlist|usar o editor padrão]].",
"watchlistedit-raw-titles": "Páginas:",
"watchlistedit-raw-submit": "Atualizar a lista de páginas vigiadas",
"watchlistedit-raw-done": "A sua lista de páginas vigiadas foi atualizada.",
"changeemail-none": "(کوئی وی کائنی)",
"changeemail-password": "تہاݙا {{SITENAME}} پاس ورڈ:",
"changeemail-submit": "ای-میل بدلو",
+ "resettokens": "ٹوکناں دی نویں ترتیب",
"resettokens-tokens": "ٹوکن",
"resettokens-token-label": "$1 (موجودہ قدر: $2)",
"bold_sample": "موٹی لکھائی",
"diff-empty": "(کوئی فرق کائنی)",
"searchresults": "کھوج دا نتارا",
"searchresults-title": "\"$1\" دے کھوج نتارے",
+ "titlematches": "ورقے دا ناں رلدے",
+ "textmatches": "ورقے دی لکھت رلدی ہے",
+ "notextmatches": "ورقے دی لکھت نی رلدی",
"prevn": "پچھلے {{PLURAL:$1|$1}}",
"nextn": "اگلے {{PLURAL:$1|$1}}",
"prev-page": "پچھلا ورقہ",
"grant-createaccount": "کھاتے کھولو",
"grant-uploadfile": "نویاں فائلاں اپ لوڈ کرو",
"grant-basic": "بنیادی حقوق",
+ "grant-viewmywatchlist": "آپݨی نظریں ہیٹھ تندیر ݙیکھو",
"newuserlogpage": "کھاتہ بݨاوݨ آلی لاگ",
"rightslog": "ورتݨ والے دے حقاں دی لاگ",
"action-read": "ایہ ورقہ پڑھو",
"action-createaccount": "ایہ ورتݨ آلا کھاتہ کھولو",
"action-move": "ایہ ورقہ ٹورو",
"action-movefile": "ایہ فائل ٹورو",
+ "action-upload": "ایہ فائل اپ لوڈ کرو",
"action-delete": "ایہ ورقہ مٹاؤ",
"action-sendemail": "ای میلاں بھیجو",
+ "action-purge": "ایہ ورقہ تازہ تے صاف کرو",
"enhancedrc-history": "پچھلا کم",
"recentchanges": "نویاں تبدیلیاں",
"recentchanges-legend": "اِختیاراتِ حالیہ تبدیلیاں",
"recentchanges-legend-heading": "<strong>اختصارات:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ایہ وی ݙیکھو [[Special:NewPages|نویں ورقیاں دی لسٹ]])",
"recentchanges-submit": "ݙیکھاؤ",
+ "rcfilters-tag-remove": "ہٹاؤ '$1'",
+ "rcfilters-activefilters": "فعال نتارے",
+ "rcfilters-advancedfilters": "ودھائے نتارے",
+ "rcfilters-limit-title": "ݙیکھاوݨ کیتے نتیجے",
"rcfilters-limit-and-date-label": "$1{{PLURAL:$1|تبدیلی|تبدیلیاں}}، $2",
+ "rcfilters-date-popup-title": "ڳولݨ کیتے ویلے دی مدت",
"rcfilters-days-title": "موجودہ ݙینہ",
"rcfilters-hours-title": "موجودہ گھنٹے",
+ "rcfilters-days-show-days": "$1 {{PLURAL:$1|ݙینہ}}",
+ "rcfilters-days-show-hours": "$1 {{PLURAL:$1|گھنٹہ|گھنٹے}}",
+ "rcfilters-highlighted-filters-list": "نمایاں: $1",
+ "rcfilters-quickfilters": "محفوظ نتارے",
"rcfilters-savedqueries-rename": "نواں ناں لکھو",
"rcfilters-savedqueries-setdefault": "ݙیفالٹ بݨاؤ",
"rcfilters-savedqueries-unsetdefault": "ݙیفالٹ توں ہٹاؤ",
"createacct-another-username-ph": "Shtypni emrin e përdoruesit",
"yourpassword": "Fjalëkalimi:",
"userlogin-yourpassword": "Fjalëkalimi",
- "userlogin-yourpassword-ph": "Shtypni fjalëkalimin tuaj",
- "createacct-yourpassword-ph": "Shtypni një fjalëkalim",
+ "userlogin-yourpassword-ph": "Fut fjalëkalimin tënd",
+ "createacct-yourpassword-ph": "Fut një fjalëkalim",
"yourpasswordagain": "Fusni fjalëkalimin përsëri",
"createacct-yourpasswordagain": "Konfirmoni fjalëkalimin",
- "createacct-yourpasswordagain-ph": "Shtypni fjalëkalimin përsëri",
+ "createacct-yourpasswordagain-ph": "Fut fjalëkalimin përsëri",
"userlogin-remembermypassword": "Më mbaj të kyçur",
"userlogin-signwithsecure": "Përdor lidhje të sigurtë",
"cannotlogin-title": "Nuk mund të kyçeni",
"userlogin-reauth": "Duhet të identifikoheni përsëri për të verifikuar që jeni {{GENDER:$1|$1}}",
"userlogin-createanother": "Krijo një llogari tjeter",
"createacct-emailrequired": "Posta elektronike",
- "createacct-emailoptional": "Adresa Elektronike (me dëshirë)",
+ "createacct-emailoptional": "Adresa elektronike (me dëshirë)",
"createacct-email-ph": "Fusni adresën tuaj elektronike",
"createacct-another-email-ph": "Vendos adresën e postës elektronike",
"createaccountmail": "Përdorni një fjalëkalim të përkohshëm të rastit dhe dërgojeni atë në adresën e specifikuar te email",
"recentchanges-label-unpatrolled": "Непатролирана измена",
"recentchanges-label-plusminus": "Промена величине странице у бајтовима",
"recentchanges-legend-heading": "<strong>Легенда:</strong>",
- "recentchanges-legend-newpage": "[[w:sr:Посебно:НовеСтране|<u>Н</u>ова страница]]",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|списак нових страница]])",
"recentchanges-submit": "Прикажи",
"rcfilters-tag-remove": "Уклоните филтер „$1”",
"rcfilters-legend-heading": "<strong>Списак скраћеница:</strong>",
"tooltip-pt-userpage": "{{GENDER:|Ваша}} корисничка страница",
"tooltip-pt-anonuserpage": "Корисничка страница за ИП адресу с које уређујете",
"tooltip-pt-mytalk": "{{GENDER:|Ваша}} страница за разговор",
- "tooltip-pt-anontalk": "Разговор о изменама с ове ИП адресе",
+ "tooltip-pt-anontalk": "Разговор о изменама са ове IP адресе",
"tooltip-pt-preferences": "{{GENDER:|Ваша}} подешавања",
"tooltip-pt-watchlist": "Списак страница које надгледате",
"tooltip-pt-mycontris": "Списак {{GENDER:|Ваших}} доприноса",
"tooltip-pt-anoncontribs": "Списак измена направљених са ове IP адресе",
- "tooltip-pt-login": "Ð\9fÑ\80епоÑ\80Ñ\83Ñ\87Ñ\83Ñ\98емо вам да Ñ\81е пÑ\80иÑ\98авиÑ\82е, иако Ñ\82о ниÑ\98е обавезно.",
+ "tooltip-pt-login": "Ð\9fÑ\80епоÑ\80Ñ\83Ñ\87Ñ\83Ñ\98емо Ð\92ам да Ñ\81е пÑ\80иÑ\98авиÑ\82е, иако Ñ\82о ниÑ\98е обавезно",
"tooltip-pt-login-private": "Морате да се пријавите да бисте користили овај Вики",
"tooltip-pt-logout": "Одјавите се",
- "tooltip-pt-createaccount": "Ð\9eÑ\85Ñ\80абÑ\80Ñ\83Ñ\98емо ваÑ\81 да оÑ\82воÑ\80иÑ\82е налог и пÑ\80иÑ\98авиÑ\82е Ñ\81е али то није обавезно",
+ "tooltip-pt-createaccount": "Ð\9fÑ\80епоÑ\80Ñ\83Ñ\87иÑ\98емо Ð\92ам да оÑ\82воÑ\80иÑ\82е налог и пÑ\80иÑ\98авиÑ\82е Ñ\81е, иако то није обавезно",
"tooltip-ca-talk": "Разговор о страници са садржајем",
"tooltip-ca-edit": "Уредите ову страницу",
"tooltip-ca-addsection": "Започните нови одељак",
"tooltip-ca-move": "Премести ову страницу",
"tooltip-ca-watch": "Додајте ову страницу на списак надгледања",
"tooltip-ca-unwatch": "Уклони ову страницу са списка надгледања",
- "tooltip-search": "Ð\9fÑ\80еÑ\82Ñ\80ажи",
+ "tooltip-search": "Ð\9fÑ\80еÑ\82Ñ\80ага",
"tooltip-search-go": "Идите на страницу с овим именом, ако постоји",
"tooltip-search-fulltext": "Претражите странице с овим текстом",
"tooltip-p-logo": "Посетите главну страну",
"feedback-thanks": "Хвала! Ваша повратна информација је постављена на страницу „[$2 $1]“.",
"feedback-thanks-title": "Хвала вам!",
"feedback-useragent": "Кориснички агент:",
- "searchsuggest-search": "Претражи",
+ "searchsuggest-search": "Претражи пројекат {{SITENAME}}",
"searchsuggest-containing": "садржи...",
"api-error-badtoken": "Унутрашња грешка: неисправан жетон.",
"api-error-emptypage": "Стварање нових празних страница није дозвољено.",
"activeusers-intro": "นี่คือรายการผู้ใช้ที่มีความเคลื่อนไหวใด ๆ ในช่วง $1 วันหลังสุด",
"activeusers-count": "$1 ปฏิบัติการ{{PLURAL:$1|}} ในช่วง $3 วันหลังสุด",
"activeusers-from": "แสดงผู้ใช้เริ่มจาก:",
+ "activeusers-groups": "แสดงผู้ใช้ที่อยู่ในกลุ่ม:",
+ "activeusers-excludegroups": "ไม่รวมผู้ใช้ที่อยู่ในกลุ่ม:",
"activeusers-noresult": "ไม่พบผู้ใช้",
"activeusers-submit": "แสดงผู้ใช้ที่ยังเคลื่อนไหว",
"listgrouprights": "สิทธิกลุ่มผู้ใช้",
"rollback-success": "ย้อนการแก้ไขโดย $1; \nเปลี่ยนกลับไปรุ่นล่าสุดโดย $2",
"rollback-success-notify": "ย้อนการแก้ไขโดย $1;\nเปลี่ยนกลับไปรุ่นล่าสุดโดย $2 [$3 แสดงการเปลี่ยนแปลง]",
"sessionfailure-title": "ช่วงเวลาสื่อสารล้มเหลว",
- "sessionfailure": "à¸\94ูà¹\80หมืà¸à¸\99มีà¸\9bัà¸\8dหาà¸\81ัà¸\9aà¸\8aà¹\88วà¸\87à¹\80วลาสืà¹\88à¸à¸ªà¸²à¸£à¸¥à¹\87à¸à¸\81à¸à¸´à¸\99à¸\82à¸à¸\87à¸\84ุà¸\93\nà¸\81ารà¸\81ระà¸\97ำà¸\99ีà¹\89à¸\96ูà¸\81ยà¸\81à¹\80ลิà¸\81à¹\80à¸\9bà¹\87à¸\99à¸\81ารà¸\9bà¹\89à¸à¸\87à¸\81ัà¸\99à¸\81ารลัà¸\81ลà¸à¸\9aà¸\8aà¹\88วà¸\87à¹\80วลาสืà¹\88à¸à¸ªà¸²à¸£à¹\84วà¹\89à¸\81à¹\88à¸à¸\99 \nà¸\81ลัà¸\9aà¹\84à¸\9bหà¸\99à¹\89าà¸\97ีà¹\88à¹\81ลà¹\89ว à¹\82หลà¸\94หà¸\99à¹\89าà¹\83หมà¹\88 à¹\81ลà¹\89วลà¸à¸\87อีกครั้ง",
+ "sessionfailure": "à¸\94ูà¹\80หมืà¸à¸\99มีà¸\9bัà¸\8dหาà¸\81ัà¸\9aà¸\8aà¹\88วà¸\87à¹\80วลาสืà¹\88à¸à¸ªà¸²à¸£à¸¥à¹\87à¸à¸\81à¸à¸´à¸\99à¸\82à¸à¸\87à¸\84ุà¸\93\nà¸\81ารà¸\81ระà¸\97ำà¸\99ีà¹\89à¸\96ูà¸\81ยà¸\81à¹\80ลิà¸\81à¹\80à¸\9bà¹\87à¸\99à¸\81ารà¸\9bà¹\89à¸à¸\87à¸\81ัà¸\99à¸\81ารลัà¸\81ลà¸à¸\9aà¸\8aà¹\88วà¸\87à¹\80วลาสืà¹\88à¸à¸ªà¸²à¸£à¹\84วà¹\89à¸\81à¹\88à¸à¸\99 \nà¸\81รุà¸\93าà¸\81รà¸à¸\81à¹\81à¸\9aà¸\9aอีกครั้ง",
"changecontentmodel-title-label": "ชื่อหน้า:",
"changecontentmodel-reason-label": "เหตุผล:",
"changecontentmodel-submit": "ความเปลี่ยนแปลง",
"tooltip-namespace_association": "เลือกกล่องนี้เพื่อรวมเนมสเปซคุยหรือเรื่องที่เกี่ยวข้องกับเนมสเปซที่เลือกด้วย",
"blanknamespace": "(หลัก)",
"contributions": "เรื่องที่{{GENDER:$1|ผู้ใช้}}นี้เขียน",
- "contributions-title": "à¹\80รืà¹\88à¸à¸\87à¸\97ีà¹\88à¹\80à¸\82ียà¸\99โดย $1",
+ "contributions-title": "à¹\80รืà¹\88à¸à¸\87à¸\97ีà¹\88มีสà¹\88วà¸\99รà¹\88วมโดย $1",
"mycontris": "เรื่องที่มีส่วนร่วม",
- "anoncontribs": "à¹\80รืà¹\88à¸à¸\87à¸\97ีà¹\88à¹\80à¸\82ียà¸\99",
+ "anoncontribs": "à¹\80รืà¹\88à¸à¸\87à¸\97ีà¹\88มีสà¹\88วà¸\99รà¹\88วม",
"contribsub2": "สำหรับ {{GENDER:$3|$1}} ($2)",
"contributions-userdoesnotexist": "บัญชีผู้ใช้ \"$1\" ยังไม่ได้ลงทะเบียน",
"nocontribs": "ไม่พบการเปลี่ยนแปลงตรงกับเงื่อนไขเหล่านี้",
"sp-contributions-newbies-sub": "สำหรับบัญชีใหม่",
"sp-contributions-newbies-title": "การเข้ามีส่วนร่วมสำหรับบัญชีใหม่",
"sp-contributions-blocklog": "ปูมการบล็อก",
- "sp-contributions-suppresslog": "ระà¸\87ัà¸\9aà¸\81ารà¹\80à¸\82à¹\89ามีสà¹\88วà¸\99รà¹\88วมà¸\82à¸à¸\87à¸\9cูà¹\89à¹\83à¸\8aà¹\89",
- "sp-contributions-deleted": "à¸\81ารà¹\81à¸\81à¹\89à¹\84à¸\82ของผู้ใช้ที่ถูกลบ",
+ "sp-contributions-suppresslog": "ระงับการมีส่วนร่วมของผู้ใช้",
+ "sp-contributions-deleted": "à¸\81ารมà¹\88ีสà¹\88วà¸\99รà¹\88วมของผู้ใช้ที่ถูกลบ",
"sp-contributions-uploads": "อัปโหลด",
"sp-contributions-logs": "ปูม",
"sp-contributions-talk": "คุย",
"ipb-unblock-addr": "ปลดบล็อก $1",
"ipb-unblock": "ปลดบล็อกผู้ใช้หรือเลขที่อยู่ไอพี",
"ipb-blocklist": "ดูการบล็อกที่มีอยู่",
- "ipb-blocklist-contribs": "à¹\80รืà¹\88à¸à¸\87à¸\97ีà¹\88à¹\80à¸\82ียà¸\99โดย $1",
+ "ipb-blocklist-contribs": "à¹\80รืà¹\88à¸à¸\87à¸\97ีà¹\88มีสà¹\88วà¸\99รà¹\88วมโดย $1",
"ipb-blocklist-duration-left": "เหลือเวลา $1",
"unblockip": "ปลดบล็อกผู้ใช้",
"unblockiptext": "ใช้แบบด้านล่างเพื่อคืนการเข้าถึงการเขียนแก่เลขที่อยู่ไอพี หรือชื่อผู้ใช้ที่เคยถูกบล็อก",
"svg-long-error": "ไฟล์ SVG ไม่ถูกต้อง: $1",
"show-big-image": "ไฟล์ต้นฉบับ",
"show-big-image-preview": "ขนาดของตัวอย่างนี้: $1",
- "show-big-image-preview-differ": "ขนาดขงตัวอย่าง $3 นี้ของไฟล์ $2 นี้: $1",
+ "show-big-image-preview-differ": "à¸\82à¸\99าà¸\94à¸\82à¸à¸\87à¸\95ัวà¸à¸¢à¹\88าà¸\87 $3 à¸\99ีà¹\89à¸\82à¸à¸\87à¹\84à¸\9fลà¹\8c $2 à¸\99ีà¹\89: $1",
"show-big-image-other": "{{PLURAL:$2|ความละเอียด|ความละเอียด}}อื่น: $1",
"show-big-image-size": "$1 × $2 พิกเซล",
"file-info-gif-looped": "วนซ้ำ",
"watchlistedit-clear-titles": "ชื่อเรื่อง:",
"watchlistedit-clear-submit": "ล้างรายการเฝ้าดู (เป็นการถาวร!)",
"watchlistedit-clear-done": "ล้างรายการเฝ้าดูของคุณแล้ว",
+ "watchlistedit-clear-jobqueue": "กำลังล้างรายการเฝ้าดูของคุณ อาจใช้เวลาสักหน่อย!",
"watchlistedit-clear-removed": "ลบ $1 ชื่อเรื่อง:",
"watchlistedit-too-many": "มีหน้าแสดงที่นี่มากเกิน",
"watchlisttools-clear": "ล้างรายการเฝ้าดู",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|คุย]])",
"timezone-local": "ท้องถิ่น",
"duplicate-defaultsort": "<strong>คำเตือน:</strong> หลักเรียงลำดับปริยาย \"$2\" ได้ลบล้างหลักเรียงลำดับปริยาย \"$1\" ที่มีอยู่ก่อนหน้า",
+ "duplicate-displaytitle": "<strong>คำเตือน:</strong> แสดงชื่อเรื่อง \"$2\" เขียนทับการแสดงชื่อเรื่องก่อนหน้านี้ \"$1\"",
+ "restricted-displaytitle": "<strong>คำเตือน:</strong> ละเลยชื่อเรื่องหน้า \"$1\" เพราะไม่เท่ากับชื่อเรื่องแท้จริงของหน้า",
"version": "รุ่น",
"version-extensions": "ส่วนขยายเพิ่ม (extension) ที่ติดตั้ง",
"version-skins": "หน้าตาที่ติดตั้ง",
"specialpages-group-maintenance": "รายงานการบำรุงรักษา",
"specialpages-group-other": "หน้าพิเศษอื่น ๆ",
"specialpages-group-login": "ล็อกอิน / สร้างบัญชี",
- "specialpages-group-changes": "à¸\9bรัà¸\9aà¸\9bรุงล่าสุดและปูม",
+ "specialpages-group-changes": "à¹\80à¸\9bลีà¹\88ยà¸\99à¹\81à¸\9bลงล่าสุดและปูม",
"specialpages-group-media": "รายงานสื่อและการอัปโหลด",
"specialpages-group-users": "ผู้ใช้และสิทธิ",
"specialpages-group-highuse": "หน้าที่มีการใช้สูง",
"authmanager-provider-password": "การพิสูจน์ตัวจริงที่อาศัยรหัสผ่าน",
"authmanager-provider-password-domain": "การพิสูจน์ตัวจริงที่อาศัยรหัสผ่านและโดเมน",
"authmanager-provider-temporarypassword": "รหัสผ่านชั่วคราว",
+ "credentialsform-account": "ชื่อบัญชี:",
+ "cannotlink-no-provider-title": "ไม่มีบัญชีที่โยงได้",
+ "cannotlink-no-provider": "ไม่มีบัญชีที่โยงได้",
+ "linkaccounts": "โยงบัญชี",
+ "linkaccounts-success-text": "โยงบัญชีแล้ว",
+ "linkaccounts-submit": "โยงบัญชี",
+ "unlinkaccounts": "เลิกโยงบัญชี",
+ "unlinkaccounts-success": "เลิกโยงบัญชีแล้ว",
"edit-error-short": "ข้อผิดพลาด: $1",
"edit-error-long": "ข้อผิดพลาด: $1",
"revid": "รุ่นแก้ไข $1",
"rcfilters-view-tags-tooltip": "Фільтрувати результати, використовуючи мітки до редагувань",
"rcfilters-view-return-to-default-tooltip": "Повернутися до головного меню фільтра",
"rcfilters-view-tags-help-icon-tooltip": "Дізнайтесь більше про редагування з мітками",
- "rcfilters-liveupdates-button": "Ð\9eновленнÑ\8f наживо",
- "rcfilters-liveupdates-button-title-on": "Ð\92имкнÑ\83Ñ\82и оновленнÑ\8f наживо",
+ "rcfilters-liveupdates-button": "Ð\90вÑ\82омаÑ\82иÑ\87не оновленнÑ\8f",
+ "rcfilters-liveupdates-button-title-on": "Ð\92имкнÑ\83Ñ\82и авÑ\82омаÑ\82иÑ\87не оновленнÑ\8f",
"rcfilters-liveupdates-button-title-off": "Показувати нові зміни одразу ж після їх здійснення",
"rcfilters-watchlist-markseen-button": "Позначити всі зміни як переглянуті",
"rcfilters-watchlist-edit-watchlist-button": "Редагувати Ваш список спостереження",
"permissionserrors": "權限錯誤",
"permissionserrorstext": "由於下列{{PLURAL:$1|原因}},您沒有權限進行目前的動作:",
"permissionserrorstext-withaction": "由於下列{{PLURAL:$1|原因}},您沒有權限進行 $2 的動作:",
- "contentmodelediterror": "您無法編輯此修訂,因此修訂使用的內容模型為 <code>$1</code> 與目前使用的頁面內容模型 <code>$2</code> 不同。",
+ "contentmodelediterror": "您無法編輯此修訂,因為它的內容模型為<code>$1</code>,與目前使用的頁面內容模型<code>$2</code>不同。",
"recreate-moveddeleted-warn": "<strong>警告:您正重新建立先前已刪除的頁面。</strong>\n\n您應考慮是否繼續編輯此頁。\n在此提供刪除與移動日誌方便作為參考:",
"moveddeleted-notice": "此頁面已刪除。\n下方提供此頁面的刪除、保護和移動日誌以便參考。",
"moveddeleted-notice-recent": "對不起,此頁面剛剛被刪除(在最近24小時內)。頁面的刪除、保護和移動日誌在下方提供以供參考。",
# WikimediaUI LESS variables for sharing
cp ./node_modules/oojs-ui/dist/wikimedia-ui-base.less "$REPO_DIR/$TARGET_DIR"
+# Misc stuff
+cp ./node_modules/oojs-ui/dist/AUTHORS.txt "$REPO_DIR/$TARGET_DIR"
+cp ./node_modules/oojs-ui/dist/History.md "$REPO_DIR/$TARGET_DIR"
+cp ./node_modules/oojs-ui/dist/LICENSE-MIT "$REPO_DIR/$TARGET_DIR"
+cp ./node_modules/oojs-ui/dist/README.md "$REPO_DIR/$TARGET_DIR"
+
# Clean up temporary area
rm -rf "$NPM_DIR"
'class' => ResourceLoaderOOUIFileModule::class,
'styles' => [
'resources/lib/oojs-ui/wikimedia-ui-base.less', // Providing Wikimedia UI LESS variables to all
- 'resources/src/oojs-ui-local.css', // HACK, see inside the file
],
'themeStyles' => 'core',
'targets' => [ 'desktop', 'mobile' ],
--- /dev/null
+Principal Authors (major contributors, alphabetically)
+
+Bartosz Dziewoński <matma.rex@gmail.com>
+Ed Sanders <esanders@wikimedia.org>
+James D. Forrester <jforrester@wikimedia.org>
+Kirsten Menger-Anderson <kmenger@wikimedia.org>
+Kunal Mehta <legoktm@gmail.com>
+Moriel Schottlender <moriel@gmail.com>
+Prateek Saxena <prtksxna@gmail.com>
+Roan Kattouw <roan@wikimedia.org>
+Rob Moen <rmoen@wikimedia.org>
+Timo Tijhof <krinklemail@gmail.com>
+Trevor Parscal <trevor@wikimedia.org>
+Volker E. <volker.e@wikimedia.org>
+
+Patch Contributors (minor contributors, alphabetically)
+
+Alangi Derick <alangiderick@gmail.com>
+Alex Monk <krenair@wikimedia.org>
+Amir E. Aharoni <aaharoni@wikimedia.org>
+Amir Sarabadani <Ladsgroup@gmail.com>
+Andrew Garrett <agarrett@wikimedia.org>
+Andrew Green <andrew.green.df@gmail.com>
+Antoine Musso <hashar@free.fr>
+Brad Jorsch <bjorsch@wikimedia.org>
+Brion Vibber <brion@users.mediawiki.org>
+C. Scott Ananian <cscott@cscott.net>
+Chad Horohoe <chadh@wikimedia.org>
+codynguyen1116 <samanthanguyen1116@gmail.com>
+David Lynch <dlynch@wikimedia.org>
+Derk-Jan Hartman <hartman.wiki@gmail.com>
+eranroz <eranroz89@gmail.com>
+Erick Guan <fantasticfears@gmail.com>
+Erik Moeller <erik@wikimedia.org>
+Florian <florian.schmidt.stargatewissen@gmail.com>
+Geoffrey Mon <geofbot@gmail.com>
+Gilles Dubuc <gdubuc@wikimedia.org>
+Huji Lee <huji.huji@gmail.com>
+Inez Korczyński <inez@wikia-inc.com>
+IvanFon <ivanfonseca55@gmail.com>
+Jon Robson <jrobson@wikimedia.org>
+Juliusz Gonera <jgonera@wikimedia.org>
+Kartik Mistry <kartik.mistry@gmail.com>
+Kyle Florence <kflorence@wikia-inc.com>
+Leszek Manicki <leszek.manicki@wikimedia.de>
+Marc A. Pelletier <marc@uberbox.org>
+Mark Holmquist <mtraceur@member.fsf.org>
+Matthew Flaschen <mflaschen@wikimedia.org>
+May Tee-Galloway <mgalloway@wikimedia.org>
+Mr. Stradivarius <misterstrad@gmail.com>
+Niklas Laxström <nlaxstrom@wikimedia.org>
+Nirzar Pangarkar <nirzardp@gmail.com>
+Ori Livneh <ori@wikimedia.org>
+Paladox <thomasmulhall410@yahoo.com>
+Pau Giner <pau.giner@gmail.com>
+Ricordisamoa <ricordisamoa@openmailbox.org>
+rillke <rillke@wikipedia.de>
+Ryan Kaldari <rkaldari@wikimedia.org>
+Sam Reed <reedy@wikimedia.org>
+Stephane Bisson <sbisson@wikimedia.org>
+Sucheta Ghoshal <sghoshal@wikimedia.org>
+Thalia Chan <thalia.e.chan@googlemail.com>
+Victor Barbu <victorbarbu08@gmail.com>
+Wei-Ko Kao <othree@gmail.com>
+Željko Filipin <zeljko.filipin@gmail.com>
--- /dev/null
+# OOUI Release History
+## v0.26.1 / 2018-03-23
+### Deprecations
+* [DEPRECATING CHANGE] icons: Flag 'comment' as to be removed (James D. Forrester)
+* [DEPRECATING CHANGE] icons: Rename 'clip'/'unClip' to 'bookmark'/'bookmarkOutline' (Volker E.)
+
+### Styles
+* ButtonElement (framed): Remove `padding` on icon + indicator variant (Volker E.)
+* WikimediaUI theme: Reduce distance of Tools in BarToolGroup (Volker E.)
+* WikimediaUI theme: Reduce necessary widths for narrow toolbar elements (Volker E.)
+* WikimediaUI icons: Amend 'help' icon to address feedback (Volker E.)
+* WikimediaUI icons: Fix 'speechBubbles' icons (Volker E.)
+* WikimediaUI icons: Fix 'underline-a' icon to be an 'a', not a 'u' (Ed Sanders)
+* WikimediaUI icons: Slightly adapted size of 'clip'/'unClip' for algnment to other icons (Volker E.)
+* WikimediaUI icons: Swap 'advanced' and 'settings' icons (Volker E.)
+
+### Code
+* WikimediaUI theme: Remove unused RTL variants of alignLeft/Right icons (Ed Sanders)
+* WikimediaUI theme: Fix/remove unused icon files (Bartosz Dziewoński)
+* demos: Add alert popout to toolbars demos (Volker E.)
+* demos: Add specialCharacter terminal tool to toolbars demos (James D. Forrester)
+* docs: Add Demos to JSDuck navigation menu (Timo Tijhof)
+* build: Replace grunt-image with grunt-imagemin (James D. Forrester)
+* icons: Re-crush SVGs (James D. Forrester)
+
+## v0.26.0 / 2018-03-20
+### Breaking changes
+* [BREAKING CHANGE] WikimediaUI: Unify available variants across icon packs (Ed Sanders)
+* [BREAKING CHANGE] icons: Remove 'alignCentre', renamed in v0.24.2 (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove 'arrowLast', deprecated since v0.25.0 (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove 'bellOn', deprecated in v0.25.0 (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove 'quotesAdd', deprecated in v0.24.4 (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove 'redirect', renamed in v0.24.4 (James D. Forrester)
+* [BREAKING CHANGE] indicators: Remove 'next' and 'previous', deprecated in v0.25.0 (James D. Forrester)
+
+### Features
+* FieldLayout: Use better icons for warning/error messages (Bartosz Dziewoński)
+* MenuTagMultiselectWidget: Check for empty inputValue in addTagFromInput (Prateek Saxena)
+* TagMultiselectWidget: Handle disabled items (Moriel Schottlender)
+
+### Styles
+* WikimediaUI theme: Add additional 'interactions' & 'media' pack icons (Volker E.)
+* WikimediaUI theme: Align refined WikimediaUI icons in size and position (Volker E.)
+* WikimediaUI theme: Apply `translateZ` hack to full canvas icons (Volker E.)
+* WikimediaUI theme: Fix regression on accelerator key alignment (Volker E.)
+* WikimediaUI theme: Fix toolbar buttonGroup (Ed Sanders)
+* WikimediaUI theme: Harmonize `padding` on FieldLayout messages (Volker E.)
+* WikimediaUI theme: Unify and refine WikimediaUI icons (Volker E.)
+* WikimediaUI theme: Use `14px` base font size & amend positioning/sizing (Volker E.)
+* Apex theme: Fix toolbar buttonGroup (Ed Sanders)
+* Apex theme: Make Apex also use 20px canvas icons (Bartosz Dziewoński)
+
+### Code
+* Use theme rules to define which tools should get blue icons, not flags (Ed Sanders)
+* build: Make the copy task for the WikimediaUI less vars less confusing (James D. Forrester)
+* build: Stop using 'grunt-image' for optimising PNGs, at least for now (James D. Forrester)
+* build: Switch SVG optimization to 'grunt-svgmin' (Volker E.)
+* build: Temporarily disable running unit tests in Firefox due to timeouts (James D. Forrester)
+* build: Update devDependencies to latest (James D. Forrester)
+* build: Updating jakub-onderka/php-parallel-lint to 1.0.0 (libraryupgrader)
+* build: Acknowledge in package.json that grunt-exec 3.0.0 exists, but we don't want it (Bartosz Dziewoński)
+* demos: Include editor switch menu in toolbars menu (Volker E.)
+* demos: Increase base `font-size` to `14px` (Volker E.)
+* demos: Re-enable bigger base size on mobile breakpoint (Volker E.)
+* demos: Use `0.8em` body font size for Apex (Bartosz Dziewoński)
+* dist: Distribute History.md so people can see what's changed (James D. Forrester)
+
+
+## v0.25.3 / 2018-03-06
+### Features
+* DropdownInputWidget: Extract menu item creation (Gabriel Birke)
+* MenuTagMultiselectWidget: Highlight first item when filtering (Moriel Schottlender)
+* demos: Use individual oojs-ui-* JS files for sourcemap support (Moriel Schottlender)
+
+### Styles
+* WikimediaUI theme: Align action toolbar primary button focus state (Volker E.)
+* WikimediaUI theme: Align toolbar items' focus to widgets elsewhere (Volker E.)
+
+### Code
+* Imply `inline-block` on toolbar item labels (Volker E.)
+* CheckboxMultiselectInputWidget: Fix handling of 'name' config option in JS (Bartosz Dziewoński)
+* TagMultiselectWidget: Only apply `onMouseDown` if not in input (Moriel Schottlender)
+* Gruntfile: Remove reference to long-absent at-ease PHP library (James D. Forrester)
+* build: Add jakub-onderka/php-console-highlighter (Umherirrender)
+* build: Adding MinusX (Kunal Mehta)
+* build: Updating mediawiki/mediawiki-codesniffer to 16.0.1 (libraryupgrader)
+* build: Updating phpunit/phpunit to 4.8.36 || ^6.5 (libraryupgrader)
+* build: pass --ansi --no-progress to composer (Antoine Musso)
+* demos: Add monospace hack for `code` element (Volker E.)
+* demos: Only claim ARIA `main` role on the first toolbar demo (Volker E.)
+* demos: Replace “Save” by “Publish changes” (Volker E.)
+
+
+## v0.25.2 / 2018-02-06
+### Deprecations
+* [DEPRECATING CHANGE] icons: Flag indicator 'alert' as to be removed (Volker E.)
+
+### Features
+* Element: Fix infusion edge case (Bartosz Dziewoński)
+* InputWidget and subclasses: Remember original value when creating the widget (Bartosz Dziewoński)
+* MultilineTextInputWidget: Emit 'enter' for Ctrl+Enter (Ed Sanders)
+* MenuTagMultiselectWidget: Erase the input when a menu option is chosen (Prateek Saxena)
+* OptionWidget: Option is still selectable/highlightable/pressable if its parent is disabled (Bartosz Dziewoński)
+* RadioSelectInputWidget: Prevent exceptions when trying to set unavailable options (Bartosz Dziewoński)
+
+### Styles
+* FieldLayout: Fix help icon negative margin in Apex (Ed Sanders)
+* LabelElement: Switch `box-sizing` to `border-box` (srishakatux)
+* ListToolGroup: Correctly point the collapse/expand icon on bottom toolbars (Volker E.)
+* RadioSelectInputWidget, CheckboxMultiselectInputWidget: Fix spacing between options in PHP (Apex theme) (Bartosz Dziewoński)
+
+### Code
+* Avoid having to call `.setValue()` in some widgets' constructors multiple times (Bartosz Dziewoński)
+* CheckboxMultiselectInputWidget: Turn inline event handler into a method (Bartosz Dziewoński)
+* DraggableElement: Replace 'OOjs-UI' with 'OOUI' for code hygiene (Volker E.)
+* TextInputWidget: Move previously forgotten methods to Multiline (Bartosz Dziewoński)
+* Follow-up b28e99712: Remove `mediawiki/at-ease` dependancy (Sam Reed)
+* Reduce code duplication between `#setValue` and `#setOptions` (Bartosz Dziewoński)
+* Remove duplicate documentation between TextInputWidget and Multiline (Bartosz Dziewoński)
+* TextInputWidget: Document that 'maxLength' counts UTF-16 code units (Bartosz Dziewoński)
+* Toolbars: Replace `$.width` with `clientWidth`/`offsetWidth` (Ed Sanders)
+* Use child selectors for menuLayout (Ed Sanders)
+* build: Don't lint a generated JSON file for validity before it's rebuilt (James D. Forrester)
+* build: Update Rubocop config for deprecations (Bartosz Dziewoński)
+* demos, docs: Replace 'alert' indicator, as it's deprecated (Volker E.)
+* demos: Bring “Word processor toolbar” demos closer to VE (Volker E.)
+* demos: Provide more space at bottom of page (Volker E.)
+* tests: Do not use obviously fake data when testing infusion (Bartosz Dziewoński)
+* testsuitegenerator: Test some 'value' parameters that match 'options' parameters (Bartosz Dziewoński)
+
+
+## v0.25.1 / 2018-01-16
+### Code
+* Allow other stuff to handle the event when we call `simulateLabelClick()` (Bartosz Dziewoński)
+* Follow-Up I0f1d9c1f: Update usages of `getSelectedItem` -> `findSelectedItem` (Ed Sanders)
+* PanelLayout: Remove buggy `translateZ` performance hack (Volker E.)
+* PopupToolGroup: Revert "Fix popup direction changing…" (Bartosz Dziewoński)
+* Rename prefixes of unique IDs to not mention "OOjs" (Bartosz Dziewoński)
+* build, demos, docs: Use “OOUI” as unified name (Volker E.)
+* demos: Use MultilineTextInputWidget in PHP demos (Ed Sanders)
+* docs: Clarify `required` true handling with `indicator: 'required'` (Volker E.)
+* docs: Use “OOUI” as unified name in code comments (Volker E.)
+
+
+## v0.25.0 / 2018-01-09
+### Breaking changes
+* [BREAKING CHANGE] Drop the `constructive` flag entirely (James D. Forrester)
+* [BREAKING CHANGE] Remove `BookletLayout#getClosestPage` (James D. Forrester)
+* [BREAKING CHANGE] SelectWidget: Remove `getFirstSelectableItem` (Prateek Saxena)
+* [BREAKING CHANGE] SelectWidget: Remove `getHighlightedItem` (Prateek Saxena)
+* [BREAKING CHANGE] SelectWidget: Remove `getRelativeSelectableItem` (Prateek Saxena)
+* [BREAKING CHANGE] icons: Drop 'watchlist', deprecated in v0.23.1 (James D. Forrester)
+
+### Deprecations
+* [DEPRECATING CHANGE] GroupElement: Rename getItem(s)FromData to findItem(s)FromData (Prateek Saxena)
+* [DEPRECATING CHANGE] MultiSelectWidget: Rename getters (Prateek Saxena)
+* [DEPRECATING CHANGE] SelectWidget: Rename `getSelectedItem` to `findSelectedItem` (Prateek Saxena)
+* [DEPRECATING CHANGE] icons: Flag indicators 'previous' & 'next' as to be removed (Volker E.)
+* [DEPRECATING CHANGE] icons: Rename 'arrowLast' to 'arrowPrevious' (James D. Forrester)
+
+### Features
+* MenuTagMultiselectWidget: Erase the input when tag is selected if filtering (Moriel Schottlender)
+
+### Styles
+* Add `margin-bottom` for widgets which are part of OOUI HorizontalLayout (Phantom42)
+* FieldLayout: Improve alignment of multiline labels with 'help' button (Bartosz Dziewoński)
+* WikimediaUI theme: Align 'transparency' icon to WikimedaUI color palette (Volker E.)
+* WikimediaUI theme: Remove obsolete global flag for 'layout' icon pack (Volker E.)
+* WikimediaUI theme: Remove obsolete icon flags (Volker E.)
+* Apex theme: Align readonly TextInputWidget across themes (Volker E.)
+* Apex theme: Apply `opacity` button transition and ensure Chrome support (Volker E.)
+* Apex theme: Remove unused, obsolete 'logo-wikimediaDiscovery' icon (Volker E.)
+* icons: Remove obsolete 'bookmark' icon remainders (Volker E.)
+* icons: Remove obsolete 'watchlist' icon remainders (Volker E.)
+* icons: Shorten 'accessibility' pack invert hex color (Volker E.)
+
+### Code
+* Clarify `.oo-ui-force-gpu-composite-layer()` mixin comment (Volker E.)
+* Fix blurry text on PanelLayout promoted to GPU in Safari (Volker E.)
+* Fix popup direction changing when the "anchor" is partially offscreen (Bartosz Dziewoński)
+* MenuTagMultiselectWidget: Don't use overlay for `$autoCloseIgnore` (Moriel Schottlender)
+* MultilineTextInputWidget: Correct documentation for `config.maxRows` (Roan Kattouw)
+* PHP TextInputWidget: Remove remaining type 'search' specific code (Volker E.)
+* Use findItem(s)FromData instead of getItem(s)FromData (Prateek Saxena)
+* demos: Override OO.ui.getViewportSpacing in infused PHP demo too (Bartosz Dziewoński)
+* demos: Promote icons page IndicatorWidget to GPU layer (Volker E.)
+* docs: Bump copyright year (James D. Forrester)
+* docs: TagMultiselectWidget: Remove wrong link to MediaWiki documentation (Prateek Saxena)
+* build: Update .gitattributes for .phpcs.xml file move (Kunal Mehta)
+* build: Add rake to Gemfile (Antoine Musso)
+* build: Don't include Gemfile* in composer zipballs (Kunal Mehta)
+* build: Update RuboCop Ruby gem (Željko Filipin)
+* build: Updating mediawiki/mediawiki-codesniffer to 15.0.0 (libraryupgrader)
+* build: Use SVGO option of 'grunt-image' for distribution (Volker E.)
+
+
+## v0.24.4 / 2017-12-20 special release
+### Deprecations
+* [DEPRECATING CHANGE] icons: Flag unused 'bellOn' icon as to be removed (Volker E.)
+* [DEPRECATING CHANGE] icons: Flag unused 'quotesAdd' & 'redirect' as to be removed (Volker E.)
+
+### Features
+* Introduce `OO.ui.getDefaultOverlay` (Bartosz Dziewoński)
+* Put menus/popups of infused PHP widgets into the default overlay (Bartosz Dziewoński)
+
+### Styles
+* icons: Add 'lightbulb' icon (Prateek Saxena)
+* icons: Add 'stop' icon to Apex theme (Volker E.)
+
+### Code
+* ClippableElement: Fix JS error when Floatable is mixed in but disabled (Roan Kattouw)
+* DropdownWidget: Remove stray use of `this.$()` (Bartosz Dziewoński)
+
+
+## v0.24.3 / 2017-11-28
+### Features
+* Allow adding virtual viewport spacing (Bartosz Dziewoński)
+* ClippableElement: Allow clipping with top or left edge (Bartosz Dziewoński)
+* DropdownInputWidget: Generate a hidden `<select>` in JS (Bartosz Dziewoński)
+* FieldsetLayout: Hide header when there is no icon or label (Bartosz Dziewoński)
+* MenuSelectWidget, PopupWidget: Automatically change popup direction if there is no space (Bartosz Dziewoński)
+* PopupToolGroup: Set clipping edges to fix clipping edge (heh) cases (Bartosz Dziewoński)
+* TextInputWidget: support spellcheck attribute (David Lynch)
+
+### Styles
+* themes: Fix PHP ComboboxInputWidget indicator position (Volker E.)
+* WikimediaUI theme: Restore `:hover:focus` border color on TextInputWidgets (Volker E.)
+* oo-ui-background-image: Drop `-o-linear-gradient` fallback (James D. Forrester)
+* oo-ui-background-image: Drop `-webkit-linear-gradient` fallback (James D. Forrester)
+
+### Code
+* PHP DropdownInputWidget: Workaround for Firefox 57 ignoring attr selector with whitespace (Volker E.)
+* DraggableGroupElement: Don't try to access non-existent property (Bartosz Dziewoński)
+* DropdownInputWidget: Remove duplicate TitledElement mixin (Bartosz Dziewoński)
+* README: Add "Community" section (Prateek Saxena)
+* README: Re-arrange intro section (Prateek Saxena)
+* build: Bump wikimedia-ui-base (Volker E.)
+* git.wikimedia.org -> phab (Zach)
+
+
+## v0.24.2 / 2017-11-07
+### Deprecations
+* [DEPRECATING CHANGE] Use en-US spelling for icon names for consistency (Ed Sanders)
+
+### Code
+* README: Consistently refer to OOUI as library (Volker E.)
+* README: Fix Doxygen rendering (Volker E.)
+* README: Simplify “Quick start” and “Contributing” section (Volker E.)
+* demos: Correct and simplify SimpleWidget styles (Bartosz Dziewoński)
+* docs: onMenuToggle: `isVisible` is the state of the menu (Prateek Saxena)
+
+
+## v0.24.1 / 2017-10-31
+### Features
+* DropdownWidget: Allow pressing Space to close the widget, as well as open (Bartosz Dziewoński)
+
+### Styles
+* WikimediaUI theme: Visually improve MenuSectionOptionWidget MenuOptions (Volker E.)
+
+### Code
+* ComboBoxInputWidget: Add `.oo-ui-comboBoxInputWidget-open` class to widget (Volker E.)
+* Generate clover.xml with code coverage results (Kunal Mehta)
+* WikimediaUI theme: Use child selectors for styling toolbar action buttons (Bartosz Dziewoński)
+* README: Simplify and move “Versioning” section (Volker E.)
+* README: Simplify “Contributing” section slightly and add LESS lint hint (Volker E.)
+* build: Bump stylelint devDependencies (James D. Forrester)
+* build: Bump various devDependencies to latest (James D. Forrester)
+* build: Downgrade 'grunt-exec' to 1.0.1 (again) (Bartosz Dziewoński)
+* build: Update grunt-image to version 4.0.0 (Ed Sanders)
+* build: Update mediawiki/mediawiki-codesniffer to 14.1.0 (libraryupgrader)
+* icons: Unify SVG markup (Volker E.)
+
+
+## v0.24.0 / 2017-10-17
+### Breaking changes
+* [BREAKING CHANGE] Drop 'MediaWiki' backwards-compatibility theme (James D. Forrester)
+* [BREAKING CHANGE] icons: Drop 'stripeSideMenu', renamed in v0.22.2 (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove 'eye'/'eyeClosed' icons, deprecated in v0.23.0 (Volker E.)
+* [BREAKING CHANGE] icons: Remove 'signature' icon, deprecated in v0.23.0 (Volker E.)
+* [BREAKING CHANGE] icons: Remove 'sun', deprecated in v0.23.0 (James D. Forrester)
+
+### Styles
+* themes: Unify icon/indicator visibility (Volker E.)
+* WikimediaUI theme: Ensure hover feedback on TextInputWidget & descendants (Volker E.)
+
+### Code
+* Fix `.oo-ui-selectable()` mixin to actually undo `.oo-ui-unselectable()` (Bartosz Dziewoński)
+* WikimediaUI theme: Fix selector in PopupWidget styles (Bartosz Dziewoński)
+
+
+## v0.23.5 / 2017-10-12
+### Code
+* PHP MultilineTextInputWidget, SearchInputWidget: Remove duplicate `use` statements (Bartosz Dziewoński)
+* PHP Theme: Fix check for IconElement/IndicatorElement for inherited traits (Bartosz Dziewoński)
+
+
+## v0.23.4 / 2017-10-11
+### Styles
+* IndexLayout: Handle long lists of tabs (Bartosz Dziewoński)
+* icons: Provide a 'reload' icon in the 'interactions' pack (Ed Sanders)
+* Apex theme: Fix PopupToolGroup active box size (Volker E.)
+* Apex theme: Fix SelectFileWidget (no browser support) `padding` (Volker E.)
+* Generalize icon and indicator positioning & visibility (Volker E.)
+* WikimediaUI theme: Reduce Checkbox*- & RadioSelectInputWidget vertical space (Volker E.)
+* WikimediaUI theme: Reduce FieldLayout `margin-top` slightly (Volker E.)
+* WikimediaUI theme: Streamlining icon/indicator visibility (Volker E.)
+
+### Code
+* Only store initialConfig in demo mode (Ed Sanders)
+* SearchInputWidget: Prevent extra `oo-ui-textInputWidget-type-text` class (Bartosz Dziewoński)
+* TextInputWidget: Use child selector for icons/indicators/labels (Ed Sanders)
+* Do not call `.offset()` on `$( 'html' )` (Bartosz Dziewoński)
+* PHP: Implement MultilineTextInputWidget, deprecate multiline option (Prateek Saxena)
+* PHP: Implement SearchInputWidget, deprecate search option (Bartosz Dziewoński)
+* build: Downgrade 'grunt-exec' to 1.0.1 (Bartosz Dziewoński)
+* demos: Adding missing `:hover` (Volker E.)
+
+
+## v0.23.3 / 2017-10-03
+### Styles
+* PopupToolGroup: Move accelerator keys `padding` to themes (Volker E.)
+* WikimediaUI theme: Align PopupToolGroup header styles (Volker E.)
+* WikimediaUI theme: Fix border on narrow bottom toolbars (Volker E.)
+* WikimediaUI theme: Fix flagged elements' icon `opacity` (Volker E.)
+* WikimediaUI theme: Improve PopupToolGroup's indicator vertical alignment (Volker E.)
+* WikimediaUI theme: Make toolbar active element highlights visually equal (Volker E.)
+* WikimediaUI theme: Remove `box-shadow` not in design (Volker E.)
+* WikimediaUI theme: Replace BookletLayout menu `border-color` (Volker E.)
+* WikimediaUI theme: Unify positioning and sizing of tools, toolgroups and menus (Volker E.)
+* WindowManager: Remove `overflow: hidden` to enhance styling flexibility (Volker E.)
+
+### Code
+* Follow-up I576f3175: highlightQuery: Handle case when query is not found (Ed Sanders)
+* IndexLayout, BookletLayout: Don't scroll panels if not scrollable (Bartosz Dziewoński)
+* LabelElement: Add tests for setHighlightedQuery (Ed Sanders)
+* SelectWidget: Allow focussing things inside OptionWidget labels (Bartosz Dziewoński)
+* WikimediaUI theme: Simplify action toolbar buttons selectors (Volker E.)
+* demos: Remove unnecessary button demo widgets (Volker E.)
+
+
+## v0.23.2 / 2017-09-26
+### Deprecations
+* [DEPRECATING CHANGE]: Apex theme: Begin killing `constructive` flag (James D. Forrester)
+
+### Features
+* LabelElement#highlightQuery: Support locale comparison (Ed Sanders)
+* MenuLayout, BookletLayout, IndexLayout: Support `expanded: false` (Bartosz Dziewoński)
+* WindowManager: Set `aria-hidden` by default and change toggleAriaIsolation behavior (Prateek Saxena)
+
+### Code
+* MenuLayout: Rewrite support for `expanded: false` (Bartosz Dziewoński)
+* TextInputWidget: Reduce CSS output by enhancing unselectable behaviour (Volker E.)
+* themes: Align DropdownWidget `&-handle` selectors for code hygiene (Volker E.)
+* Apex theme: Simplify Radio- & Checkbox*optionWidget label rules (Volker E.)
+* Remove duplicated `outline` property (Volker E.)
+* Remove LESS vars covered by WikimediaUI Base (Volker E.)
+* demos: Expand long dialog title to actually test things (James D. Forrester)
+* demos: Restrict `opacity` to non-flagged icons only (Volker E.)
+
+
+## v0.23.1 / 2017-09-19
+### Deprecations
+* [DEPRECATING CHANGE] SelectWidget: Rename `getFirstSelectableItem` to `findFirstSelectableItem` (Prateek Saxena)
+* [DEPRECATING CHANGE] SelectWidget: Rename `getHighlightedItem` to `findHighlightedItem` (Prateek Saxena)
+* [DEPRECATING CHANGE] SelectWidget: Rename `getRelativeSelectableItem` to `findRelativeSelectableItem` (Prateek Saxena)
+* [DEPRECATING CHANGE] icons: Flag unused 'watchlist' icon as to be removed (Volker E.)
+
+### Styles
+* RadioOptionWidget, CheckboxMultioptionWidget: Support very long labels (Bartosz Dziewoński)
+* WikimediaUI theme: Harmonize toolbar icon/indicator opacity (Volker E.)
+* WikimediaUI theme: Improve ListToolGroup's color and opacity handling (Volker E.)
+* WikimediaUI theme: Simplify disabled tool opacity rules (Volker E.)
+
+### Code
+* BookletLayout#getClosestPage: Fix version number of deprecation (Prateek Saxena)
+* HtmlSnippet: Throw exception if given non-string content (Bartosz Dziewoński)
+* Use `findFirstSelectableItem` instead of `getFirstSelectableItem` (Prateek Saxena)
+* Use `findHighlightedItem` instead of `getHighlightedItem` (Prateek Saxena)
+* Use `findRelativeSelectableItem` instead of `getRelativeSelectableItem` (Prateek Saxena)
+* WikimediaUI theme: Concatenate constructive & progressive selectors (Volker E.)
+* WikimediaUI theme: Remove unnecessary properties (Volker E.)
+* demos: Add examples of FieldLayout with very long labels (Bartosz Dziewoński)
+* demos: Avoid menu's `box-shadow` from lurkin into toolbar (Volker E.)
+
+
+## v0.23.0 / 2017-09-05
+### Breaking changes
+* [BREAKING CHANGE] Remove CardLayout and references in IndexLayout (Volker E.)
+* [BREAKING CHANGE] Remove FloatingMenuSelectWidget (Volker E.)
+* [BREAKING CHANGE] Remove back-compat `OO.ui` prefix assumption in infusion code (Prateek Saxena)
+* [BREAKING CHANGE] icons: Remove 'caret' icons, deprecated in v0.21.3 (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove 'wikitrail' icon, renamed in v0.20.1 (James D. Forrester)
+
+### Deprecations
+* [DEPRECATING CHANGE] BookletLayout: Rename `getClosestPage()` to `findClosestPage()` (Prateek Saxena)
+* [DEPRECATING CHANGE] icons: Flag unused 'sun' icon as to be removed (James D. Forrester)
+* [DEPRECATING CHANGE] icons: Move 'eye'/'eyeClosed' to 'accessibility' (Volker E.)
+* [DEPRECATING CHANGE] icons: Move 'signature' to 'editing-advanced' (Volker E.)
+
+### Features
+* Element: Improve error message when the widget being infused is missing (Bartosz Dziewoński)
+
+### Styles
+* Apex theme: Only apply `margin` to label if visible (Ed Sanders)
+* WikimediaUI theme: Fix frameless indicator combination buttons' appearance (Volker E.)
+* ButtonInputWidget: Fix Safari-specific intrinsic `margin` (Volker E.)
+
+### Code
+* Ensure only options belonging to the SelectWidget can be clicked (Ed Sanders)
+* SelectFileWidget: Rename `getTargetItem()` to `findTargetItem()` (Prateek Saxena)
+* Toolgroup: Rename `getTargetTool()` to `findTargetTool()` (Prateek Saxena)
+* WikimediaUI theme: Simplify `transition` code and remove obsolete (Volker E.)
+* build: Add 'accessibility' icon pack in Apex to build module definition (Volker E.)
+* build: Update eslint-config-wikimedia 0.4->0.5 (Ed Sanders)
+* build: Updating mediawiki/mediawiki-codesniffer to 0.12.0 (libraryupgrader)
+* tests: Make MockWidget filename match class name (Kunal Mehta)
+
+
+## v0.22.5 / 2017-08-22
+### Features
+* Add `title` attribute to the 'remove' button in TagItemWidget (Moriel Schottlender)
+
+### Styles
+* WikimediaUI theme: Fix regression on disabled border (Volker E.)
+
+### Code
+* Align vars to WikimediaUI Base and remove them as OOjs UI vars (Volker E.)
+* DraggableElement: Make toggling draggability consistent (Bartosz Dziewoński)
+* Follow-up 022f532: Don't crash if TitledElement initializes before AccessKeyedElement (Roan Kattouw)
+* WikimediaUI theme: Make checkbox/radio code leaner (Volker E.)
+* WikimediaUI theme: Remove unnecessary selector in CheckboxInputWidget (Volker E.)
+* docs: Align code comment references to Phabricator tasks (Volker E.)
+* build: Upgrade devDependencies to latest and make pass (James D. Forrester)
+* build: Update mediawiki-codesniffer to v0.10.1 and fix issues (WMDE-Fisch)
+* build: Update mediawiki-codesniffer to v0.11.0 and fix issues (WMDE-Fisch)
+* tests: Prepare for qunit 2.x (James D. Forrester)
+
+
+## v0.22.4 / 2017-08-01
+### Features
+* CheckboxMultiselectInputWidget: setValue when CheckboxMultiselect changes (Prateek Saxena)
+* FieldLayout: Show widget's accesskey in our title (Bartosz Dziewoński)
+* TextInputWidget: When positioning label, don't clear padding if we will set it again (Bartosz Dziewoński)
+* TitledElement: When an AccessKeyedElement, show access key in the title (Bartosz Dziewoński)
+
+### Styles
+* icons: Vertically align 'play' & 'stop' icons (Volker E.)
+* Apex theme: Add focus styles to Tag-/CapsuleMultiselectWidget (Volker E.)
+* Apex theme: Add focus styles to frameless buttons (Volker E.)
+* Apex theme: Add play icon (copied from WikimediaUI theme) (Roan Kattouw)
+* Apex theme: Align ButtonGroup-/ButtonSelectWidget focus logic to WikimediaUI (Volker E.)
+* Apex theme: Align Dropdown*Widget's focus state with other widgets (Volker E.)
+* Apex theme: Align TextInputWidget focus to variablized way (Volker E.)
+* Apex theme: Align ToggleSwitchWidget focus style to other widgets (Volker E.)
+* Apex theme: Improve alignment of TextInputWidget and its elements (Volker E.)
+* Apex theme: Introduce framed button focus indication (Volker E.)
+* Apex theme: Replace and unify `border-radius` with variables (Volker E.)
+* WikimediaUI theme: Set ButtonElement's height per default (Volker E.)
+* WikimediaUI theme: Work around a Firefox rendering bug for checkboxes and radios (Bartosz Dziewoński)
+
+### Code
+* DraggableGroupElement: Remove ARIA roles & attributes (Volker E.)
+* FieldsetLayout: Use `<legend>` now that Chrome 55 bug is less important (James D. Forrester)
+* Apex theme: Align remaining values to coding convention (Volker E.)
+* WikimediaUI theme: Align `*-fallback` var with notation elsewhere (Volker E.)
+* WikimediaUI theme: Code comment hygiene (Volker E.)
+* WikimediaUI theme: Directly use the Less values rather than via copy-paste (James D. Forrester)
+* demos: Add examples of TextInputWidget with dynamic label (Bartosz Dziewoński)
+* demos: Demo.DraggableItemWidget should not inherit from OO.ui.OptionWidget (Bartosz Dziewoński)
+* demos: Show example link on `:focus` (Volker E.)
+* docs: Fix some PHPDoc `@return` tags (Ricordisamoa)
+* build: Add a script to print the dependency tree of everything (Bartosz Dziewoński)
+
+
+## v0.22.3 / 2017-07-11
+### Features
+* Tag-/CapsuleMultiselectWidget: Avoid visual focusTrap feedback (Volker E.)
+* WindowManager: Avoid inconsistent state due to asynchronous promise resolution (Bartosz Dziewoński)
+* WindowManager: fix closing promise state check (David Lynch)
+
+### Styles
+* icons: Align ongoingConversation to grid (Ed Sanders)
+* icons: Replace the puzzle icon, using the one from VisualEditor (James D. Forrester)
+* icons: Vertically center mapPin icon (Volker E.)
+* Apex theme: Add 'article' icon, copied from WikimediaUI (Moriel Schottlender)
+
+### Code
+* DropdownWidget, MenuSelectWidget: Set `aria-expanded` attribute (Prateek Saxena)
+* FieldLayout: Add `role='alert'` for error messages (Prateek Saxena)
+* FieldLayout: Set `aria-describedby` on the fieldWidget (Prateek Saxena)
+* PopupWidget: Update function name in a comment (Bartosz Dziewoński)
+* TagMultiselectWidget: Skip `updateInputSize()` for invisible inputs (Roan Kattouw)
+* Toolbar: Add comment for greppability of dynamic CSS classes (Bartosz Dziewoński)
+* themes: Align read-only variable names to pseudo-class selector scheme (Volker E.)
+* themes: Align variable names to WikimediaUI Base scheme (Volker E.)
+* WikimediaUI theme: Align `@opacity-icon*` variable names to WikimediaUI Base (Volker E.)
+* WikimediaUI theme: Align checked variable names to pseudo-class scheme (Volker E.)
+* WikimediaUI theme: Align disabled variable names to pseudo-class scheme (Volker E.)
+* WikimediaUI theme: Align variable pseudo classes names to WikimediaUI Base (Volker E.)
+* WikimediaUI theme: Replace `@color-base-light` with `@color-base--inverted` (Volker E.)
+* WikimediaUI theme: Variablize PopupWidget values (Volker E.)
+* WikimediaUI theme: Pull in the upstream WikimediaUI package (James D. Forrester)
+* build: Updating mediawiki/mediawiki-codesniffer to 0.10.0 (Kunal Mehta)
+* phpcs: Enable more rules, or document why they are disabled (Bartosz Dziewoński)
+* testsuitegenerator: Blacklist deprecated `multiline` config option (Bartosz Dziewoński)
+
+
+## v0.22.2 / 2017-06-28
+### Deprecations
+* [DEPRECATING CHANGE] TextInputWidget: Move multi-line support out (Prateek Saxena)
+* [DEPRECATING CHANGE] icons: Move and rename 'stripeSideMenu' to 'draggable' (Volker E.)
+
+### Features
+* DropdownInputWidget: Unbreak setting 'value' via config options (Bartosz Dziewoński)
+* Element: Work around browsers that set fractional scrollTop values (Roan Kattouw)
+
+### Styles
+* BookletLayout: Workaround for horizontal scrollbars on menu when editable (Bartosz Dziewoński)
+* icons: Let's stop referring to removed icons, hmm? (James D. Forrester)
+* Rewrite all styling for "outline controls" (Bartosz Dziewoński)
+* Apex theme: Align appearance of tags' close icon to WikimediaUI theme (Volker E.)
+* Apex theme: Fix HorizontalLayout containing FieldLayouts (Bartosz Dziewoński)
+* WikimediaUI theme: Remove default DraggableElement styling (Ed Sanders)
+* WikimediaUI theme: Use icon instead of indicator in Tag-/CapsuleItemWidget (Volker E.)
+* WikimediaUI: Strengthen Radio*Widget's `:checked` state (Volker E.)
+
+### Code
+* MenuSelectWidget: Fix item hiding when menu contents change (Roan Kattouw)
+* MultilineTextInputWidget: Fix autosizing (Bartosz Dziewoński)
+* PopupWidget: Replace CSS with Less comments for smaller dist (Volker E.)
+* SearchInputWidget: Fix ability to clear the input (Bartosz Dziewoński)
+* TabIndexedElement: Fix validation and make consistent in PHP and JS (Bartosz Dziewoński)
+* Use javascript-stringify instead of JSON.stringify (Ed Sanders)
+* Apex theme: Fix order of selectors for :first-child FieldLayout (Bartosz Dziewoński)
+* demos: Add links to documentation from code examples (Prateek Saxena)
+* demos: Allow linking to specific widgets (Bartosz Dziewoński)
+* demos: Indicate code toggle clearer (Volker E.)
+* demos: Pull out all links to docs/sources to the top of the code (Bartosz Dziewoński)
+* demos: Simplify code generation, now that we use javascript-stringify (Bartosz Dziewoński)
+* demos: Use URL 'query' part for linking to demo sections rather than URL 'fragment' (Bartosz Dziewoński)
+* docs: Fix some typos in documentation (Bartosz Dziewoński)
+* docparser: Fix handling for fake trait constructors (Bartosz Dziewoński)
+* docparser: Make matching '(default: ...)' case-insensitive (Bartosz Dziewoński)
+* docparser: Tighter check for 'use' statements in PHP (Bartosz Dziewoński)
+
+
+## v0.22.1 / 2017-05-31
+### Code
+* WindowManager: Do not use return value of `#closeWindow` as promise (Bartosz Dziewoński)
+* WindowManager: Fix check for a window already closing (Bartosz Dziewoński)
+* WindowManager: Fix error handling for `#openWindow` with string argument (Bartosz Dziewoński)
+* WindowManager: Fix important typo in deprecation warning (Bartosz Dziewoński)
+* WindowManager: Fix incorrect checks for promise state (Bartosz Dziewoński)
+* WindowManager: Provide other `jQuery.Promise` methods on the b/c promise too (Bartosz Dziewoński)
+* demos: Clarify code comment (Bartosz Dziewoński)
+* demos: Clean up the global window manager too when destroying (Bartosz Dziewoński)
+* demos: Load icon packs in the PHP demo (Bartosz Dziewoński)
+* demos: Replace abandoned icon name 'remove' to current one 'trash' (Volker E.)
+
+## v0.22.0 / 2017-05-30
+### Breaking changes
+* [BREAKING CHANGE] TextInputWidget: Remove search related methods (Prateek Saxena)
+* [BREAKING CHANGE] icons: Drop the core icon pack (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove unused 'bookmark' icon (Volker E.)
+* [BREAKING CHANGE] Depend on OOjs v2.1.0, up from v2.0.0 (James D. Forrester)
+
+### Deprecations
+* [DEPRECATING CHANGE] Rename the 'MediaWiki' theme to 'WikimediaUI' (James D. Forrester)
+* [DEPRECATING CHANGE] WindowManager: Deprecate using `openWindow`/`closeWindow` returns as promises (Bartosz Dziewoński)
+
+### Features
+* Add HiddenInputWidget to generate hidden input (Victor Barbu)
+* InputWidget: Introduce `#setInputId` and `inputId` config option (Bartosz Dziewoński)
+* MenuTagMultiselectWidget: Clear text field after adding an item from it (Bartosz Dziewoński)
+* MenuTagMultiselectWidget: Handle the 'selected' config option (Bartosz Dziewoński)
+* NumberInputWidget: Use icons instead of labels (Volker E.)
+* PopupButtonWidget: Handle empty configuration (Bartosz Dziewoński)
+* PopupWidget: Position close button in head absolutely (David Lynch)
+* PopupWidget: Sensibly position anchor-less popups (Roan Kattouw)
+* WindowManager: Add `WindowInstance` - a Promise-based lifecycle object (Timo Tijhof)
+* WindowManager: Handle errors better in `#closeWindow` (Bartosz Dziewoński)
+
+* Allow *even more* widgets to be focussed programatically (Bartosz Dziewoński)
+* Only cancel mouse down event if tool in toolgroup clicked on (Ed Sanders)
+* Re-introduce `.simulateLabelClick()` as a separate method from .focus() (Bartosz Dziewoński)
+
+### Styles
+* themes: Field*Layout help position perfectly aligned (Volker E.)
+* themes: Improve frameless button in size and behaviour (Volker E.)
+* themes: Increase FieldsetLayout header's `font-size` (Volker E.)
+* Apex theme: Ensure vertical centering of ButtonElement's icon (Volker E.)
+* Apex theme: Make OptionWidget icon override more specific (Moriel Schottlender)
+* Apex theme: Start Apex's 'user' icon pack, with just 'userAvatar' for now (Ed Sanders)
+* WikimediaUI theme: Align `@background-color-destructive` to WikimediaUI Base (Volker E.)
+* WikimediaUI theme: Align ButtonInputWidget's `line-height` to ButtonWidget (Volker E.)
+* WikimediaUI theme: Align inline label's position (Volker E.)
+* WikimediaUI theme: Ensure icon aligns in dropdown menu (Volker E.)
+* WikimediaUI theme: Remove incorrect comments (Volker E.)
+
+### Code
+* MenuTagMultiselectWidget: Add test for 'selected' config option (Bartosz Dziewoński)
+* windows: Add tests for OO.ui.alert/confirm/prompt (Timo Tijhof)
+* AUTHORS: Update for the past two years' work (James D. Forrester)
+* build: Add the README/AUTHORS/LICENCE files to dist (James D. Forrester)
+* demos: Add TextInputWidget examples with inline labels but no indicators (Ed Sanders)
+* demos: Add viewport meta tag to PHP demo too (Volker E.)
+* demos: Avoid inline CSS for the overlay (Bartosz Dziewoński)
+* demos: Fix code generation for more complicated cases (Bartosz Dziewoński)
+* demos: Fix up a couple of minor things in demo widgets (Bartosz Dziewoński)
+* demos: Fix `z-index` with fixed demo header (Volker E.)
+* demos: Increase and strengthen responsive support (Volker E.)
+* demos: Indicate widgets clearer by sections (Volker E.)
+* demos: Make disabled progress bar in demo determinate (Ed Sanders)
+* demos: Show code that can be used to create the widget (Prateek Saxena)
+* testsuitegenerator: Handle classes with no constructor (Bartosz Dziewoński)
+
+
+## v0.21.4 / 2017-05-16
+### Features
+* Allow more widgets to be focussed programatically (Bartosz Dziewoński)
+* Generalize `.getInputId()` for all widgets (Bartosz Dziewoński)
+* Use `.focus()` method when possible instead of looking inside widgets (Bartosz Dziewoński)
+* TagMultiselectWidget: Fix `Ctrl`+`Backspace` to delete last item (Bartosz Dziewoński)
+* TagMultiselectWidget: Fix order of checks for `allowArbitrary`/`allowDuplicates` (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Separate two active ToggleButton siblings visually (Volker E)
+
+### Code
+* LabelWidget: Fix label click handling (Bartosz Dziewoński)
+* RadioSelectInputWidget: When generating a unique 'name', don't make it random (Bartosz Dziewoński)
+* Use glaringly wrong tags for elements that are supposed to be unused (Bartosz Dziewoński)
+* README: Clarify and simplify descriptions (Volker E)
+* build: Upgrade eslint-config-wikimedia from 0.3.0 to 0.4.0 and make pass (James D. Forrester)
+* demos: Add ARIA roles (Volker E)
+* demos: Clean up the window manager when destroying the dialogs demo (Bartosz Dziewoński)
+* demos: Preserve scroll position when changing non-page options (Bartosz Dziewoński)
+* demos: Rename deprecated Card to current TabPanel (Volker E)
+* demos: Tame buggy mobile browser behaviour on `position: fixed` (Volker E)
+* demos: Turn the menu into a fixed header (Bartosz Dziewoński)
+* docs: Fix `OO.ui.IndexLayout` example (Volker E)
+* tests: Order the `attributes` object keys, for less noisy diffs (Bartosz Dziewoński)
+
+
+## v0.21.3 / 2017-05-09
+### Deprecations
+* [DEPRECATING CHANGE] Merge functionality of FloatingMenuSelectWidget into MenuSelectWidget (Bartosz Dziewoński)
+* [DEPRECATING CHANGE] Rename CardLayout to TabPanelLayout (Prateek Saxena)
+* [DEPRECATING CHANGE] icons: Deprecate 'bookmark' icon (Volker E)
+* [DEPRECATING CHANGE] icons: Merge 'caret' into regular movement icons (James D. Forrester)
+
+### Styles
+* OptionWidget: Use parent selector for icon/indicator/label styles (Roan Kattouw)
+* Apex theme: Follow same FieldLayout `margin` logic as MediaWiki theme (Volker E)
+* MediaWiki theme: Bring styling to design spec in Safari/iOS (Volker E)
+* MediaWiki theme: Fix ButtonInputWidget appearance in Saf/iOS (Volker E)
+* MediaWiki theme: Fix `padding` for frameless buttons in ProcessDialogs (Ed Sanders)
+* MediaWiki theme: Provide focus indicator to TagMultiselectWidget (Volker E)
+* MediaWiki theme: Unify and harmonize `padding`/position of Tag*Widgets (Volker E)
+
+### Code
+* Fix some errors flagged by ESLint's 'valid-jsdoc' option (Bartosz Dziewoński)
+* NumberInputWidget: Followup db801c55f0 – clean up backward compat vars (Moriel Schottlender)
+* MenuSectionOptionWidget: Remove unsupported ARIA attribute (Volker E)
+* MenuSelectWidget: Scroll to the top if filtering and no exact match (David Lynch)
+* MenuSelectWidgets: Don't unconditionally hide all descendant inputs (Roan Kattouw)
+* TagMultiselectWidget: Actually use the focus trapping element (Bartosz Dziewoński)
+* TagMultiselectWidget: Fix `#addTag` return value to match docs (Bartosz Dziewoński)
+* TagMultiselectWidget: Fix keyboard navigation between items (Bartosz Dziewoński)
+* ToggleButtonWidget: Remove misleading `aria-checked` attribute (Volker E)
+* Unbreak FloatingMenuSelectWidget when `$container` is not given (Bartosz Dziewoński)
+* build: Fix invalid ecmaVersion setting (Timo Tijhof)
+* build: Use source maps in coverage report (James D. Forrester)
+* icons: Add first/last to complement previous/next in movement pack (Ed Sanders)
+* icons: Provide 'clip', 'unClip', and 'pushPin' in moderation (James D. Forrester)
+* tests: Do not set `QUnit.config.requireExpects = true` (Bartosz Dziewoński)
+
+
+## v0.21.2 / 2017-04-25
+### Features
+* Element: New method `#getElementId` (Bartosz Dziewoński)
+* NumberInputWidget: Remake as an actual TextInputWidget child (Moriel Schottlender)
+
+### Styles
+* ProgressBarWidget: Switch to `box-sizing: border-box` (Volker E)
+* TabOptionWidget: Cleanup & align paddings/position to dialog environment (Volker E)
+* MediaWiki theme: Decrease selector specificity and fix invalid appearance (Volker E)
+* MediaWiki theme: Fix IE 7 oversized buttons (Volker E)
+* MediaWiki theme: Improve SearchWidget design (Volker E)
+
+### Code
+* Do not use `role=menu`/`menuitem` for MenuSelectWidget/MenuOptionWidget (Bartosz Dziewoński)
+* PopupTagMultiselectWidget: Update popup position on resize (Prateek Saxena)
+* ProcessDialog: Display error messages on top of footer action buttons (Bartosz Dziewoński)
+* SelectWidget/MenuSelectWidget: Maintain `aria-activedescendant` attribute on focus owner (Bartosz Dziewoński)
+* Set ARIA `role=combobox` on DropdownWidget and LookupElement too (Bartosz Dziewoński)
+* Set `aria-owns` for everything with a dropdown list (ARIA `role=combobox`) (Bartosz Dziewoński)
+* Follow-up d22d23311: Don't reference OO.ui.ToolGroup blindly (James D. Forrester)
+* build: Bump grunt-stylelint, bring in stylelint explicitly (James D. Forrester)
+* demos: Add some more examples with 'accessKey' (Bartosz Dziewoński)
+* docs: Document Window#$overlay property (Bartosz Dziewoński)
+* tests: Drop unnecessary hints to qunit about the number of tests (James D. Forrester)
+
+
+## v0.21.1 / 2017-04-18
+### Styles
+* PopupWidget: Do not leave space for anchor if there's no anchor (Bartosz Dziewoński)
+* MediaWiki theme: Ensure WCAG level AA contrast on unsupported SelectFileWidget (Volker E)
+* MediaWiki theme: Fit icon/indicator & label in DecoratedOptionWidget (Volker E)
+* MediaWiki theme: Fix standalone, disabled sibling ButtonWidgets (Volker E)
+* MediaWiki theme: Fix white `border-color` of frameless buttons (Volker E)
+* MediaWiki theme: Make readonly TextInputWidget appearance clearer (Volker E)
+* MediaWiki theme: TagMultiselectWidget outlined UI improvements (Volker E)
+* MenuOptionWidget: Remove theme-independent 'check' icon (Prateek Saxena)
+
+### Code
+* environment: Upgrade jQuery from 1.11.3 to 3.2.1 (James D. Forrester)
+* DropdownInput-/RadioSelectInputWidget: Remove unnecessary ARIA attributes (Volker E)
+* Element: Use `JSON.parse` rather than the deprecated `$.parseJSON` (James D. Forrester)
+* Fix typo in frameless button mixin (David Lynch)
+* FloatingMenuSelectWidget: Add 'ready' event after menu is clipped (Moriel Schottlender)
+* MediaWiki theme: Clarify `@min-height-widget-default` usage (Volker E)
+* PopupToolGroup: Mixin flaggable (David Lynch)
+* TagMultiselectWidget: Allow preset InputWidget (Moriel Schottlender)
+* TagMultiselectWidget: Redo data validation for Tag* and Menu* (Moriel Schottlender)
+* themes: Align `@size-*-min` variable to naming scheme and rename (Volker E)
+* build: Drop the csscomb task (James D. Forrester)
+* docs: Fix numbering in Quick start (Kartik Mistry)
+* demos: Polish demo labels, styles and add frameless button tests (Volker E)
+* tests: Update OO.ui.Process tests for jQuery 3 compatibility (Bartosz Dziewoński)
+
+
+## v0.21.0 / 2017-04-11
+### Breaking changes
+* [BREAKING CHANGE] ActionWidget: Remove resize event (IvanFon)
+* [BREAKING CHANGE] dependencies: Drop support for ES3 browsers via es5-shim (James D. Forrester)
+
+### Features
+* Create a TagMultiselectWidget (Moriel Schottlender)
+* FloatingMenuSelectWidget: Add `width` config option (Moriel Schottlender)
+* MenuSelectWidget: Add `config.$autoCloseIgnore` (Roan Kattouw)
+
+### Styles
+* PopupWidget: Center the anchor for vertical (above/below) popups too (Bartosz Dziewoński)
+* MediaWiki theme: Add separator when toolbar items break on narrow (Volker E)
+* MediaWiki theme: Fix IE < 11 icon/indicator position in SelectFileWidget (Volker E)
+* MediaWiki theme: Fix overflow ellipsis on small DropdownWidget sizes (Volker E)
+* MediaWiki theme: Fix selector regression on DraggableElement (Volker E)
+* MediaWiki theme: Fix Toolbars containing ButtonGroups (David Lynch)
+* MediaWiki theme: Replace arrows with chevrons and increase contrast (Volker E)
+* MediaWiki theme: Unify `padding` across widgets and variablize (Volker E)
+* MediaWiki theme: Unify `padding` on ButtonElement (Volker E)
+* MediaWiki theme: Unify `padding` on DecoratedOptionWidget and descendants (Volker E)
+* Follow-up eceb6f20: MediaWiki theme: Remove unused indicator flags (Volker E)
+
+### Code
+* Remove remnants of PHP-5.3-style `array()` literals (Bartosz Dziewoński)
+* ClippableElement: Fix progressive width loss bug (Roan Kattouw)
+* ComboBoxInputWidget: Fix minor JS/PHP differences (Bartosz Dziewoński)
+* ComboBoxInputWidget: Redo the 'down' indicator in PHP (Bartosz Dziewoński)
+* DraggableElement: Only apply focus when widget is not disabled (Moriel Schottlender)
+* DraggableElement: Toggle style on `$handle`, not `$element` (Andrew Green)
+* DropdownInputWidget: Only allow setting values actually in the dropdown (Bartosz Dziewoński)
+* MenuSelectWidget: Highlight the first result when searching (Moriel Schottlender)
+* MessageDialog: Accept proposed size dialog on `getSetupProcess` (Ebrahim Byagowi)
+* TextInputWidget: Reduce unnecessary duplicated CSS output (Volker E)
+* TextInputWidget: Use `.prop()` rather than `.attr()` for 'required' (Bartosz Dziewoński)
+* Apex theme: Align coding style to conventions (Volker E)
+* Apex theme: Simplify color usage through Less variables (Volker E)
+* demos: Remove scaling restrictions (Volker E)
+* docparser: Improve trait/mixin handling (Bartosz Dziewoński)
+* docparser: Properly handle default values in PHP (Bartosz Dziewoński)
+* docs: Add detail to documentation of core.js utilities (Ed Sanders)
+* docs: Minor documentation tweaks (Bartosz Dziewoński)
+* tests: Comparison tests for infusing previously untestable classes (Bartosz Dziewoński)
+
+
+## v0.20.2 / 2017-03-30
+### Styles
+* DraggableElement: Fix regression on selectors (Volker E)
+
+### Code
+* GroupElement: Fix insertion bugs (Bartosz Dziewoński)
+* icons: Drop unused 'invert' variant from Apex 'icons-interactions' pack (Bartosz Dziewoński)
+* build: Add exec:composer and add it to `_ci` (Prateek Saxena)
+
+
+## v0.20.1 / 2017-03-28
+### Deprecations
+* [DEPRECATING CHANGE] icons: Deprecate and/or move all the core icons (James D. Forrester)
+* [DEPRECATING CHANGE] icons: Rename 'wikitrail' to 'mapTrail' (Volker E)
+* Follow-up b12205ac: Add deprecation notices to icons moved in v0.16.2 (James D. Forrester)
+* Follow-up da8d99af: Add deprecation notice to icon moved in v0.14.0 (James D. Forrester)
+
+### Features
+* DraggableGroupElement: Make draggable conditional (Moriel Schottlender)
+* build: Implement `grunt add-theme` task to ease theme creation (Bartosz Dziewoński)
+
+### Styles
+* ButtonElement: Normalize appearance in Firefox (Volker E)
+* Blank theme: Fix up the 'blank' theme (Bartosz Dziewoński)
+* MediaWiki theme: Position PopupToolGroup indicator similar to other widgets (Volker E)
+
+### Code
+* Element: Add special case for document root in getClosestScrollableContainer (Bartosz Dziewoński)
+* FloatableElement: Abort positioning if no longer attached (David Lynch)
+* GroupElement: Transform to be an OO.EmitterList mixin (Moriel Schottlender)
+* MenuOptionWidget: Remove inherited, duplicated property (Volker E)
+* OO.ui.isFocusableElement: Update for jQuery 3 deprecations (Bartosz Dziewoński)
+* PopupWidget: Add 'ready' event when the popup is ready (Moriel Schottlender)
+* Use Node.DOCUMENT_NODE rather than magic number (Bartosz Dziewoński)
+* Follow-up 4bc67351c5: Unbreak FloatableElement positioning (Roan Kattouw)
+* Follow-up Iaa7dffc13: *Actually* allow `$returnFocusTo` to be `null` (Ed Sanders)
+* themes: Reorder Less rules alphabetically (Volker E)
+* MediaWiki theme: Remove obsolete ButtonOptionWidget styles (Volker E)
+* MediaWiki theme: Remove unnecessary OptionWiget `border` property (Volker E)
+* build: Add a new jenkins script (Prateek Saxena)
+* build: Bump grunt-cssjanus to master (Volker E)
+* build: Match file order between tests/index and karma (Timo Tijhof)
+* build/demos: Generalize demos and build so that it's easier to add new themes (Bartosz Dziewoński)
+
+
+## v0.20.0 / 2017-03-15
+### Breaking changes
+* [BREAKING CHANGE] Element#scrollIntoView: Drop `complete` config option (James D. Forrester)
+* [BREAKING CHANGE] Element#scrollIntoView: Remove deprecated `complete` config parameter (James D. Forrester)
+* [BREAKING CHANGE] LabelElement: Remove deprecated `fitLabel` function (James D. Forrester)
+* [BREAKING CHANGE] MessageDialog: Drop the deprecated '`verbose`' flag (James D. Forrester)
+* [BREAKING CHANGE] PopupWidget#setAlignment: Remove backwards-compatibility (James D. Forrester)
+* [BREAKING CHANGE] Remove CapsuleMultiSelectWidget (James D. Forrester)
+* [BREAKING CHANGE] Remove TextInputMenuSelectWidget (James D. Forrester)
+* [BREAKING CHANGE] TextInputWidget: Remove `type=date`/`month` support (Geoffrey Mon)
+* [BREAKING CHANGE] icons: Drop '…Undo' icons, deprecated in 0.18.3 (James D. Forrester)
+* [BREAKING CHANGE] icons: Drop 'beta' and 'ribbonPrize', deprecated in 0.18.3 (James D. Forrester)
+* [BREAKING CHANGE] icons: Drop 'betaLaunch', deprecated in 0.18.3 (James D. Forrester)
+* [BREAKING CHANGE] icons: Drop status flags from Wikimedia (logos) icon pack (Volker E)
+
+### Deprecations
+* [DEPRECATING CHANGE] ActionWidget/Set: Warn for methods using the `resize` event (Prateek Saxena)
+
+### Features
+* Use `<span>` rather than `<div>` for inline-ish widgets (Bartosz Dziewoński)
+* CapsuleMultiselectWidget: Call `updateInputSize` when adding, removing items (Prateek Saxena)
+* DropdownInputWidget: Add support for `optgroup` (Prateek Saxena)
+* FieldLayout: Use `<span>` rather than `<div>` when possible (Bartosz Dziewoński)
+
+### Styles
+* DropdownInputWidget: Tweak PHP widget's disabled styling (Bartosz Dziewoński)
+* NumberInputWidget: Set input to 100% height (Volker E)
+* MediaWiki theme: Add unit to `line-height` for Chrome (Volker E)
+* MediaWiki theme: Align “framed” ButtonWidgets cross-browser (Volker E)
+* MediaWiki theme: Ensure theme color in disabled TextInputWidget on Safari (Volker E)
+* MediaWiki theme: Ensure vertical alignment of dialog top bar items (Volker E)
+* MediaWiki theme: Fix TextInputWidget's IconElement `max-height` (Volker E)
+* MediaWiki theme: Fix appearance of ComboBoxInputWidget PHP (Volker E)
+* MediaWiki theme: Use color palette color for dialog top bar (Volker E)
+* MediaWiki theme: Vertically align label in SelectFileWidget (Volker E)
+
+### Code
+* DropdownInputWidget: Remove accidental patterned background in PHP (Bartosz Dziewoński)
+* MediaWiki theme: Align WindowManager to CSS Coding Guidelines (Volker E)
+* MediaWiki theme: Indicators shouldn't provide global `progressive` flag (Volker E)
+* MediaWiki theme: Simplify Radio- & Checkbox…optionWidget label rules (Volker E)
+* build: Bump various devDependencies to master (James D. Forrester)
+* build: Exclude demos/vendor from composer test too (James D. Forrester)
+* demos: Add ButtonGroupWidget (icon and text) demo (Volker E)
+* demos: Add disabled DropdownInputWidget demo (Bartosz Dziewoński)
+
+
+## v0.19.5 / 2017-03-07
+### Deprecations
+* [DEPRECATING CHANGE] icons: Move 'add' from core to 'interactions' pack (James D. Forrester)
+
+### Features
+* FloatableElement: Add config for `hideWhenOutOfView` (Moriel Schottlender)
+
+### Styles
+* MediaWiki theme: Add visual feedback on focussed Outlined Booklet Dialog (Volker E)
+* OutlinedBookletDialog: Bring visual order into levels (Volker E)
+* icons: Add 'highlight' to 'editing-styling' pack (Moriel Schottlender)
+* icons: Add 'substract' icon, in interactions pack (Volker E)
+* icons: Fix vertical alignment of 'journal' (Volker E)
+* icons: Remove 'teardrop' from MediaWiki theme 'close' icon (Volker E)
+
+### Code
+* CapsuleMultiselectWidget: Update popup position if height changed (Prateek Saxena)
+* ComboBoxInputWidget: Improve documentation example (Bartosz Dziewoński)
+* ListToolGroup: Re-clip when expanding/collapsing (Roan Kattouw)
+* MenuSelectWidget#filterFromInput: Clear MenuSectionOptionWidgets if empty (Roan Kattouw)
+* PopupElement: Set `$floatableContainer` to `this.$element` by default (Roan Kattouw)
+* PopupTool: For bottom toolbars, make the popup go up, like toolgroups (Bartosz Dziewoński)
+* PopupWidget: Make popups able to actually pop *up*, as well as sideways (Roan Kattouw)
+* PopupWidget: Position anchor relative to popup, not popup relative to anchor (Roan Kattouw)
+* TextInputWidget: Fix documentation for 'maxRows' type (Bartosz Dziewoński)
+* Use `options` in ComboBoxInputWidget demo (Moriel Schottlender)
+* Follow-up 442ffe73, 7f21350d, 9dfa5dd5: Mention in icon definitions they're deprecated (James D. Forrester)
+* demos: Make demo consoles LTR, even in the RTL demo (Roan Kattouw)
+* demos: Add demo/test for PopupWidget/PopupButtonWidget placements (Bartosz Dziewoński)
+* demos: Add sections to dialogs demo (Bartosz Dziewoński)
+* demos: Extract widgets, dialogs and layouts from dialogs.js (Bartosz Dziewoński)
+* demos: Reuse some widgets in the dialogs demo (Bartosz Dziewoński)
+* styles: Replace stylelint block with inline comments everywhere (Volker E)
+
+
+## v0.19.4 / 2017-02-28
+### Features
+* Add `OO.ui.Element.static.getScrollLeft` (Bartosz Dziewoński)
+* FloatableElement: Support positioning relative to all edges (Roan Kattouw)
+
+### Styles
+* MediaWiki theme: Align DraggableElement focus with standard appearance (Volker E)
+* MediaWiki theme: Align appearance of PHP DropdownInputWidget to JS (Volker E)
+* MediaWiki theme: Fix TextInputWidget inline label misalignment (Volker E)
+* MediaWiki theme: Fix ToolGroupTool's label alignment (Volker E)
+* MediaWiki theme: Fix button layout in ButtonGroup-/SelectWidgets in IE 9 (Volker E)
+* MediaWiki theme: Fix styling for FieldLayout inside HorizontalLayout (Bartosz Dziewoński)
+* styles: Improve vertical alignment of elements' & widgets' icons (Ed Sanders/Volker E)
+* icons: Add 'feedback' icon, in interactions pack (Roan Kattouw)
+* icons: Add 'searchDiacritic' icon, in editing-advanced pack (Ed Sanders)
+
+### Code
+* Make generic placeholder pseudo-class browser-prefix mixin (Ed Sanders)
+* BookletLayout: When continuous, properly make the inner PageLayouts non-scrollable (Bartosz Dziewoński)
+* Element: Fix `scrollLeft()` for body/html/window (Roan Kattouw)
+* OutlineOptionWidget: Remove unused and misplaced values (Volker E)
+* PopupWidget: Remove `left: 0;` breaking floatable popups (Roan Kattouw)
+* MediaWiki theme: Remove obsolete ComboBoxInputWidget selectors (Volker E)
+* README: Encourage direct release in the instructions (James D. Forrester)
+* build: Test the 'minify' task in CI (James D. Forrester)
+* demos: Add 'label' to ToolGroupTool example (Bartosz Dziewoński)
+* demos: Extract ButtonStyleShowcaseWidget from the demo code (Bartosz Dziewoński)
+* demos: Extract CapsuleNumberPopupMultiselectWidget from the demo code (Bartosz Dziewoński)
+* demos: Extract remaining widgets from widgets.js (Bartosz Dziewoński)
+
+
+## v0.19.3 / 2017-02-21
+### Features
+* FieldLayout, FieldsetLayout: Add support for `$overlay` for help popups (Bartosz Dziewoński)
+* MenuSelectWidget: Add config option to not close on choose (Roan Kattouw)
+
+### Styles
+* MediaWiki theme: Make CapsuleItemWidget behave similar to other widgets (Volker E)
+* MediaWiki theme: SelectFileWidget drop target aligned to UX patterns (Volker E)
+
+### Code
+* BookletLayout: Remove unnecessary overrides (Bartosz Dziewoński)
+* Element#getClosestScrollableContainer: Update code comment (Bartosz Dziewoński)
+* FieldLayout, LabelWidget: If input has no ID, focus on element on label click (Prateek Saxena)
+* PopupWidget (and similar): Document why it is unwise to show unattached widgets, and emit warnings (Bartosz Dziewoński)
+* build: Bump stylelint and make pass (James D. Forrester)
+* demos: Add DropdownWidget (with MenuSectionOptionWidget) (Prateek Saxena)
+* demos: Further improve responsive layout (Volker E)
+* demos: Minor tweaks for button style showcase code (Bartosz Dziewoński)
+* demos: Rename OO.ui.Demo to just Demo (Bartosz Dziewoński)
+* demos: Replace `table` in button style showcase with responsive layout (Volker E)
+* demos: Set the default page in demo.js (Bartosz Dziewoński)
+
+
+## v0.19.2 / 2017-02-14
+### Features
+* CapsuleMultiselectWidget: Make labels work (Prateek Saxena)
+* FloatableElement, PopupWidget: Do positioning from the right in RTL (Roan Kattouw)
+* TextInputWidget: getValidity: Check browser validation first (Prateek Saxena)
+
+### Styles
+* icons: Fix vertical alignment of eye icon (Ed Sanders)
+
+### Code
+* core: Do not clear unrelated flags when clearing 'progressive' (Bartosz Dziewoński)
+* ActionWidget: Remove event listening code for widget's 'resize' event (Prateek Saxena)
+* ClippableElement: Order matters (inexplicably) (Bartosz Dziewoński)
+* demos: Use longer text in popup in $overlay demo (Bartosz Dziewoński)
+
+
+## v0.19.1 / 2017-02-07
+### Features
+* Dialog: Support meta as well as ctrl for modifier on enter key (David Lynch)
+
+### Styles
+* FieldLayout: Fix styling for disabled widgets in PHP (Bartosz Dziewoński)
+* MediaWiki theme: Align tab navigation to color palette (Volker E)
+* MediaWiki theme: Fix RTL version of largerText icon to be, well, RTL (James D. Forrester)
+* MediaWiki theme: Fix direction of shadow on position:bottom toolbars (Ed Sanders)
+* MediaWiki theme: Use correct `border-color` on PopupWidget anchor (Volker E)
+* Mediawiki theme: Fix focus inset to overlap scrollbars (Volker E)
+* icons: Provide a 'halfStar' vertical split star (codynguyen1116)
+
+### Code
+* CheckboxMultiselectInputWidget: Allow disabling specific options (Huji Lee)
+* DraggableGroupElement: Add mandatory ARIA role (Volker E)
+* FieldLayout: Move `<label>` from `$body` to `$label` (Bartosz Dziewoński)
+* FieldLayout: Remove the need for `simulateLabelClick` (Prateek Saxena)
+* InputWidget: Fix 'id' attribute setting for `<label>` (Bartosz Dziewoński)
+* LabelWidget: Remove the need for `simulateLabelClick` (Prateek Saxena)
+* Toolbar: Make toolbar position selectors more specific (Ed Sanders)
+* WindowManager: Clarify `#addWindows` documentation (Bartosz Dziewoński)
+* Windows: Use the "recommended" `WindowManager#addWindows` usage (Bartosz Dziewoński)
+* Apex theme: Get rid of toolbar-shadow div (only used by Apex) (Ed Sanders)
+* MediaWiki theme: Remove unnecessary `font-weight` property (Volker E)
+* build: Bump various dev dependencies to latest (James D. Forrester)
+* colorize-svg: Colorize using a method compatible with rsvg (Bartosz Dziewoński)
+* demos: Load icons stylesheets with correct directionality (LTR/RTL) (Bartosz Dziewoński)
+* demos: Follow-up a02979ad: Load the icons-content pack in the PHP demo (James D. Forrester)
+* demos: Remove 'Constructive' button from the icons page (Prateek Saxena)
+* demos: Add link to documentation (Prateek Saxena)
+* demos: Fix regression on toolbars demo (Volker E)
+* docs: Add quotes around `PROJECT_NAME` setting (Ricordisamoa)
+* docs: Document for JSDuck various overridden inherited properties (Bartosz Dziewoński)
+* docs: Fix `OO.ui.prompt()` documentation (Bartosz Dziewoński)
+* docs: Set `.static.name` in all dialog examples that need it (Bartosz Dziewoński)
+
+
+## v0.19.0 / 2017-01-31
+### Breaking changes
+* [BREAKING CHANGE] ButtonWidget: Switch `box-sizing` over to `border-box` (Volker E)
+* [BREAKING CHANGE] LabelElement: Drop no-op fitLabel() method. (James D. Forrester)
+* [BREAKING CHANGE] WindowManager: Error if `.static.name` is not defined when adding a window (Bartosz Dziewoński)
+
+### Features
+* PopupButtonWidget: Add `$overlay` config option (Bartosz Dziewoński)
+* SelectWidget: Allow OptionWidget subclasses to provide custom match text (Roan Kattouw)
+* Toolbar: Support `position:bottom` (Ed Sanders)
+
+### Styles
+* CapsuleMultiselectWidget: Fix focussing when inside BookletLayout with popup (Bartosz Dziewoński)
+* CapsuleMultiselectWidget: Styling tweaks related to popups (Bartosz Dziewoński)
+* MenuSelectWidget: Override ClippableElement's `min-height` (Bartosz Dziewoński)
+* PopupWidgets: Unify paddings and line-height (Bartosz Dziewoński)
+* TextInputWidget/MediaWiki theme: Revert "Improve Less code and align labels" (Bartosz Dziewoński)
+* PanelLayout/Apex theme: Revert regression (Volker E)
+
+### Code
+* CapsuleMultiSelectWidget: Call correct parent constructor (Ricordisamoa)
+* CapsuleMultiselectWidget: Make popup really work with $overlay (Bartosz Dziewoński)
+* FieldsetLayout: Swap 'max-width' and 'width' (Bartosz Dziewoński)
+* FloatableElement: More correctly decide if we need custom position (Bartosz Dziewoński)
+* MenuSelectWidget: Hide menu if all items are hidden (Bartosz Dziewoński)
+* ProcessDialog: Account for `config.flags` being undefined (Ed Sanders)
+* Follow-up 1dc6a45: {Booklet,Index}Layout: Avoid deprecated `config.complete` (Roan Kattouw)
+* Follow-up d21cf8a: unbreak popups with no $floatableContainer (Roan Kattouw)
+* PHP: Avoid unique ID conflicts between PHP and JS code (Bartosz Dziewoński)
+* demos: Failing demo for DropdownWidget with an overlay (Roan Kattouw)
+* demos: Fix vertical spacing in icons demo (Bartosz Dziewoński)
+* demos: Improve layout on mobile and fix various glitches (Volker E)
+* demos: Make the icon page easier to use (Prateek Saxena)
+* demos: Use longer text in PopupWidgets to showcase line wrapping (Bartosz Dziewoński)
+
+
+## v0.18.4 / 2017-01-17
+### Deprecations
+* [DEPRECATING CHANGE] MessageDialog: Default 'verbose' option to true (James D. Forrester)
+* Follow-up 1dc6a45: Emit deprecations from Element#scrollIntoView callback (James D. Forrester)
+* Follow-up 4518bcf: Emit deprecation warnings for LabelElement#fitLabel (James D. Forrester)
+* Follow-up 574fd34: Emit deprecations for use of CapsuleMultiSelectWidget (James D. Forrester)
+* Follow-up ea9a4ac: Throw deprecation warnings for TextInputMenuSelectWidget (James D. Forrester)
+* Follow-up f69a2ad: Emit deprecations for old PopupWidget#setAlignment values (James D. Forrester)
+
+### Features
+* CapsuleMultiSelectWidget: Add allowDuplicates option (Brad Jorsch)
+* CapsuleMultiSelectWidget: Remove onFocusForPopup, call focus directly (Roan Kattouw)
+* ClippableElement: Add `min-height` for usability in edge cases (Volker E)
+* TextInputWidget: Disable hiding focus when clicking indicator/label (Volker E)
+
+### Styles
+* ActionFieldLayout: Limit the 'max-width: 50em' to align: top (Bartosz Dziewoński)
+* ButtonGroupWidget: Limit default cursor to active ButtonWidgets (Volker E)
+* FieldLayout, FieldsetLayout: Limit width of label+help to 50em (Bartosz Dziewoński)
+* FieldLayout: Correct styling regressions for align: 'inline' (Bartosz Dziewoński)
+* FieldLayout: Fix positioning of 'help' with align: left/right (Bartosz Dziewoński)
+* MediaWiki theme: Unify box-shadows to one visual appearance (Volker E)
+* PanelLayout: Remove 3D appearance of framed panels and harmonise padding (Volker E)
+* PopupWidget: Change margins to prevent click blocking (Ed Sanders)
+
+### Code
+* ClippableElement: Also clean up `maxWidth`, `maxHeight` when turning clipping off (Bartosz Dziewoński)
+* Element#updateThemeClasses: Batch `setTimeout()` calls (Bartosz Dziewoński)
+* MediaWiki theme: Use variable for disabled ProgressBar (Volker E)
+* PopupWidget#setAlignment: Tweak docs to indicate default parameter value (James D. Forrester)
+* PHP: Add method Tag::generateElementId() to match JS OO.ui.generateElementId() (Bartosz Dziewoński)
+* styles: Improve and clarify GPU composite layer mixin (Volker E)
+* demos: Add a LabelWidget that has a corresponding TextInputWidget (Prateek Saxena)
+* demos: Add lots more FieldLayout demos (Bartosz Dziewoński)
+* demos: Add test for ClippableElements at the bottom of their containers (Prateek Saxena)
+* docs: Use 'an' instead of 'a' before 'HTML' (Prateek Saxena)
+* docs: Include an i18n example in OO.ui.msg documentation (David Lynch)
+* tests: Improve ignoring expected differences in JS/PHP comparison tests (Bartosz Dziewoński)
+* tests: Tweaks to the display of failed tests (Bartosz Dziewoński)
+* testsuitegenerator: Allow testing LabelWidget's 'input' (Bartosz Dziewoński)
+* testsuitegenerator: Specify sensible values to test for 'align' (Bartosz Dziewoński)
+* testsuitegenerator: Test FieldLayout etc. also with TextInputWidget (Bartosz Dziewoński)
+
+
+## v0.18.3 / 2017-01-03
+### Deprecations
+* [DEPRECATING CHANGE] icons: Deprecate the 'beta' and 'ribbonPrize' icons (James D. Forrester)
+* [DEPRECATING CHANGE] icons: Rename '*Undo' to 'un*' (James D. Forrester)
+* [DEPRECATING CHANGE] icons: Rename 'betaLaunch' to 'logoWikimediaDiscovery', move pack (James D. Forrester)
+
+### Features
+* ComboBoxInputWidget: Make it impossible to set `multiline` to true (Prateek Saxena)
+* Introduce `OO.ui.isMobile()` (Ed Sanders)
+* Provide `OO.ui.prompt()` method to complement `confirm()`/`alert()` (Ed Sanders)
+
+### Styles
+* FloatableElement: Replace superfluous class with general one (Volker E)
+* MediaWiki theme: Change custom error border color to `destructive` (Volker E)
+* MediaWiki theme: Change error/invalid color to alias of `destructive` (Volker E)
+* MediaWiki theme: Fix PHP CheckboxMultiselectInputWidget/RadioSelectInputWidget option spacing (Bartosz Dziewoński)
+* MediaWiki theme: Indicate normal, flagged ButtonWidgets' `:hover` clearer (Volker E)
+* MediaWiki theme: Set `line-height` explicitly on legends and labels (Volker E)
+
+### Code
+* BarToolGroup: Remove obsolete CSS selectors (Volker E)
+* ClippableElement: Compatibility with jQuery 3 (Bartosz Dziewoński)
+* Element: Do not try to scroll invisible/unattached elements into view (Bartosz Dziewoński)
+* LabelWidget: Properly hide labels if they are set to null (Ed Sanders)
+* NumberInputWidget: Avoid bitwise tricks when checking for integers (Bartosz Dziewoński)
+* PopupButtonWidget: Remove unnecessary CSS property (Volker E)
+* ProgressBarWidget: Use CSS transforms for indeterminate widget (Bartosz Dziewoński)
+* TextInputWidget: Do nothing in `#adjustSize`/`#positionLabel` if not attached (Bartosz Dziewoński)
+* TextInputWidget: Only call `#onElementAttach` on focus if it wasn't called (Bartosz Dziewoński)
+* TextInputWidget: Use `Element#isElementAttached` (Bartosz Dziewoński)
+* styles: Replace `transform` with dedicated mixin (Volker E)
+* MediaWiki theme: Make `box-shadow` LESS vars follow naming scheme (Volker E)
+* MediaWiki theme: Simplify frameless ButtonWidget selectors (Volker E)
+* performance: Apply webkit GPU hack to scrollable panels (Ed Sanders)
+* demos: Add disabled Progress bar (Volker E)
+* demos: Add examples for `OO.ui.alert()`/`confirm()`/`prompt()` (Bartosz Dziewoński)
+* demos: Avoid using 'required' as a test indicator (Ed Sanders)
+* build: Bump file copyright notices for 2017 (James D. Forrester)
+* docs: Fix small typo (Amir Sarabadani)
+
+
+## v0.18.2 / 2016-12-06
+### Styles
+* MediaWiki theme: Address sub-pixel rendering issues of RadioInputWidgets (Volker E)
+* MediaWiki theme: Improve `:active:focus` states on ButtonElements (Volker E)
+* MediaWiki theme: Reduce MapPin icons' hole for better recognisability (Volker E)
+
+### Code
+* FieldsetLayout: Temporarily remove use of `<legend>` due to Chrome 55 bug (Bartosz Dziewoński)
+* TextInputWidget/MediaWiki theme: Improve Less code and align labels (Volker E)
+
+
+## v0.18.1 / 2016-11-29
+### Features
+* PopupElement: Allow $autoCloseIgnore to be overridden (Roan Kattouw)
+* WindowManager: Allow $returnFocusTo to be null (Ed Sanders)
+
+### Styles
+* MediaWiki theme: Reduce, align `margin` and `padding` of form elements (Volker E)
+* MediaWiki theme: Replace color function with palette color (Volker E)
+* MediaWiki theme: Standard placeholder colours for CapsuleMultiselectWidget too (Bartosz Dziewoński)
+* MediaWiki theme: Tweak destructive red for background-independent contrast (Volker E)
+
+### Code
+* Field & Fieldset: Make help popup code consistent (Ed Sanders)
+* PopupWidget: Consistently use OO.ui.contains() for auto-closing (Roan Kattouw)
+* build: Bump eslint-config-wikimedia to v0.3.0 and make pass (James D. Forrester)
+* eslint: Re-enable wrap-iife and partially enable dot-notation (Ed Sanders)
+
+
+## v0.18.0 / 2016-11-08
+### Breaking changes
+* [BREAKING CHANGE] ComboBoxWidget: Remove this deprecated alias for ComboBoxInputWidget (James D. Forrester)
+* [BREAKING CHANGE] core: Remove {add|remove}CaptureEventListener (James D. Forrester)
+* [BREAKING CHANGE] icons: Remove deprecated alias 'photoGallery' (Ed Sanders)
+* [BREAKING CHANGE] InputWidget: Remove deprecated #setRTL function (James D. Forrester)
+* [BREAKING CHANGE] MediaWiki theme: Remove deprecated `constructive` variables (Volker E)
+* [BREAKING CHANGE] TextInputWidget: remove isValid() method, deprecated since v0.12.3 (Ricordisamoa)
+
+### Deprecations
+* [DEPRECATING CHANGE] Break out parts of TextInputWidget into a new SearchInputWidget (Prateek Saxena)
+
+### Features
+* ButtonElement: Add `role="button"` only when needed (Prateek Saxena)
+* ButtonWidget: Remove code to not let the button get focus after clicking (Prateek Saxena)
+* CapsuleMultiselectWidget: Add placeholder option (Prateek Saxena)
+* CapsuleMultiselectWidget: Don't discard current input value when editing an item (Bartosz Dziewoński)
+* ComboBoxInputWidget: Hide dropdown indicator when there is no dropdown (Volker E)
+* TextInputWidget: Add methods #setRequired / #isRequired (Bartosz Dziewoński)
+* TextInputWidget: Allow type="month" (Geoffrey Mon)
+* WindowManager: Add a $returnFocusTo property (Prateek Saxena)
+* Add OO.ui.warnDeprecation method (Prateek Saxena)
+
+### Styles
+* ButtonElement: Normalize `:focus` appearance in Firefox (Volker E)
+* ButtonGroupWidget: Change `cursor` on `.oo-ui-buttonElement-active` (Volker E)
+* CapsuleItemWidget: Make interactivity of label clearer (Volker E)
+* ComboBoxInputWidget: Align to design specification (Volker E)
+* PopupToolGroup: Fix border colour (Ed Sanders)
+* MessageDialog: Improve `-actions` buttons by resetting `border-radius` (Volker E)
+* SelectFileWidget: Don't show action-indicating cursor on empty state (Volker E)
+* MediaWiki theme: Fix border colours in toolbar (Ed Sanders)
+* MediaWiki theme: Address subpixel rendering errors in buttoned widgets (Volker E)
+* MediaWiki theme: Align readonly TextInputWidget to overhauled color palette (Volker E)
+* MediaWiki theme: Fix `:hover` in ComboBoxInput- & CapsuleMultiselectWidget (Volker E)
+* MediaWiki theme: Fix ButtonElement's `:active:focus` state visually (Volker E)
+* MediaWiki theme: Fix FieldsetLayouts' icon position (Volker E)
+* MediaWiki theme: Fix SelectFileWidget's label visibility in IE11 (Volker E)
+* MediaWiki theme: Fix visual glitch CheckboxInputWidget's `:active` state (Volker E)
+* MediaWiki theme: Fix visual glitch on `:active:focus` widgets state (Volker E)
+* MediaWiki theme: Fix wrong colored `box-shadow` on ToggleSwitchWidget (Volker E)
+* MediaWiki theme: Make colors follow color palette (Volker E)
+* MediaWiki theme: Make placeholder follow WCAG 2.0 level AA contrast ratio (Volker E)
+* MediaWiki theme: Replace abandoned color from early palette iteration (Volker E)
+* MediaWiki theme: Use `@color-progressive` for progress bar (Volker E)
+* MediaWiki theme: Use `color-progressive` for switched-on binary inputs (Volker E)
+* icons: Replace bigger/smaller with more obvious forms (Ed Sanders)
+
+### Code
+* CapsuleMultiSelectWidget: Always keep input as wide as placeholder text (Prateek Saxena)
+* CapsuleMultiselectWidget: Fix crash on right-click when no input (Moriel Schottlender)
+* OutlineOptionWidget: Follow-up de9058299f: don't duplicate parent's logic (Roan Kattouw)
+* Toolbar: Defer computation of the narrow threshold (Roan Kattouw)
+* Window: Update `-content` CSS so that child elements can give it focus (Prateek Saxena)
+* Window#withoutSizeTransitions: Build transition property using sub-properties (Prateek Saxena)
+* WindowManager: Warn if .static.name is not defined when adding a window (Bartosz Dziewoński)
+* Tag: Generate valid HTML for self-closing tags (Bartosz Dziewoński)
+* OO.ui.warnDeprecation: Fix how we use getProp (Prateek Saxena)
+* MediaWiki theme: Add W3C Standards Notation for placeholder pseudo class (Volker E)
+* MediaWiki theme: Clarify usage of `@max-width-*` Less variables (Volker E)
+* MediaWiki theme: Refactor z-index inside ButtonSelectWidget/ButtonGroupWidget (Bartosz Dziewoński)
+* demo: Add FieldsetLayout with icon (Bartosz Dziewoński)
+* demo: Align to color palette (Volker E)
+* demo: Fix for IE 9 (Bartosz Dziewoński)
+* demo: Remove deprecated TextInputWidget (type=search) (Volker E)
+* demo: Fix PHP demo directionality (Bartosz Dziewoński)
+* demo: Remove PHP 5.3 compatibility, version check and PHPCS exception (Bartosz Dziewoński)
+* build: Make MediaWiki the default theme in doc live previews (Ed Sanders)
+* build: Remove obsolete csscomb rules (Volker E)
+* build: Remove upstreamed rules and fix documentation (Ed Sanders)
+* build: Update eslint-config-wikimedia to v0.2.0 (Ed Sanders)
+
+## v0.17.10 / 2016-10-03 (special release)
+### Styles
+* FieldsetLayout: Styling fixes for `<legend>` labels (Bartosz Dziewoński)
+* FieldsetLayout: Work around positioning problems in Firefox (Bartosz Dziewoński)
+
+## v0.17.9 / 2016-09-13
+### Features
+* DropdownWidget: Add CSS class to widgets with open dropdown menus (Volker E)
+* SelectFileWidget: Remove MIME type information (Volker E)
+* TextInputWidget: Make disabled fields' inner labels unselectable (Volker E)
+
+### Styles
+* ActionToolGroup: Show left border, instead of right (Ed Sanders)
+* ButtonElement: Centralize styling properties (Volker E)
+* ButtonOptionWidget: Make active state carry default cursor (Volker E)
+* Radio- and CheckboxInputWidget: Fix visual disabled state on labels (Volker E)
+* ToggleButtonWidget: Use inverted variant when initially active (Leszek Manicki)
+
+* MediaWiki theme: Adjust CheckboxInputWidget to match M30 design (Volker E)
+* MediaWiki theme: Adjust RadioInputWidget to match M29 design (Volker E)
+* MediaWiki theme: Align Dropdown- & CapsuleMultiSelectWidget `:focus` state (Volker E)
+* MediaWiki theme: Align disabled text contrast to WCAG compliance (Volker E)
+* MediaWiki theme: Enhance button styles and align them to new color palette (Volker E)
+* MediaWiki theme: Fix ButtonElement-active on flagged & primary buttons (Volker E)
+* MediaWiki theme: Fix `:hover` state of ComboBoxInputWidget (Volker E)
+* MediaWiki theme: Fix regression on `border` of active (selected) buttons (Volker E)
+* MediaWiki theme: Improve appearance of CapsuleMultiselectWidget with child (Volker E)
+* MediaWiki theme: Make ToggleSwitchWidget's disabled state follow enabled (Volker E)
+* MediaWiki theme: Make colors' contrast compliant to WCAG 2.0 level AA (Volker E)
+* MediaWiki theme: Toolbar: Use progressive colors for active and active-hover (Prateek Saxena)
+* MediaWiki theme: Unify `-pressed` and `-emphasized` color var (Volker E)
+* MediaWiki theme: Unify different widgets' selected menu state (Volker E)
+* MediaWiki theme: Use a solid border for disabled SelectFile drop target (Volker E)
+
+### Code
+* FieldsetLayout: Make use of `<fieldset>` and `<legend>` tags (Volker E)
+* NumberInputWidget: Clean-up Less code & remove style properties (Volker E)
+* NumberInputWidget: Simplify CSS selectors & fix button text alignment (Volker E)
+* TextInputWidget: Treat `rows: 0` the same in PHP and in JS (Bartosz Dziewoński)
+* Toolbar: Simplify and concatenate selectors (Volker E)
+* MediaWiki theme: Align tools' variables to common vars naming convention (Volker E)
+* MediaWiki theme: Clean-up unnecessary properties in ToolGroup (Volker E)
+* build: Align csscomb configuration with CSS coding conventions (Volker E)
+* build: Introduce eslint to replace jshint and jscs (James D. Forrester)
+* build: Limit the file list of jsonlint (Ed Sanders)
+* build: Remove jshint and jscs, now done in eslint (James D. Forrester)
+* docs: IndexLayout: Fix ReferenceError in code sample (Prateek Saxena)
+* git: Add .idea directory to .gitignore (Florian)
+* testsuitegenerator: Also support 'int' and 'bool' (Bartosz Dziewoński)
+* testsuitegenerator: Simplify code generating all possible config options (Bartosz Dziewoński)
+
+
+## v0.17.8 / 2016-08-16
+### Features
+* ProgressBarWidget: Do not make zero progress indeterminate (Leszek Manicki)
+* ProgressBarWidget: Add PHP version (Leszek Manicki)
+* TextInputWidget: Show state as valid (no matter the case) on focus (Prateek Saxena)
+
+### Styles
+* ButtonElement: Fix 'active' state icon variants in MediaWiki theme (Bartosz Dziewoński)
+* FieldLayout: Use saner line-height for errors/notices (Bartosz Dziewoński)
+* SelectFileWidget: Improve thumbnail appearance (Volker E)
+* styles: Inherit specific `font` properties, not all (Volker E)
+* MediaWiki theme: Clear border on selected framed buttons (Volker E)
+* MediaWiki theme: Fix ButtonWidget (frameless, indicator) `:focus` appearance (Volker E)
+* MediaWiki theme: Fix ToggleSwitchWidget's sub-pixel rounding errors (Volker E)
+
+
+### Code
+* MediaWiki theme: Improve CapsuleMultiselectWidget Less code and behaviour (Volker E)
+* MediaWiki theme: Improve DropdownWidget Less code and behaviour (Volker E)
+* MediaWiki theme: Removing never applied styles on BarToolGroup (Volker E)
+* MediaWiki theme: Simplify ToolGroup selectors (Volker E)
+* testsuitegenerator: Specify sensible values to test for 'progress' (Bartosz Dziewoński)
+
+
+## v0.17.7 / 2016-08-03
+### Styles
+* MediaWiki theme: Apply `border-color` on `:hover` to textInputWidgets (Volker E)
+* MediaWiki theme: Decrease `margin`/`padding` on `legend` replacement (Volker E)
+* MediaWiki theme: Decrease distance between label and Checkbox*-/Radio*Widget (Volker E)
+* MediaWiki theme: Improve UX on ToggleSwitchWidget (Volker E)
+* icons: Fix vertical alignment of 'bell' by moving up 1px (Ed Sanders)
+* icons: Provide a 'tray' icon in alerts pack (James D. Forrester)
+* icons: Provide the alerts pack for Apex theme too (James D. Forrester)
+
+### Code
+* CheckboxMultiselectWidget: Rewrite Shift-clicking code (Bartosz Dziewoński)
+* NumberInputWidget: Merge object literals being passed as config for buttons (Prateek Saxena)
+* SelectFileWidget: Reduce div soup when 'showDropTarget' is enabled (Prateek Saxena)
+* styles: Replace unprefixed `box-sizing` property with mixin (Volker E)
+* MediaWiki theme: Disable vendor UI extensions on every `type=number` input (Volker E)
+* MediaWiki theme: Remove unnecessary toolGroup selector (Volker E)
+* MediaWiki theme: Replace `border` property values with Less variables (Volker E)
+* MediaWiki theme: Replace static `color` value with Less variable (Volker E)
+* build: Add 'prep-test' task to be run before running tests in the browser (Prateek Saxena)
+* build: Align to stylelint-config-wikimedia for `!important` (James D. Forrester)
+* build: Align to stylelint-config-wikimedia for string quotes (James D. Forrester)
+* build: Bump stylelint-related devDependencies to latest (James D. Forrester)
+* build: Downgrade grunt-jscs to 2.8.0 to avoid cst bug (James D. Forrester)
+* docs: Correct some code comments in PHP mixins (Bartosz Dziewoński)
+* standalone tests: Correct error message (Bartosz Dziewoński)
+
+
+## v0.17.6 / 2016-07-12
+### Features
+* CapsuleMultiselectWidget: Allow ignoring user input for 'allowArbitrary' widgets (Bartosz Dziewoński)
+* Dialog: Set the 'title' attribute on the title LabelWidget (Prateek Saxena)
+* ToolFactory: Allow '\*' as an item in a toolgroup include list (Ed Sanders)
+* Window: make the focus trap smarter (David Lynch)
+
+### Styles
+* Add aria-hidden to several Layouts (David Lynch)
+* Add dialog transition duration to theme JS file (Ed Sanders)
+* ButtonGroupWidget: Fix border on button's CSS states (Volker E)
+* MediaWiki theme: Normalize [placeholder] appearance x-browser and ensure a11y (Volker E)
+* MediaWiki theme: Unify ButtonWidget focus `border-radius` values (Volker E)
+* styles: Set `line-height` to unitless values to follow best practice (Volker E)
+* icons: Give "Stop" a filled background, aligned with others in the pack (Volker E)
+* icons: Unify cross-out lines direction to top-left/bottom-right (Volker E)
+
+### Code
+* README: Replace git.wikimedia.org URL with Phabricator one (Paladox)
+* build: Bump stylelint devDependencies to latest (James D. Forrester)
+* build: Update karma and karma-coverage to latest (Paladox)
+* demo: Dialogs: Removing title from SimpleDialog as it'll never show (Prateek Saxena)
+* docs: Remove self-closing tag syntax in comments and demos (Volker E)
+* docs: LabelWidget: Add TitledElement mixin (Prateek Saxena)
+* package: Replace git.wikimedia.org url with diffusion url (Paladox)
+
+
+## v0.17.5 / 2016-06-19
+### Styles
+* Dropdown,SelectFileWidget: Improve user experience on disabled widgets (Volker E)
+* MediaWiki theme: Fix ToggleSwitchWidget's grip circle shape (Volker E)
+* MediaWiki theme: Fix focus states of ActionWidget's buttons (Volker E)
+* MediaWiki theme: Improve focus states of primary buttons & ToggleSwitchWidget (Volker E)
+
+### Code
+* DraggableGroupWidget: Remove unnecessary `cursor` property (Volker E)
+* GroupElement#removeItems: Fix to actually unbind events (Ed Sanders)
+* ProcessDialog: Change DOM ordering of actions (David Lynch)
+* MediaWiki theme: Remove `line-height` from TextInputWidget `input` (Volker E)
+* MediaWiki theme: Remove obsolete `color` property, which never gets applied (Volker E)
+* build: Bump devDependencies to latest and make pass (James D. Forrester)
+* composer: Exclude copied demo PHP from phpcs test (James D. Forrester)
+* demos: Add descriptive hints on navigation types to dialog names (Volker E)
+
+
+## v0.17.4 / 2016-05-31
+### Features
+* DropdownWidget: Handle type-to-search when menu is not expanded (Bartosz Dziewoński)
+* Implement MultiselectWidget, CheckboxMultiselectWidget and CheckboxMultiselectInputWidget (Bartosz Dziewoński)
+* SelectWidget: Improve focus behaviour (Bartosz Dziewoński)
+
+### Styles
+* icons: Use B/I/S/U icons for British and Candian English variants (Ed Sanders)
+* MediaWiki theme: Provide an adjacent disabled ButtonGroup/SelectWidget button border (Volker E)
+* MediaWiki theme: Make iconed and non-iconed buttons have the same height (Roan Kattouw)
+
+### Code
+* ButtonElement: Remove unnecessary inheritance duplication of `display` (Volker E)
+* GroupWidget: Mix in GroupElement, rather than inherit from it (Bartosz Dziewoński)
+* LookupElement: Add missing `@mixins` documentation (Bartosz Dziewoński)
+* SelectWidget: Implement `#getFirstSelectableItem` in terms of `#getRelativeSelectableItem` (Bartosz Dziewoński)
+* SelectWidget: Optimize `#getRelativeSelectableItem` without filter (Bartosz Dziewoński)
+* styles: Remove unnecessary CSS rules on disabled buttons (Volker E)
+* styles: Simplify disabled `.oo-ui-tool-link` rules (Volker E)
+
+
+## v0.17.3 / 2016-05-24
+### Deprecations
+* [DEPRECATING CHANGE] CapsuleMultiSelectWidget: Rename to CapsuleMultiselectWidget (Bartosz Dziewoński)
+
+### Features
+* SelectWidget/OptionWidget: Implement selecting by accesskey (Bartosz Dziewoński)
+* TextInputWidget: Stop returning 'multiline' from 'getSaneType' (Prateek Saxena)
+
+### Styles
+* SelectFileWidget: Improve consistency to other widgets (Volker E)
+* MediaWiki theme: Align styles of normal and not-supported SelectFileWidgets (Volker E)
+
+### Code
+* CapsuleMultiselectWidget: Prefer Array#map to jQuery.map (Bartosz Dziewoński)
+* CapsuleMultiselectWidget: Use OO.ui.findFocusable() (Bartosz Dziewoński)
+* dependencies: Update es5-shim to v4.5.8 (James D. Forrester)
+* build: Bump grunt-stylelint to v0.3.0 (James D. Forrester)
+* build: Bump various devDependencies to latest (James D. Forrester)
+* build: Fix watch path for css (Ed Sanders)
+* build: Remove grunt-cli (Ed Sanders)
+* build: Upgrade stylelint-config-wikimedia to 0.2.0 and make pass (James D. Forrester)
+* build: Use stylelint instead of csslint (Volker E)
+* docs: Add some missing @mixins documentation (Bartosz Dziewoński)
+* stylelint: Add `@` whitespace and name case rules (Volker E)
+* stylelint: Add `@media` whitespace rules (Volker E)
+* stylelint: Add block formatting rules (Volker E)
+* stylelint: Add font rules (Volker E)
+* stylelint: Add no duplicate property rule (Volker E)
+* stylelint: Add selector whitespace (Volker E)
+* stylelint: Add whitespace rules (Volker E)
+* stylelint: Change to use central Wikimedia configuration (Volker E)
+* stylelint: Use null instead of false to disable rules (Ed Sanders)
+
+
+## v0.17.2 / 2016-05-10
+### Features
+* ButtonWidget: Implement, document and demonstrate the 'active' config option (Bartosz Dziewoński)
+
+### Styles
+* ToggleSwitchWidget: Align focus state with other widgets (Volker E)
+* MediaWiki theme: Remove `border-radius` from disabled numberInputWidget buttons (Volker E)
+
+### Code
+* TextInputWidget: Remove proprietary `<input results>` attribute styles (Volker E)
+* MediaWiki theme: Align `input` & `textarea` coding style to Less way (Volker E)
+
+
+## v0.17.1 / 2016-05-03
+### Styles
+* CapsuleMultiSelectWidget: Fix cross-browser inconsistencies and improve UX (Volker E)
+* SelectFileWidget: Add `no-drop` cursor where it belongs (Volker E)
+* MediaWiki theme: Align focus state of capsuleItemWidget with other widgets (Volker E)
+* MediaWiki theme: Custom `:focus` state for SelectWidgets (Bartosz Dziewoński)
+* MediaWiki theme: Standardize `:focus` states of ButtonWidgets (Volker E)
+
+### Code
+* DraggableGroupElement: Simplify and improve drag logic (Ed Sanders)
+
+
+## v0.17.0 / 2016-04-26
+### Breaking changes
+* [BREAKING CHANGE] PHP: Use traits instead of custom mixin system (Kunal Mehta)
+* [BREAKING CHANGE] TitledElement.php: Remove $element::$title fallback (Kunal Mehta)
+
+### Styles
+* MenuToolGroup: Correct display of checkmarks (Bartosz Dziewoński)
+* OutlineOptionWidget: Correct the size of the icons (David Lynch)
+* OutlineOptionWidget: Don't apply italics to "placeholder" status (James D. Forrester)
+* SelectFileWidget: Fix UI glitches on over-long filenames (Volker E)
+* TabOptionWidget: Disabled OptionWidget should receive default cursor (Volker E)
+* styles: Add fullScreen icon to media group (Ed Sanders)
+
+### Code
+* ButtonElement.php: Fix toggleFramed() to actually be chainable (Bartosz Dziewoński)
+* GroupElement::$targetPropertyName: Remove, no longer needed (Kunal Mehta)
+* IconElement.php: Rename protected "icon" property (Kunal Mehta)
+* IndicatorElement.php: Rename protected "indicator" property (Kunal Mehta)
+* LabelElement.php: Rename protected "label" property (Kunal Mehta)
+* build: Update grunt-svg2png to v0.2.7-wmf.1 (Paladox)
+* demos: Split off demos.php from widgets.php (Bartosz Dziewoński)
+* docparser: Remove commented-out line of code (Bartosz Dziewoński)
+* styles: Factor out `max-width-input-default` variable (Volker E)
+
+
+## v0.16.6 / 2016-04-19
+### Features
+* ButtonOptionWidget: Inherit OptionWidget, not DecoratedOptionWidget (Bartosz Dziewoński)
+* ClippableElement: Gracefully handle failure to call clip() after natural height change (Roan Kattouw)
+* NumberInputWidget: Disable onWheel action unless the widget has focus (Bartosz Dziewoński)
+* NumberInputWidget: Disable onWheel action when the widget is disabled (Prateek Saxena)
+* NumberInputWidget: Use input type="number" (Prateek Saxena)
+* TextInputWidget: Allow type="number" (Prateek Saxena)
+* TextInputWidget: Set step to 'any' if the type is set to 'number' (Prateek Saxena)
+* styles: Give icons, indicators `min-width/-height` for cross-browser support (Volker E)
+
+### Styles
+* Apex, MediaWiki themes: Properly center PopupButtonWidget anchors (Roan Kattouw)
+* MediaWiki theme: Use disabled color variable for disabled label (Volker E)
+* styles: Use transparent rather than white in icons (Bartosz Dziewoński)
+
+### Code
+* SelectFileWidget: Merge identical CSS rules (Volker E)
+* SelectFileWidget: Simplify CSS selector specificity (Volker E)
+* TextInputWidget: Clarify comment about affected browsers (Volker E)
+* TextInputWidget: Consolidate selectors with the same property rules (Volker E)
+* TextInputWidget: Stop claiming to fire non existent events in the documentation (Prateek Saxena)
+* styles: Centralise the width/height properties of icons and indicators (Volker E)
+* Apex theme: Change variable names to match MediaWiki theme (Bartosz Dziewoński)
+* README: Update with new build process (Matthew Flaschen)
+* typo: texfield -> textfield (Derk-Jan Hartman)
+
+
+## v0.16.5 / 2016-04-07
+### Styles
+* Prevent modal windows from exceeding available height on Firefox (Bartosz Dziewoński)
+* Apex, MediaWiki themes: Add "articles" icon (Marc A. Pelletier)
+* DropdownInputWidget: Give un-infused widget cursor:pointer (Ed Sanders)
+* RadioSelectInputWidget: Match PHP styling to JS (Bartosz Dziewoński)
+
+### Code
+* ComboBoxInputWidget: Disable autocomplete by default (James D. Forrester)
+* GroupElement: Add change event (Prateek Saxena)
+* GroupElement.php: Use strict mode in array_search (James D. Forrester)
+* styles: Lower specifity of CSS type attribute selectors (Volker E)
+* styles: Minor cleanup and unification of values and comments (Volker E)
+* styles: Remove unnecessary `resize` property from `select` (Volker E)
+* MediaWiki theme: Exchange `rgba()` with hex CSS colors to support IE 8 (Volker E)
+* MediaWiki theme: Replace fixed CSS property values with variables (Volker E)
+* RadioSelectInputWidget: Don't try to reuse DOM when infusing (Bartosz Dziewoński)
+* TextInputWidget: Use getValidity in demos (Ricordisamoa)
+* Window: Correct documentation (Bartosz Dziewoński)
+* build: Add browserNoActivityTimeout to karma (Paladox)
+* build: For grunt-svg2png use a tag instead of git hash (Paladox)
+* build: Update demos script to also run grunt publish-build (Paladox)
+* build: Use a version of grunt-svg2png without a rate-limited CDN (Paladox)
+
+
+## v0.16.4 / 2016-03-22
+### Features
+* NumberInputWidget: Optionally don't show the increment buttons (Thalia Chan)
+
+### Styles
+* NumberInputWidget: Fix rounded corners when showButtons=false (Ed Sanders)
+
+### Code
+* core: Add tests for throttle (David Lynch)
+* Tag: Allow appendContent and prependContent to accept an array (Moriel Schottlender)
+* LabelElement: Cast label to string before check if it is empty (Florian)
+* README.md: Add note about needing composer, clean up more generally (James D. Forrester)
+* build: Bump grunt-karma to 0.12.2 (Paladox)
+* build: Drop the 'npm prepublish' task which runs pre-install as well (James D. Forrester)
+* demos: Restore constructive widgets (James D. Forrester)
+* rubocop: Re-run todos, upgrade to newer rule names (James D. Forrester)
+* rubocop: Review todos (Bartosz Dziewoński)
+
+
+## v0.16.3 / 2016-03-16
+### Features
+* core: Add `#throttle` to complement `#debounce` (David Lynch)
+* ClippableElement: Never exceed the dimensions of the browser viewport (Bartosz Dziewoński)
+* FloatableElement: Hide if the anchor element is outside viewport (Bartosz Dziewoński)
+
+### Styles
+* Apex, MediaWiki themes: Fix vertical alignment of close icon (Ed Sanders)
+* MediaWiki theme: Disabled ButtonElement icon should not be colored (Bartosz Dziewoński)
+
+### Code
+* ButtonInputWidget: Actually disallow non-plaintext labels in 'useInputTag' mode (Bartosz Dziewoński)
+* Element: Preserve `OOUI\HtmlSnippet( '' )` when infusing (Bartosz Dziewoński)
+* InputWidget: Actually reuse parts of the DOM when infusing (Bartosz Dziewoński)
+* MediaWiki theme: Remove broken remnant of d6b05bc0 (Bartosz Dziewoński)
+* TextInputWidget: Treat empty placeholder the same in PHP and JS (Bartosz Dziewoński)
+* TitledElement: Treat empty title the same in PHP and JS (Bartosz Dziewoński)
+* build: Bump devDependencies to latest (James D. Forrester)
+* build: Bump devDependencies to latest (Paladox)
+* build: Update grunt-svg2png to commit 2fe1dad07eaec4b655263f8b487a672df4b668b4 (Paladox)
+* demo: Expand the dialog $overlay demo for testing scrolling things off-screen (Bartosz Dziewoński)
+* tests: Emulated setTimeout for unit testing (David Chan)
+* testsuitegenerator: Always test empty values for 'string' type, not just for 'label' (Bartosz Dziewoński)
+* testsuitegenerator: Change values tested for 'flags' config options (Bartosz Dziewoński)
+* testsuitegenerator: Test 'HtmlSnippet' type (mostly for labels) (Bartosz Dziewoński)
+
+
+## v0.16.2 / 2016-03-08
+### Deprecations
+* [DEPRECATING CHANGE] MediaWiki theme: Scrap `constructive` flag (Volker E)
+* [DEPRECATING CHANGE] Move some editing icons from core to editing-* (James D. Forrester)
+
+### Features
+* Dialog: trigger the primary action with ctrl-enter (David Lynch)
+* TextInputWidget: Allow type="date" (Geoffrey Mon)
+
+### Styles
+* Apex, MediaWiki themes: Add markup '<>' icon in editing-advanced (Ed Sanders)
+* Apex, MediaWiki themes: Drop padding from buttons in MessageDialogs (James D. Forrester)
+* editing-styling pack: Have uk fallback to use ru bold and italic icons (Paladox)
+* styles: Remove superflous pseudo-class and unitize comments (Volker E)
+
+### Code
+* CapsuleMultiSelectWidget: Emit 'resize' when widget height changes (Bartosz Dziewoński)
+* TextInputWidget: Prevent uncaught errors when using #selectRange in IE (Ed Sanders)
+* TextInputWidget: Update comment about Blink height miscalculation (Bartosz Dziewoński)
+* Follow-up I0667fbc: Fix draggable element CSS (Ed Sanders)
+* Add Element::configFromHtmlAttributes() helper method (Bartosz Dziewoński)
+* Clean-up duplicate properties across widgets (Volker E)
+* docs: Clarify the lack of `.oo-ui-box-shadow()` mixin (Volker E)
+
+
+## v0.16.1 / 2016-03-01
+### Styles
+* CapsuleItemWidget: Revert regression on "remove" button in Firefox (Volker E)
+
+### Code
+* ActionFieldLayout: Add max-width: 50em; (Florian)
+* DraggableGroupElement: Don't emit reorder event when action is a no-op (Ed Sanders)
+* Element: Fix #gatherPreInfuseState called incorrectly, causing TypeErrors (Thiemo Mättig)
+* NumberInputWidget: fix example (Ricordisamoa)
+* SelectWidget: fix incorrect `@return` that should be `@param` (Ricordisamoa)
+* build: Compress PNGs with Zopfli etc. after they are built (James D. Forrester)
+* build: Enable all passing jscs jsDoc rules (Ricordisamoa)
+* build: Enable jscs jsDoc rule 'checkAnnotations' and make pass (Ricordisamoa)
+* build: Enable jscs jsDoc rule 'checkParamNames' and make pass (Ricordisamoa)
+* build: Enable jscs jsDoc rule 'checkTypes' and make pass (Ricordisamoa)
+* build: Enable jscs jsDoc rule 'requireNewlineAfterDescription' and make pass (Ricordisamoa)
+* build: Enable jscs jsDoc rule 'requireReturnTypes' and make pass (Ricordisamoa)
+* demos: Display a nicer error message on old PHP versions (Kunal Mehta)
+
+
+## v0.16.0 / 2016-02-22
+### Breaking changes
+* [BREAKING CHANGE] DraggableGroupElement: Add default implementation of reorder (Ed Sanders)
+* [BREAKING CHANGE] Remove 'noimages' distribution (Bartosz Dziewoński)
+* [BREAKING CHANGE] Require PHP 5.5.9+; drop old array syntax (James D. Forrester)
+* [BREAKING CHANGE] SelectFileWidget: Remove deprecated config 'dragDropUI' (Prateek Saxena)
+
+### Deprecations
+* [DEPRECATING CHANGE] MenuOptionsWidgets: Drop jQuery autoEllipsis support (Bartosz Dziewoński)
+
+### Features
+* core#debounce: If an immediate timeout is already waiting, don't re-set it (Bartosz Dziewoński)
+* LabelElement: Bring in highlightQuery method from VE (Ed Sanders)
+* DraggableElement: Defer adding of -dragging class so it isn't applied to copy (Ed Sanders)
+* DraggableElement: Introduce $handle config option (Ed Sanders)
+* DraggableGroupElement: Live reorder list while dragging (Ed Sanders)
+* DraggableGroupElement: Only show meaningful drop positions (Ed Sanders)
+
+### Styles
+* CapsuleItemWidget: Tweak styles for the "remove" button (Bartosz Dziewoński)
+* MenuSelectWidget: Bring some sanity styling when inside different widgets (Bartosz Dziewoński)
+* NumberInputWidget: Apex: Round the correct corners in the disabled state (Prateek Saxena)
+* styles: Use block rather than inline-block to avoid line height issues (Bartosz Dziewoński)
+* MediaWiki theme: Restore non-broken version of eye.svg (Bartosz Dziewoński)
+
+### Code
+* Avoid parsing HTML when creating <input> nodes (Bartosz Dziewoński)
+* tests: Actually run core test suite in standalone mode (Bartosz Dziewoński)
+* Compress PNGs with zopflipng (Ori Livneh)
+* DraggableGroupElement: Cache directionality (Ed Sanders)
+* DraggableGroupElement: Fix offset calculation (Ed Sanders)
+* DraggableGroupElement: Reduce flicker when dragging (Ed Sanders)
+* TextInputWidget: Don't call #updatePosition if there's no label to position (Bartosz Dziewoński)
+* PHP: Take advantage of PHP 5.5 understanding ( new Foo )->foo (Bartosz Dziewoński)
+* README: Update Phabricator URL broken by upgrade (James D. Forrester)
+* build: Bump grunt-svg2png to a newer (still personal) version; lots faster (James D. Forrester)
+
+## v0.15.4 / 2016-02-16
+### Deprecations
+* [DEPRECATING CHANGE] Element#scrollIntoView: Replace callback with promise (Ed Sanders)
+
+### Features
+* SelectWidget: Prevent mouse highlighting while typing-to-select (Bartosz Dziewoński)
+
+### Styles
+* PHP DropdownInputWidget: Match height of <option> to JS MenuOptionWidget (Bartosz Dziewoński)
+
+### Code
+* DraggableElement: Remove 'HACK' comment, this isn't a hack (Bartosz Dziewoński)
+* Element: Expand variable names in scrollIntoView (Ed Sanders)
+* Element, ListToolGroup: Add some missing documentation (Ed Sanders)
+* Element#scrollIntoView: Make the promise version actually work (Bartosz Dziewoński)
+* PopupWidget: Only build head and footer if we're going to use it (Bartosz Dziewoński)
+* PopupWidget: Tweak some comments (Bartosz Dziewoński)
+* styles: Remove initial value `ease` from `transition` (Volker E)
+
+## v0.15.3 / 2016-02-09
+### Features
+* CapsuleItemWidget: Let user tab through items, edit and delete them (Prateek Saxena)
+* CapsuleMultiSelectWidget: Edit instead of remove on backspace (Prateek Saxena)
+* CapsuleWidgets: Edit on click and remove on Ctrl+Backspace (Prateek Saxena)
+* CapsuleWidgets: Toggle through capsules and the input with arrow keys (Prateek Saxena)
+* DropdownWidget: Open menu on up and down arrow keys (Prateek Saxena)
+* MenuSelectWidget: Ensure currently selected element is visible when menu opens (Bartosz Dziewoński)
+* SelectFileWidget: Show thumbnail when dropTarget is shown (Prateek Saxena)
+* Really preserve dynamic state of widgets when infusing (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki, Apex themes: Replace 'language' icon with tweaked version (Mun May Tee)
+
+### Code
+* CapsuleItemWidget: Use Button instead of an Indicator (Prateek Saxena)
+* CapsuleMultiSelectWidget: Extend config instead of when setting property (Prateek Saxena)
+* InputWidget: Remove the 'setAccessKey' method (Prateek Saxena)
+* SelectWidget: Really prevent default action during type-to-select (Bartosz Dziewoński)
+* Put '@keyframes' rules inside a mixin to avoid duplicating them (Bartosz Dziewoński)
+* Apex theme: Remove unnecessary '@keyframes' prefixing (Bartosz Dziewoński)
+* Mediawiki theme: Align button mixins/states to CSS guidelines/standard (Volker E)
+* Correct code using plain DOM events documented as jQuery events (Bartosz Dziewoński)
+* demo: Add a long DropdownInputWidget demo (Bartosz Dziewoński)
+* demo: In PHP demo, load oojs-ui-core only instead of whole oojs-ui (Bartosz Dziewoński)
+* demo: Measure time needed to construct the demo (Bartosz Dziewoński)
+* demo: widgets: OO.ui.CapsuleMultiSelectWidget: Remove non-existent 'values' config (Prateek Saxena)
+* docparser: Recognize and ignore '@uses' (Bartosz Dziewoński)
+* docs: OO.ui.CapsuleMultiSelectWidget: Config options (Prateek Saxena)
+* docs: OO.ui.CapsuleMultiSelectWidget: Link to the widget it uses (Prateek Saxena)
+* docs: OO.ui.SelectFileWidget: Minor language change (Prateek Saxena)
+
+
+## v0.15.2 / 2016-02-02
+### Features
+* DropdownWidget: Prevent label from overflowing the handle (Bartosz Dziewoński)
+
+### Styles
+* Ensure gradient filter rendering on IE 8&9 (Bartosz Dziewoński)
+* Remove unused CSS classes .oo-ui-ltr and .oo-ui-rtl (Bartosz Dziewoński)
+* Update `.oo-ui-vertical-gradient` mixin to modern times (Volker E)
+
+### Code
+* Unify SVG icon color values to CSS/Less coding standards (Volker E)
+* ComboBoxInputWidget: Don't make the 'datalist' infusable (Bartosz Dziewoński)
+* Move OO.ui.alert and OO.ui.confirm methods to separate file (Bartosz Dziewoński)
+* README: Add "Loading the library" wherein we apologise for the mess that is the dist/ directory (Bartosz Dziewoński)
+* build: Actually check that all required files are not missing (Bartosz Dziewoński)
+* build: Add intro.js.txt and outro.js.txt to all distribution JS files (Bartosz Dziewoński)
+* build: De-duplicate per-theme modules lists (Bartosz Dziewoński)
+* build: Only define one 'less' task, not one per-distribution (Bartosz Dziewoński)
+* build: Remove unused 'ieCompat' options from 'less' (Bartosz Dziewoński)
+* build: Remove unused 'report' options from 'less' (Bartosz Dziewoński)
+* build: Small modules.yaml tweaks (Bartosz Dziewoński)
+* build: Split the library into four parts (Bartosz Dziewoński)
+* build: Switch modules.json to YAML to document some of the weird stuff we've put in there (Bartosz Dziewoński)
+* build: Unbreak `grunt build --graphics=vector` (Bartosz Dziewoński)
+* build: Update phpunit/phpunit to 4.8 (Paladox)
+* docparser: Parse '@class Foo' annotations, not just '@class' (Bartosz Dziewoński)
+
+
+## v0.15.1 / 2016-01-26
+### Features
+* Really filter out unsafe URLs, but don't throw silly exceptions (Bartosz Dziewoński)
+* ClippableElement: Try to prevent unnecessary scrollbars (Bartosz Dziewoński)
+* Dialog: Don't set `overflow:hidden;` on `.oo-ui-window-body` elements (Alex Monk)
+* TextInputWidget: Don't fail if 'validate' function returns null (Bartosz Dziewoński)
+
+### Styles
+* WindowManager: Only apply `top: 1em; bottom: 1em;` to non-fullscreen windows (Bartosz Dziewoński)
+* Align mixin whitespace to CSS/Less coding guidelines (Volker E)
+* Enable `cursor: pointer` just on enabled widgets (Volker E)
+* Apex, MediaWiki themes: Fix size of templateAdd icon (Ed Sanders)
+* Apex, MediaWiki themes: Quotes icon fixes (Ed Sanders)
+* Apex, MediaWiki themes: Re-crush SVGs, removing useless ID values and empty groups (James D. Forrester)
+* Apex theme: Fix FieldLayout padding in inline mode (Ed Sanders)
+* Apex theme: NumberInputWidget: Fix width of +/- buttons (Ed Sanders)
+* MediaWiki theme: Add invert variant to 'accessibility' icon pack icons (Bartosz Dziewoński)
+* MediaWiki theme: Align `@input-*` vars to coding guidelines (Volker E)
+* MediaWiki theme: Align `rgba()` values to CSS/Less guidelines (Volker E)
+* MediaWiki theme: Align size variables to CSS/Less guidelines (Volker E)
+* MediaWiki theme: Consolidate emphasized color values into variable (Volker E)
+* MediaWiki theme: Establish new `@border-default` variable (Volker E)
+* MediaWiki theme: Make icon variants actually work for all icons (Bartosz Dziewoński)
+* MediaWiki theme: Make transition of text input fields smoother (Volker E)
+* MediaWiki theme: Merge `@oo-ui-toolbar-bar-text` & `@color-default` vars (Volker E)
+* MediaWiki theme: Replace fixed & consolidate disabled values with vars (Volker E)
+* MediaWiki theme: Update avatar icon (Pau Giner)
+
+### Code
+* NumberInputWidget: Replace `box-sizing` property with mixin as anywhere else (Volker E)
+* SelectFileWidget: Order name and type spans in the order they are shown (Prateek Saxena)
+* TextInputWidget: Simplify `#getValidity` (Bartosz Dziewoński)
+* README: Add a 'Contributing' section (James D. Forrester)
+* build: Don't generate .min.js and .min.css files by default (Bartosz Dziewoński)
+* build: Only build one graphics distribution (mixed/vector/raster), not all (Bartosz Dziewoński)
+* build: Update jakub-onderka/php-parallel-lint to 0.9.2 (Paladox)
+* build: Update mediawiki/mediawiki-codesniffer to 0.5.1 (Paladox)
+* demo: Extend compounded form in widget.js demo (Volker E)
+
+## v0.15.0 / 2016-01-12
+### Breaking changes
+* [BREAKING CHANGE] Drop Internet Explorer 8 support from JavaScript code (Ricordisamoa)
+* [BREAKING CHANGE] Delete deprecated aliases 'picture' and 'insert' (Ed Sanders)
+
+### Deprecations
+* [DEPRECATING CHANGE] Create single icon for language/translation (Ed Sanders)
+* [DEPRECATING CHANGE] Move 'redirect' icon to 'articleRedirect' and cleanup (Ed Sanders)
+* [DEPRECATING CHANGE] core: Deprecate add/removeCaptureEventListener (Bartosz Dziewoński)
+
+### Features
+* Send escape key cancel events through action handler (Alex Monk)
+
+### Styles
+* MediaWiki theme: Align variable values & properties to CSS/Less guidelines (Volker E)
+* MediaWiki theme: Align `@neutral-button-border` to CSS/Less guidelines (Volker E)
+* MediaWiki theme: Align `transition` variables with coding guidelines (Volker E)
+* MediaWiki theme: Change color value to Less variable (Volker E)
+* MediaWiki theme: Clarify `@active` variable by renaming it (Volker E)
+* MediaWiki theme: Clarify `@background` var by renaming it (Volker E)
+* MediaWiki theme: Clarify `@select` variable by renaming it (Volker E)
+* MediaWiki theme: Clarify `@text` variable by renaming it (Volker E)
+* MediaWiki theme: Consolidate stray `margin` and `padding` properties (Volker E)
+* MediaWiki theme: Remove unnecessary `@-ms-keyframes` vendor rule (Volker E)
+* MediaWiki theme: Replace fixed `invalid` color value with variable (Volker E)
+* MediaWiki theme: Unify `border` property values (Volker E)
+* MediaWiki theme: Unify `border-radius` values (Volker E)
+* MediaWiki theme: Unify `-disabled` variables usage (Volker E)
+
+### Code
+* core: Add constants for MouseEvent.which button codes (Ed Sanders)
+* demo: Remove IE 8 support (Bartosz Dziewoński)
+* build: Fix typos ("overridden") (Ed Sanders)
+* build: Bump file copyright notices for 2016 (James D. Forrester)
+* build: Update most devDependencies to latest (James D. Forrester)
+* build: Updating development dependencies (Kunal Mehta)
+
+## v0.14.1 / 2015-12-08
+
+### Features
+* Implement OO.ui.alert() and OO.ui.confirm() (Bartosz Dziewoński)
+
+### Styles
+* CapsuleMultiSelectWidget: Interface tweaks (Bartosz Dziewoński)
+* CapsuleMultiSelectWidget: Make the text field span all available area (Bartosz Dziewoński)
+* CapsuleMultiSelectWidget: Update menu position when typing (Bartosz Dziewoński)
+* HorizontalLayout: Synchronise behaviour between themes (Bartosz Dziewoński)
+* Apex theme: Enlarge 'search' icon (Bartosz Dziewoński)
+* MediaWiki theme: Correct text color in MessageDialog, TabOptionWidget (Volker E)
+
+### Code
+* Tool*: Consolidate and cross-link some documentation (Bartosz Dziewoński)
+* Tool*: Expand, correct docs for #onUpdateState and the related event (Bartosz Dziewoński)
+* core.js: Extract a large chunk of the file incorrectly in a closure (Bartosz Dziewoński)
+* Apex, MediaWiki themes: Standardize XML structure for various 'search' images (Bartosz Dziewoński)
+* MediaWiki theme: Add missing theme mixin placeholder (no-op) (Bartosz Dziewoński)
+* build: Test PHP documentation with Doxygen via composer and make pass (James D. Forrester)
+* demo: Quit using the 'image' icon in documentation examples (Bartosz Dziewoński)
+
+## v0.14.0 / 2015-11-24
+### Breaking changes
+* [BREAKING CHANGE] Depend on OOjs v1.1.10, up from v1.1.9 (James D. Forrester)
+* [BREAKING CHANGE] TextInputWidget: Remove old deprecated alias #setPosition (Ed Sanders)
+
+### Deprecations
+* [DEPRECATING CHANGE] De-duplicate 'trash' and 'remove' icons (James D. Forrester)
+
+### Features
+* TextInputWidget: Add insertContent method (Thalia Chan)
+* TextInputWidget: Add encapsulateContent method to insert new content around a selection (Thalia Chan)
+
+### Styles
+* Apex theme: Provide the 'interactions' icon pack (James D. Forrester)
+* MediaWiki theme: Make dialog and panel box-shadows outset rather than inset (Ed Sanders)
+
+### Code
+* FlaggedElement.php: Fix type hint (Reedy)
+* SelectFileWidget: Remove sometimes-incorrect 'title' on the <input> (Bartosz Dziewoński)
+* SelectFileWidget: Use i18n string for button label (Ed Sanders)
+* TextInputWidget: Fix documentation of insertContent method (Thalia Chan)
+* \*.php: Replace `@chainable` jsduck-ism with `@return` $this (Reedy)
+* .gitattributes: Ignore both `/doc` and `/docs` directories (James D. Forrester)
+* AUTHORS: Update for the past few months' work (James D. Forrester)
+* build: Added Rakefile (Željko Filipin)
+
+## v0.13.3 / 2015-11-17
+### Deprecations
+* [DEPRECATING CHANGE] Duplicate icons: Unify 'picture' and 'image' (Ed Sanders)
+
+### Features
+* RequestManager: Introduce a mixin for widgets that need to do API calls (David Lynch)
+* TextInputWidget: Add getRange method (Ed Sanders)
+* WindowManager: Allow getSetup/ReadyProcess to reject (Ed Sanders)
+* WindowManager: Fade in overlay after 'setup' not 'ready' (Ed Sanders)
+
+### Styles
+* MediaWiki, Apex themes: Remove small 0.1em vertical margin from buttons (Bartosz Dziewoński)
+* MediaWiki theme: Add destructive variant to the 'cancel' icon (James D. Forrester)
+* MediaWiki theme: Reduce whitespace between FieldLayouts (Bartosz Dziewoński)
+
+### Code
+* TitledElement: Behave like its docs say it should (David Lynch)
+* Use null for abstract methods and correct documentation (Ed Sanders)
+* demo: Make button style showcase a table (Bartosz Dziewoński)
+
+## v0.13.2 / 2015-11-10
+### Deprecations
+* [DEPRECATING CHANGE] ComboBoxWidget: Refactor into ComboBoxInputWidget (Bartosz Dziewoński)
+* [DEPRECATING CHANGE] MediaWiki, Apex themes: Unify add/insert icons (Ed Sanders)
+
+### Features
+* ComboBoxInputWidget: Implement PHP version (Bartosz Dziewoński)
+* LookupElement: Make auto-highlighting the first term configurable (Florian)
+
+### Styles
+* Add some missing white backgrounds and use variables when possible (Bartosz Dziewoński)
+* MediaWiki theme: Make the menu icon identical to Apex's (Ed Sanders)
+* MediaWiki theme: Specify 'line-height' for DropdownWidget's handle (Bartosz Dziewoński)
+* WikiText icon: Make slightly narrower (Ed Sanders)
+
+### Code
+* Apex theme: Remove dead styles for ComboBoxWidget (Bartosz Dziewoński)
+* build: Make copy:fastcomposerdemos work again (Bartosz Dziewoński)
+
+## v0.13.1 / 2015-11-03
+### Deprecations
+* [DEPRECATING CHANGE] InputWidget: Replace `#setRTL` with `#setDir` (Ed Sanders)
+
+### Features
+* Allow widgets to re-use parts of the DOM when infusing; use for InputWidget's `$input` (Bartosz Dziewoński)
+* FieldLayout: Allow setting errors and notices dynamically (Bartosz Dziewoński)
+* InputWidget: Add '`dir`' to config (Ed Sanders)
+
+### Styles
+* TextInputWidget: Account for scroll bar width when positioning indicators/labels (Ed Sanders)
+* TextInputWidget: Ensure icon+indicator+label are top aligned in multi-line mode (Ed Sanders)
+
+### Code
+* FieldLayout: Mark `#makeMessage` as `@protected` (Bartosz Dziewoński)
+* History.md: wrap `<select>` tag in backticks (Ricordisamoa)
+* tests: Refactor property->attribute copying (Ed Sanders)
+
+## v0.13.0 / 2015-10-27
+### Breaking changes
+* [BREAKING CHANGE] Remove aliases for OO.ui.mixins, deprecated in 0.11.4 (C. Scott Ananian)
+* [BREAKING CHANGE] Turn Element#gatherPreInfuseState into a static method (Bartosz Dziewoński)
+
+### Features
+* Update outline widget when current item is scrolled out of view (Ed Sanders)
+* TextInputWidget: Emit 'resize' events (Ed Sanders)
+* TextInputWidget: Fix scrollbars in `<textarea>`s in IE8-11 (Ed Sanders)
+* TextInputWidget: Improve selection API (Ed Sanders)
+
+### Styles
+* MediaWiki theme: Adjust ToggleSwitchWidget to match M61 design (Volker E)
+* Follow-up I54f1e3c92: Fix placement of cursors on checkbox/radio widgets (Volker E)
+* Follow-up I598e7b25a: Apply MenuToolGroup missing styles fix to Apex theme (Ed Sanders)
+
+### Code
+* Consistently use '`//`' rather than '`/* */`' for Less comments (Bartosz Dziewoński)
+* Remove obsolete Opera<12.1 vendor prefixes (Volker E)
+* Remove unnecessary IE10beta vendor-prefixes from OOjs UI (Volker E)
+* build: Switch back to upstream version of grunt-contrib-concat (Timo Tijhof)
+* build: Updating development dependencies (Kunal Mehta)
+* build: Use my Gmail address for attribution (Timo Tijhof)
+
+## v0.12.12 / 2015-10-13
+### Features
+* CapsuleMultiSelectWidget: When 'allowArbitrary' is true, don't require 'Enter' to confirm (Bartosz Dziewoński)
+* SelectFileWidget: Add a focus method (Ed Sanders)
+
+### Styles
+* CapsuleMultiSelectWidget: Set 'background-color' rather than 'background' (Bartosz Dziewoński)
+* DropdownWidget: Fix vertical alignment of handle's text (Volker E)
+* MediaWiki theme: Get transitions on ButtonWidget's `:hover` states in sync (Volker E)
+* MediaWiki theme: Unbreak checkbox/radio 'cursor: pointer' (Bartosz Dziewoński)
+* MediaWiki theme: Use inverted icon for 'active' buttons (Ed Sanders)
+
+### Code
+* ButtonElement: Actually use 'active' property and add getter (Ed Sanders)
+* Element: Document $element config option (Thalia)
+* composer.json: Add author names & e-mails (Alangi Derick)
+* demo: Correct some typos (Bartosz Dziewoński)
+
+## v0.12.11 / 2015-10-06
+### Styles
+* MediaWiki theme: Make shadows translucent black instead of light grey (Ed Sanders)
+* MediaWiki theme: Make PHP DropdownInputWidget look closer to JS version (Bartosz Dziewoński)
+
+### Code
+* Follow-up I4acbe69420: BookletLayout: Fix focus of page switching (Ed Sanders)
+* IndexLayout: Fix focus of panel switching (Ed Sanders)
+* TextInputWidget: Remove 'autocomplete' attribute on page navigation (Bartosz Dziewoński)
+* build: Bump es5-shim and various devDependencies to master (James D. Forrester)
+
+## v0.12.10 / 2015-09-29
+### Styles
+* Fix icon/indicator padding on TextInputWidget/SelectFileWidget (Ed Sanders)
+
+### Code
+* CapsuleItemWidget: Remove 'click' event preventing (Bartosz Dziewoński)
+* FloatableElement: Don't try unbinding events before we bind them (Bartosz Dziewoński)
+* SelectWidget: Ensure 'choose' never emits null (Ed Sanders)
+* Remove old textInputWidget-decorated classes (Ed Sanders)
+* build: Upgrade MediaWiki-Codesniffer to 0.4.0 (Kunal Mehta)
+
+## v0.12.9 / 2015-09-22
+### Features
+* BookletLayout, IndexLayout: Make autoFocus and focussing more reliable (Bartosz Dziewoński)
+* CapsuleMultiSelectWidget: Allow using CapsuleItemWidget subclasses (Bartosz Dziewoński)
+* CardLayout: Add a 'label' config option (Ed Sanders)
+* FloatableElement: Introduce mixin (Bartosz Dziewoński)
+* FloatingMenuSelectWidget: Update position of menus within overlay while scrolling (Bartosz Dziewoński)
+* IndexLayout: Add 'expanded' option, passed through to StackLayout (Ed Sanders)
+* MenuLayout: Use child selectors to allow nesting menus (Ed Sanders)
+* Re-attempt I31ab2bace4: Try to stop user from tabbing outside of open dialog box (Ed Sanders)
+
+### Styles
+* SelectFileWidget: Move file type over to the right in secondary text colour (Ed Sanders)
+* Fix focus styles on disabled widgets (Volker E)
+* Apex, MediaWiki themes: Make most borders on table icon thinner (Ed Sanders)
+* Apex, MediaWiki themes: Make picture icon border thinner (Ed Sanders)
+* MediaWiki theme: Alter buttons' padding and position icons absolutely (nirzar)
+* MediaWiki theme: Fix height of IndexLayout tab widget (Ed Sanders)
+* MediaWiki theme: Unify box-shadows for PopupWidget and DropdownWidget (Volker E)
+
+### Code
+* #isFocusableElement: Rewrite for performance and correctness (Ed Sanders)
+* BookletLayout: Remove unnecessary JSHint override (Bartosz Dziewoński)
+* DropdownWidget: Update example doc to show #getMenu usage (Ed Sanders)
+* Follow-up bf1497be: Fix PopupToolGroup use of renamed Clippable property (Ed Sanders)
+* PopupWidget: Add missing `@mixins` doc entry (Bartosz Dziewoński)
+* SelectFileWidget: Fix DOM order of file type label (Ed Sanders)
+* Widget: Fix docs for disable event (Ed Sanders)
+* docs: Remove excess empty lines in comments (Bartosz Dziewoński)
+* docs: Add quotes around PROJECT_BRIEF setting (Timo Tijhof)
+
+## v0.12.8.1 / 2015-09-18 (special release)
+### Code
+* build: Update version requirement for mediawiki/at-ease: 1.0.0 → 1.1.0 (Ori Livneh)
+
+## v0.12.8 / 2015-09-08
+### Styles
+* SelectFileWidget: Overflow and ellipsis for label (Ed Sanders)
+* Apex theme: Move transition timing to common variables (Prateek Saxena)
+* MediaWiki theme: Move window transition to `@medium-ease` variable (Prateek Saxena)
+* MediaWiki theme: Add missing `width` and `height` attributes to icons (Ed Sanders)
+* Clean up CSS values in .oo-ui-transition calls (Timo Tijhof)
+* Use 'ease' instead of 'ease-in-out' for CSS transitions (Timo Tijhof)
+
+### Code
+* Toolbar: Prevent double initialization (Roan Kattouw)
+* build: Bump grunt-contrib-jshint from 0.11.2 to 0.11.3 to fix upstream issue (James D. Forrester)
+* build: Upgrade grunt-banana-checker to v0.3.0 (James D. Forrester)
+
+## v0.12.7 / 2015-09-01
+### Deprecations
+* [DEPRECATING CHANGE] SelectFileWidget: Re-design to use a clearly clickable button (Ed Sanders)
+
+### Styles
+* FieldLayout: Don't add `margin-bottom` when in a HorizontalLayout (Florian)
+* SelectFileWidget: Use gray for hover and `@progressive-fade` for drop active (Prateek Saxena)
+* Apex, MediaWiki themes: Fix scale of external link icon (Ed Sanders)
+* Apex, MediaWiki themes: Re-crush all SVG files with SVGO (James D. Forrester)
+* Apex, MediaWiki themes: Reduce size of 'close' icon by 1px (Ed Sanders)
+* Apex, MediaWiki themes: Remove Inkscape-ism from SVG files (James D. Forrester)
+* Apex, MediaWiki themes: Standardise XML prolog for SVG files (Bartosz Dziewoński)
+* MediaWiki theme: Fix viewBox of arrow indicators (Ed Sanders)
+* MediaWiki theme: Fix viewBox of several icons (James D. Forrester)
+
+### Code
+* LookupElement: Really disallow editing of `readOnly` TextInputWidgets (Bartosz Dziewoński)
+* SelectFileWidget: Fix drop and drop hover exception in Firefox (Ed Sanders)
+* SelectFileWidget: Improve type checking (Ed Sanders)
+
+## v0.12.6 / 2015-08-25
+### Features
+* AccessKeyedElement: Introduce (Florian)
+* ButtonOptionWidget: Mixin TitledElement (Bartosz Dziewoński)
+* ClippableElement: Allow $clippableContainer to be different from $clippable (Roan Kattouw)
+* Dialog: Listen for Escape key on $element, not document (Roan Kattouw)
+* InputWidget: Add TitledElement and AccessKeyedElement mixins (Florian)
+* PopupWidget: Make it possible to add static footers (Moriel Schottlender)
+* SelectFileWidget: Add drag drop UI as a config (Prateek Saxena)
+* TextInputWidget: Add moveCursorToEnd() (Roan Kattouw)
+
+### Styles
+* MenuToolGroup: Add some missing styles for tools' 'check' icons (Bartosz Dziewoński)
+* PopupWidget: don't apply header styles to footer (Roan Kattouw)
+* SelectFileWidget: Mute the drag and drop design (Ed Sanders)
+* Add colour to neutral state of MW frameless buttons (Ed Sanders)
+* Editing-advanced icon pack: Add 'calendar' (Bartosz Dziewoński)
+
+### Code
+* DropdownInputWidget: Allow users to pass config options to DropdownWidget (Alex Monk)
+* Theme: Add theme classes to $icon and $indicator only (Bartosz Dziewoński)
+* Use OO.ui.debounce() for Element#updateThemeClasses (Roan Kattouw)
+* Document browser-specific code with support comments (Timo Tijhof)
+* Update OOjs to v1.1.9 (James D. Forrester)
+* Fix file permissions (Southparkfan)
+* Fix inArray test in drag handler (Ed Sanders)
+* Prefer ES5 over jQuery methods (Bartosz Dziewoński)
+* build: Enable jscs rule 'requireSpacesInsideBrackets' and make pass (James D. Forrester)
+* build: Enable jscs rule 'requireVarDeclFirst' and make pass (James D. Forrester)
+* build: Make `quick-build` build the 'mixed' distribution (James D. Forrester)
+* build: Update jscs devDependency from 1.8.0 to 2.1.0 (James D. Forrester)
+* build: Update various devDependencies to latest (James D. Forrester)
+* core: Remove spurious "[description]" placeholder from documentation (Timo Tijhof)
+* demos, tests: Use es5-shim for IE8 compatibility (Bartosz Dziewoński)
+* phpcs.xml: Ignore JS demo files in the PHP distribution (James D. Forrester)
+* testsuitegenerator: Do not generate nonsensical tests for 'maxLength' (Bartosz Dziewoński)
+
+## v0.12.5 / 2015-08-18
+### Features
+* CapsuleMultiSelectWidget: Unbreak $overlay config option (Bartosz Dziewoński)
+* FloatingMenuSelectWidget: Introduce, based on TextInputMenuSelectWidget (Bartosz Dziewoński)
+* FieldLayout: Throw an error if no widget is provided (Prateek Saxena)
+* MessageDialog: Focus primary action button when the dialog opens (Prateek Saxena)
+
+### Styles
+* DropdownWidget: Remove additional vertical margin, for consistency (Bartosz Dziewoński)
+* FieldLayout: Correct rendering of multiline messages in MediaWiki theme (Bartosz Dziewoński)
+* Move base icon/indicator styles out of themes (Roan Kattouw)
+* MediaWiki theme: Correct styling of nested buttons (Bartosz Dziewoński)
+
+### Code
+* DropdownWidget: Add $overlay config option (Bartosz Dziewoński)
+* IconElement, IndicatorElement: Apply base styles to the right selector (Bartosz Dziewoński)
+* Add background-repeat: no-repeat; to default icon/indicator styles (Roan Kattouw)
+* Remove redundant background rules for icons/indicators (Roan Kattouw)
+* Revert "TextInputWidget: Update doc'ed requirements for validate function" (Prtksxna)
+* Don't directly use #addEventListener for compatibility with IE 8 (Bartosz Dziewoński)
+* demos: Add a demo of the $overlay config option of various widgets (Bartosz Dziewoński)
+
+## v0.12.4 / 2015-08-13
+### Styles
+* CapsuleMultiSelectWidget: Style tweaks (Ed Sanders)
+
+### Code
+* MenuSelectWidget: Call #updateItemVisibility in more cases (Bartosz Dziewoński)
+* PopupWidget: Remove 'focusout' handling again, limit to CapsuleMultiSelectWidget (Bartosz Dziewoński)
+
+## v0.12.3 / 2015-08-11
+### Deprecations
+* [DEPRECATING CHANGE] TextInputWidget: Add getValidity function, deprecate isValid (Prateek Saxena)
+
+### Features
+* Add OO.ui.isSafeUrl() to make sure url targets are safe client-side (Kunal Mehta)
+* CapsuleMultiSelectWidget: Introduce (Brad Jorsch)
+* FieldLayout: Allow displaying errors or notices next to fields (Bartosz Dziewoński)
+* HorizontalLayout: Introduce (Bartosz Dziewoński)
+* If ProcessDialog#fitLabel is called before dialog is open, defer (Ed Sanders)
+* Mixin TitledElement into DropdownInputWidget and FieldLayout (Florian)
+* Preserve dynamic state of widgets when infusing (Bartosz Dziewoński)
+* TextInputWidget: Don't forget to positionLabel() after it's been unset (Bartosz Dziewoński)
+
+### Styles
+* FieldLayout: Kill 'list-style-image' too for messages list (Bartosz Dziewoński)
+* PopupToolGroup: Handle popup position on very narrow screens (Ed Sanders)
+* ToggleSwitchWidget: Update according to spec (Prateek Saxena)
+* MediaWiki, Apex themes: Fix height of frameless toolbar button (Ed Sanders)
+* Apex theme: Correct disabled iconed button tool's text colour (Ed Sanders)
+* Revert "Dialog: Increase z-index of .oo-ui-dialog to 1000+" (Ed Sanders)
+
+### Code
+* ButtonOptionWidget: Make it more difficult to set an inappropriate 'tabIndex' (Bartosz Dziewoński)
+* TextInputWidget: Update doc'ed requirements for validate function (Prateek Saxena)
+* TextInputWidget: Use getValidity in setValidityFlag (Prateek Saxena)
+* Element: DWIM when repeatedly infusing the same node (Bartosz Dziewoński)
+* Element: Preserve 'classes' config option through infusion (Bartosz Dziewoński)
+* demo: Make compatible with IE 8 (Bartosz Dziewoński)
+* build: Exclude irrelevant files from Composer PHP package (Timo Tijhof)
+* build: Move phpcs config from composer.json to phpcs.xml (Timo Tijhof)
+* build: Output doxygen to "doc" for consistency with other PHP libraries (Kunal Mehta)
+* build: Switch svg2png to personal build which fixes long lines (James D. Forrester)
+* demos, tests: Use `.parent` instead of `.super` (Bartosz Dziewoński)
+* docparser: Add rudimentary error handling (Bartosz Dziewoński)
+* doxygen: Use default directory for HTML_OUTPUT (Kunal Mehta)
+* tests: Twist the time in comparison tests in a different manner (Bartosz Dziewoński)
+* testsuitegenerator: Output the number of generated test cases (Bartosz Dziewoński)
+
+## v0.12.2 / 2015-07-28
+
+### Styles
+* Dialog: Increase z-index of .oo-ui-dialog to 1000+ (Prateek Saxena)
+* MediaWiki theme: Create new 'accessibility' icon pack (Violetto)
+
+### Code
+* SelectWidget: Fix @mixins documentation (Roan Kattouw)
+* Update OOjs to v1.1.8 (James D. Forrester)
+
+## v0.12.1 / 2015-07-22
+
+### Features
+* PendingElement: Make this actually useful (Roan Kattouw)
+* TextInputWidget: Handle required: true better (Bartosz Dziewoński)
+* TextInputWidget: Handle type: 'search' better (Bartosz Dziewoński)
+
+### Styles
+* PanelLayout: Add some vertical margin when 'padded' and 'framed' (Bartosz Dziewoński)
+* MediaWiki, Apex themes: Add 'clear' indicator (Bartosz Dziewoński)
+* MediaWiki theme: Align colour of toolbar and dropdown buttons (Prateek Saxena)
+
+### Code
+* Window: Compute directionality only when needed (Roan Kattouw)
+* Standardise some common comments (Bartosz Dziewoński)
+* build: Add clean:demos task (Bartosz Dziewoński)
+* build: Add clean:tests task (Bartosz Dziewoński)
+* build: Have copyright header reference "OOjs UI" team (Kunal Mehta)
+* build: Use new grunt-tyops package rather than local original (James D. Forrester)
+* Gruntfile: Fix 'pgk' to 'pkg' and add to typos list (James D. Forrester)
+* package.json: Use proper SPDX license notation (Derk-Jan Hartman)
+
+## v0.12.0 / 2015-07-13
+### Breaking changes
+* [BREAKING CHANGE] SearchWidget: Remove deprecated event re-emission (Ed Sanders)
+
+### Features
+* Allow infusion of widgets in other namespaces (Kunal Mehta)
+* Only allow construction of classes that extend OO.ui.Element in infusion (Kunal Mehta)
+* ButtonInputWidget: Disable generating `<label>` elements (Bartosz Dziewoński)
+* FieldLayout: Support HTML help messages through HtmlSnippet (Kunal Mehta)
+* RadioSelectWidget: Improve accessibility (Bartosz Dziewoński)
+* SelectWidget: Call #chooseItem instead of #selectItem when enter is pressed (Ed Sanders)
+
+### Styles
+* MediaWiki, Apex themes: Add a 'notice' icon, same as the 'alert' indicator (James D. Forrester)
+* MediaWiki, Apex themes: Re-crush with svgo 0.5.3 (James D. Forrester)
+* PopupWidget: Use child selectors to apply rules correctly (Ed Sanders)
+* TextInputWidget: Use 'text' cursor for icon/indicator rather than 'pointer' (Bartosz Dziewoński)
+* Set Scots to use bold-b and italic-i (baud/italeec) (Ed Sanders)
+
+### Code
+* ClippableElement: Fix horizontal clipping in nested scrollable elements (Roan Kattouw)
+* ClippableElement: Only call reconsiderScrollbars() if we actually *stopped* clipping (Roan Kattouw)
+* Follow-up 3ddb3603: unbreak nesting of autosizing or labeled TextInputWidgets (Roan Kattouw)
+* InputWidget: Add additional `<span/>` only for subclasses that need it (Bartosz Dziewoński)
+* LookupElement: Disallow editing of readOnly TextInputWidgets (Bartosz Dziewoński)
+* History: Re-write into new B/D/F/S/C format and clean up (James D. Forrester)
+* build: Don't run phpcs over demos/php (Kunal Mehta)
+* build: Update development dependencies (James D. Forrester)
+* build: Update watch rules (Kunal Mehta)
+
+## v0.11.8 / 2015-07-07
+### Features
+* DropdownInputWidget, RadioSelectInputWidget: Consistently call `#cleanUpValue` (Bartosz Dziewoński)
+* TextInputWidget: Allow setting the HTML autocomplete attribute (Florian)
+* TextInputWidget: Support `rows` option when in multiline mode (Kunal Mehta)
+* Make scroll into view work in scrollable divs in Firefox (Roan Kattouw)
+
+### Styles
+* MediaWiki theme: Remove support for frameless primary buttons (Bartosz Dziewoński)
+
+### Code
+* Use at-ease instead of PHP's @ (Kunal Mehta)
+* Use composer's autoloader in exec:phpGenerateJSPHPForKarma (Kunal Mehta)
+* build: Don't lint demos/{dist,node_modules,vendor} (Kunal Mehta)
+* build: Build demos as part of `grunt build` too (Kunal Mehta)
+* build: Build demos as part of `grunt quick-build` (Kunal Mehta)
+* build: Only build test files (`build-tests` task) when going to run tests (Bartosz Dziewoński)
+* demos: Make self-contained in demos/ directory (Kunal Mehta)
+* tests: Provide better output when running infusion test under Karma (Bartosz Dziewoński)
+
+## v0.11.7 / 2015-07-01
+### Features
+* Element.php: Strip all namespaces from infused PHP widgets (Kunal Mehta)
+* OptionWidget: Explicitly set aria-selected to `false` on init (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add support for frameless primary buttons (Ed Sanders)
+* MediaWiki theme: Align and center the advanced icon (Roan Kattouw)
+* MediaWiki, Apex themes: Fix styling for frameless process dialog actions (Ed Sanders)
+
+### Code
+* Element.php: Add test case to verify class name in infused widgets (Kunal Mehta)
+* Element.php: Only variables may be passed by reference (Kunal Mehta)
+* Theme.php: Actually make abstract in PHP (Kunal Mehta)
+* Theme.php: Add missing doc comments (Kunal Mehta)
+* documentation: Use bold in comments instead of h4 (Ed Sanders)
+
+## v0.11.6 / 2015-06-23
+### Features
+* NumberInputWidget: Don't use `Math.sign()` (Brad Jorsch)
+* SelectWidget: Fix invalid escape sequence `\s` (Roan Kattouw)
+
+### Styles
+* DropdownWidget: Add white background in MediaWiki theme (Prateek Saxena)
+* SelectFileWidget: Add white background in MediaWiki theme (Prateek Saxena)
+* MediaWiki theme: Add constructive variants for star and unStar icons (Roan Kattouw)
+* MediaWiki theme: Add invert variant to all icons (Roan Kattouw)
+* MediaWiki theme: Add progressive variant to ongoingConversation icon (Stephane Bisson)
+
+### Code
+* Use `.parent` instead of `.super` (Stephane Bisson)
+* build: Updating development dependencies (Kunal Mehta)
+
+## v0.11.5 / 2015-06-16
+### Features
+* ButtonInputWidget: Render frameless button correctly (Bartosz Dziewoński)
+* ComboBoxWidget: Add a getter method for text inputs (Mr. Stradivarius)
+* FieldsetLayout: Make rule for disabled label color more precise (Bartosz Dziewoński)
+* MenuSelectWidget: Explain what the widget config option is for (Roan Kattouw)
+* RadioSelectInputWidget: Unbreak form submission in JS version (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add destructive variant to check icon (Matthew Flaschen)
+* MediaWiki, Apex themes: Add ongoingConversation icon (Matthew Flaschen)
+
+### Code
+* build: Configure jsonlint (Kunal Mehta)
+
+## v0.11.4 / 2015-06-09
+### Deprecations
+* [DEPRECATING CHANGE] Introduce oo.ui.mixin namespace for mixins, and put them src/mixins (C. Scott Ananian)
+
+### Features
+* ActionFieldLayout: Add PHP version (Bartosz Dziewoński)
+* ButtonWidget: Fix not having tabindex updated when enabled/disabled (Brad Jorsch)
+* ClippableElement: Fix behavior of clippables in nested scrollables (Bartosz Dziewoński)
+* ClippableElement: Fix behavior of long clippables (Bartosz Dziewoński)
+* Dialog: Label in aria terms (Prateek Saxena)
+* DropdownWidget: Adjust height to other widgets (Bartosz Dziewoński)
+* DropdownWidget: Blank widget when no item is selected (Brad Jorsch)
+* Element#reconsiderScrollbars: Preserve scroll position (Bartosz Dziewoński)
+* GroupElement: pass correct event name to disconnect() from aggregate() (Roan Kattouw)
+* NumberInputWidget: Create, for numeric input (Brad Jorsch)
+* NumberInputWidget: Use keydown, not keypress (Brad Jorsch)
+* ProcessDialog: Don't center the title label if there's not enough space (Bartosz Dziewoński)
+* RadioOptionWidget: Control focus more strictly (Bartosz Dziewoński)
+* RadioSelectInputWidget: Create (Bartosz Dziewoński)
+* SelectFileWidget: Create (Brad Jorsch)
+* SelectWidget: Listen to keypresses and jump to matching items (Brad Jorsch)
+* TextInputWidget: Adjust height to other widgets (Bartosz Dziewoński)
+* Widget: Add `#supportsSimpleLabel` static property to control `<label>` usage (Bartosz Dziewoński)
+* Window: Clear margins for actions in horizontal/vertical groups (Ed Sanders)
+* `OOUI\Tag`: Avoid 'Potentially unsafe "href" attribute value' exceptions for relative URLs (Bartosz Dziewoński)
+
+### Styles
+* MessageDialog: Remove unintentional action button margin (Bartosz Dziewoński)
+* styles: Change gradient mixin syntax to W3C standards' syntax (Volker E)
+* styles: Remove obsolete "-ms-linear-gradient" declaration (Volker E)
+* Apex theme: Use matching 'lock' and 'unLock' icons (Bartosz Dziewoński)
+* MediaWiki and Apex themes: Force background color of `<select>` to white (Ed Sanders)
+* MediaWiki and Apex themes: Re-crush SVG files (James D. Forrester)
+
+### Code
+* ActionFieldLayout: Dead code removal and cleanup (Bartosz Dziewoński)
+* BarToolGroup: Add description and example (Kirsten Menger-Anderson)
+* ButtonInputWidget and TextInputWidget: Document and enforce allowed types (Bartosz Dziewoński)
+* DropdownInputWidget: Tweak documentation (Bartosz Dziewoński)
+* InputWidget#getInputElement: Mark as `@protected`, not `@private` (Bartosz Dziewoński)
+* ListToolGroup: Add description and example (Kirsten Menger-Anderson)
+* MenuToolGroup: Add description, example and mark private method (Kirsten Menger-Anderson)
+* PendingElement: Add description (Kirsten Menger-Anderson)
+* PopupTool: Add description and example (Kirsten Menger-Anderson)
+* PopupToolGroup: Add description and mark protected methods (Kirsten Menger-Anderson)
+* Tool: Add description (Kirsten Menger-Anderson)
+* ToolFactory: Add description (Kirsten Menger-Anderson)
+* ToolGroup: Add description and mark protected methods (Kirsten Menger-Anderson)
+* ToolGroupFactory: Add description (Kirsten Menger-Anderson)
+* ToolGroupTool: Add description and example (Kirsten Menger-Anderson)
+* Toolbar: Add description (Kirsten Menger-Anderson)
+* `OOUI\Element::mixins`: Improve doc comment (Kunal Mehta)
+* `OOUI\Tag`: Add basic phpunit tests (Kunal Mehta)
+* build: Update MediaWiki codesniffer to 0.2.0 (Kunal Mehta)
+* build: Updating development dependencies (James D. Forrester)
+* demo: Add 'layout' variable to the consoles (Bartosz Dziewoński)
+* demo: Link JS and PHP demos (Bartosz Dziewoński)
+* docs: Update name of upstream OOjs project in jsduck documentation (C. Scott Ananian)
+* mailmap: Add an additional e-mail for Bartosz per request (James D. Forrester)
+* test: Use -p option to phpcs instead of -v (Kunal Mehta)
+
+## v0.11.3 / 2015-05-12
+### Features
+* BarToolGroup: Don't use "pointer" cursor for disabled tools in enabled toolgroups (Bartosz Dziewoński)
+* Tool: Support icon+label in bar tool groups (Bartosz Dziewoński)
+* ToolGroupTool: Correct opacity of disabled nested tool group handle (Bartosz Dziewoński)
+* ToolGroupTool: Synchronize inner ToolGroup disabledness state (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add a powerful default text color for tools (Trevor Parscal)
+* MediaWiki theme: Adjust quotes icon to match other icons (nirzar)
+* MediaWiki theme: Give names to some more toolbar colours (Bartosz Dziewoński)
+* MediaWiki theme: Provide all variants of the 'tag' icon (James D. Forrester)
+* MediaWiki theme: Rejigger some toolbar coloring (Bartosz Dziewoński)
+* MediaWiki theme: Remove box-shadow from nested toolbars (Bartosz Dziewoński)
+* MediaWiki theme: Remove unusued toolbar shadow (Trevor Parscal)
+* MediaWiki theme: Update button specification (nirzar)
+
+## v0.11.2 / 2015-05-11
+### Features
+* Don't select lookup items on initialize (Ed Sanders)
+* ListToolGroup, MenuToolGroup: Set accelTooltips = false (Bartosz Dziewoński)
+* PopupWidget: Add setAlignment (Moriel Schottlender)
+* Simplify default action prevention in buttons and forms (Bartosz Dziewoński)
+* TextInputWidget: Allow override of #setValidityFlag (Ed Sanders)
+* TextInputWidget: Use aria-required along with the required attribute (Prateek Saxena)
+
+### Styles
+* TabOptionWidget: Fix disabled styles to not react to hover/select (Ed Sanders)
+* Toolbar: Fix shadow styling (Bartosz Dziewoński)
+* Toolbar: Remove some useless code from the example (Bartosz Dziewoński)
+* Toolbar: Rework example and add 'menu' tool group example (Bartosz Dziewoński)
+* MediaWiki theme: Change highlight color for selected menu option (nirzar)
+* MediaWiki theme: Polish the toolbar design (nirzar)
+* MediaWiki theme: Remove accidentally duplicated styles for SelectWidget (Bartosz Dziewoński)
+
+### Code
+* SelectWidget: Mark as @abstract, which it is (Bartosz Dziewoński)
+* Toolbar: Move some tweaks from demo to actual implementation (Bartosz Dziewoński)
+
+## v0.11.1 / 2015-05-04
+### Features
+* Add IndexLayout (Trevor Parscal)
+* SelectWidget: Add #selectItemByData method (Moriel Schottlender)
+* TextInputWidget: Annotate input validation with aria-invalid (Prateek Saxena)
+* TextInputWidget: Don't set 'invalid' flag on first focus, even if invalid (Bartosz Dziewoński)
+* TextInputWidget: Support 'required' config option in PHP (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add 'destructive' variant to block icon (Moriel Schottlender)
+* MediaWiki theme: Better vertical alignment of 'search' icon (Ed Sanders)
+* MediaWiki theme: Tweak 'search' icon size (Ed Sanders)
+* MediaWiki theme: Use variable for transition time and easing function (Prateek Saxena)
+* MediaWiki theme: input: Use variable for transition time and easing function (Prateek Saxena)
+* MediaWiki theme: radio/checkbox: Use variable for transition time and easing function (Prateek Saxena)
+* MediaWiki, Apex themes: Switch icons: clear → cancel, closeInput → clear (Bartosz Dziewoński)
+* MediaWiki, Apex themes: Switch over 'magnifyingGlass' icon to be 'search' (James D. Forrester)
+
+### Code
+* CardLayout: Fix typo (Kirsten Menger-Anderson)
+* LabelElement: Document that label config option can take an HtmlSnippet (Roan Kattouw)
+* PopupButtonWidget: Update align config in example (Kirsten Menger-Anderson)
+* Remove GridLayout remnants (Bartosz Dziewoński)
+* TabOptionWidget: Change link to card layout (Kirsten Menger-Anderson)
+* build: Add clean:doc task (Bartosz Dziewoński)
+* build: Bump grunt-jscs to latest version (James D. Forrester)
+* core: Add OO.ui.debounce() utility (Roan Kattouw)
+* demo: Add icons with variants to icons demo (Bartosz Dziewoński)
+
+## v0.11.0 / 2015-04-29
+### Breaking changes
+* [BREAKING CHANGE] Do not set font-size: 0.8em anywhere in the library (Bartosz Dziewoński)
+
+### Deprecations
+* [DEPRECATING CHANGE] Create rtl-ready alignments in PopupWidget (Moriel Schottlender)
+
+### Features
+* MediaWiki theme: Adding variants to several icons (Moriel Schottlender)
+* TextInputWidget: Allow functions to be passed as 'validate' config option (Bartosz Dziewoński)
+
+### Styles
+* TextInputWidget: Styles for 'invalid' flag (Bartosz Dziewoński)
+
+### Code
+* Update OOjs to v1.1.7 (James D. Forrester)
+* Update jQuery from v1.11.1 to v1.11.3 (James D. Forrester)
+* build: Use jquery and oojs from npm instead of embedded lib (Timo Tijhof)
+
+## v0.10.1 / 2015-04-27
+### Features
+* Correct `tabindex` attribute setting (Bartosz Dziewoński)
+* Make toolbars keyboard-accessible (Bartosz Dziewoński)
+
+### Code
+* ToggleButtonWidget: Unbreak horizontal alignment (Bartosz Dziewoński)
+
+## v0.10.0 / 2015-04-22
+### Breaking changes
+* [BREAKING CHANGE] ButtonWidget: remove deprecated `nofollow` option alias (C. Scott Ananian)
+* [BREAKING CHANGE] Convert ToggleWidget from a mixin to an abstract class (Bartosz Dziewoński)
+* [BREAKING CHANGE] MenuLayout: Reimplement without inline styles (Bartosz Dziewoński)
+
+### Deprecations
+
+### Features
+* BarToolGroup: Allow tools with labels instead of icons (Bartosz Dziewoński)
+* BookletLayout: Find first focusable element and add focusable utility (Moriel Schottlender)
+* ButtonWidget: Remove href to make unclickable when disabled (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki, Apex themes: Add viewCompact, viewDetails, visionSimulator icons (Mun May Tee)
+
+### Code
+* ButtonInputWidget: Don't double-mixin FlaggedElement (Bartosz Dziewoński)
+* ButtonWidget: Remove pointless #isHyperlink property (Bartosz Dziewoński)
+* FormLayout: Better document how this works with InputWidgets (Bartosz Dziewoński)
+* MenuLayout: Add example (Kirsten Menger-Anderson)
+* MenuLayout: Fix initialization order (Bartosz Dziewoński)
+* PHP: More useful debugging information on unsafe tag attributes (Chad Horohoe)
+* SelectWidget#getTargetItem: Simplify (Ed Sanders)
+* Toolbar: Add example (Bartosz Dziewoński)
+* demo: Remove VisualEditor references from toolbar demo, use generic icons (Ed Sanders)
+* demo: Remove outline controls from outlined BookletLayout demo (Bartosz Dziewoński)
+* demo: Simplify ButtonGroupWidget and ButtonSelectWidget examples (Bartosz Dziewoński)
+
+## v0.9.8 / 2015-04-12
+### Features
+* BookletLayout: Allow focus on any item (Moriel Schottlender)
+
+### Styles
+* Apex theme: Correctly position popups in RTL; follows-up v0.9.5 (Moriel Schottlender)
+* Apex, MediaWiki themes: Correct or delete unused SVG files (James D. Forrester)
+
+### Code
+* Error: Add description (Kirsten Menger-Anderson)
+* ProcessDialog: Remove stray `this.$` from documentation code example (Roan Kattouw)
+* ProgressBarWidget: Remove spurious styles from CSS output (Bartosz Dziewoński)
+
+* build: Add explicit dependency upon grunt-cli (Kunal Mehta)
+* build: Move coverage output from "/dist/coverage" to "/coverage" (Timo Tijhof)
+* build: Run lint before build in grunt-test (Timo Tijhof)
+* colorize-svg: Generate language-specific rules for images even if equal to default ones (Bartosz Dziewoński)
+* colorize-svg: Sprinkle `/* @noflip */` on language-specific rules (Bartosz Dziewoński)
+* demo: Change html dir property when direction changes (Moriel Schottlender)
+
+## v0.9.7 / 2015-04-03
+### Code
+* build: Generate correct paths to fallback images (Bartosz Dziewoński)
+
+## v0.9.5 / 2015-04-02
+### Deprecations
+* [DEPRECATING CHANGE] Deprecate search widget event re-emission (Ed Sanders)
+
+### Features
+* Process: Allow rejecting with single Error (Matthew Flaschen)
+* Correctly position popups in RTL (Moriel Schottlender)
+
+### Styles
+* ButtonElement: Increase specificity of icon and indicator styles (Bartosz Dziewoński)
+* DecoratedOptionWidget: Fix opacity of icons/indicators when disabled (Ed Sanders)
+
+* Balance padding now that focus highlight is balanced (Ed Sanders)
+* Remove line height reset for windows (Ed Sanders)
+* Restore font family definitions to form elements (Ed Sanders)
+
+* Apex theme: Tweak `check.svg` syntax (Bartosz Dziewoński)
+* MediaWiki, Apex themes: Bring in remaining VisualEditor icons (James D. Forrester)
+* MediaWiki, Apex themes: Provide an RTL variant for the help icon (James D. Forrester)
+* MediaWiki theme: Add vertical spacing to RadioSelectWidget (Ed Sanders)
+* MediaWiki theme: Allow intention flags for non-buttons (Andrew Garrett)
+* MediaWiki theme: Fix icon opacity for disabled ButtonOptionWidgets (Bartosz Dziewoński)
+* MediaWiki theme: Revert "Syncing some button styles with MediaWiki UI" (Bartosz Dziewoński)
+* MediaWiki theme: Use checkbox icon per mockups (Bartosz Dziewoński)
+
+### Code
+* ActionFieldLayout: Add description and example (Kirsten Menger-Anderson)
+* BookletLayout: Add description and example (Kirsten Menger-Anderson)
+* IconWidget: Mix in FlaggedElement (Bartosz Dziewoński)
+* MenuLayout: Correct documentation (Bartosz Dziewoński)
+* OutlineOption: Add description (Kirsten Menger-Anderson)
+* PageLayout: Add description (Kirsten Menger-Anderson)
+* Process: Add description (Kirsten Menger-Anderson)
+* StackLayout: Add description and example (Kirsten Menger-Anderson)
+* Choose can't emit with a null item (Ed Sanders)
+* Refactor icon handling again (Bartosz Dziewoński)
+* build: Add a 'generated automatically' banner to demo.rtl.css (Bartosz Dziewoński)
+* build: Generate prettier task names for 'colorizeSvg' (Bartosz Dziewoński)
+* build: Have separate 'cssjanus' target for demo.rtl.css (Bartosz Dziewoński)
+* build: Make colorize-svg.js actually work more often (Bartosz Dziewoński)
+* build: Properly support LTR/RTL icon versions in colorize-svg.js (Bartosz Dziewoński)
+* build: Simplify 'fileExists' task configuration (Bartosz Dziewoński)
+* build: Support (poorly) per-language icon versions in colorize-svg.js (Bartosz Dziewoński)
+* build: Update grunt-banana-checker to v0.2.1 (James D. Forrester)
+
+## v0.9.4 / 2015-03-25
+### Breaking changes
+
+### Deprecations
+
+### Features
+* ProcessDialog#executeAction: Don't eat parent's return value (Roan Kattouw)
+* Compensate for loss of margin when opening modals (Ed Sanders)
+* Make outline controls' abilities configurable (Trevor Parscal)
+
+### Styles
+* MediaWiki theme: Reduce thickness of toolbar border (Ed Sanders)
+
+### Code
+* ButtonElement: Clarify description (Kirsten Menger-Anderson)
+* ButtonElement: Disable line wrapping on buttons (Ed Sanders)
+* FieldLayout: Clarify description and mark private methods (Kirsten Menger-Anderson)
+* FieldsetLayout: Add description and example (Kirsten Menger-Anderson)
+* FormLayout: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* Layout: Add description (Kirsten Menger-Anderson)
+* LookupElement: Add description and mark private and protected methods (Kirsten Menger-Anderson)
+* LookupElement: Fix typo in docs (Bartosz Dziewoński)
+* MenuLayout: Reorder styles (Bartosz Dziewoński)
+* MenuSectionOptionWidget: Add description and example (Kirsten Menger-Anderson)
+* PanelLayout: Add description and example (Kirsten Menger-Anderson)
+* SearchWidget: Add description and mark private methods (Kirsten Menger-Anderson)
+* TabIndexElement: Mark private method (Kirsten Menger-Anderson)
+
+## v0.9.3 / 2015-03-19
+### Features
+* LookupElement: Add optional config field for suggestions when empty (Matthew Flaschen)
+* ProcessDialog: send an array to showErrors in failed executeAction (Moriel Schottlender)
+
+### Code
+* Dialog: Fix links to static properties (Kirsten Menger-Anderson)
+* DraggableGroupElement: Clarify description and mark private methods (Kirsten Menger-Anderson)
+* Fix code style in `@examples` (Ed Sanders)
+* FlaggedElement: Add example and clarify description (Kirsten Menger-Anderson)
+* GroupElement: Clarify description (Kirsten Menger-Anderson)
+* IndicatorElement: Clarify description (Kirsten Menger-Anderson)
+* MenuSelectWidget: Clarify description (Kirsten Menger-Anderson)
+* TabIndexedElement: Clarify description (Kirsten Menger-Anderson)
+* TitledElement: Clarify description (Kirsten Menger-Anderson)
+* Widget: Clarify description (Kirsten Menger-Anderson)
+* Window: Clarify description of setDimensions method (Kirsten Menger-Anderson)
+* WindowManager: Clarify description and mark private methods (Kirsten Menger-Anderson)
+* Update OOjs to v1.1.6 (James D. Forrester)
+* Add .mailmap file (Roan Kattouw)
+* Add Kirsten to AUTHORS.txt (Roan Kattouw)
+* demo: Add one more toolbars demo (Bartosz Dziewoński)
+
+## v0.9.2 / 2015-03-12
+### Styles
+* Toolbar: Be less aggressive with `white-space: nowrap` (Bartosz Dziewoński)
+
+### Code
+* Window: Revert changes from 521061dd (Bartosz Dziewoński)
+
+## v0.9.1 / 2015-03-11
+### Features
+* PanelLayout: Add `framed` config option (Bartosz Dziewoński)
+* TextInputWidget: Use MutationObserver for #onElementAttach support (Bartosz Dziewoński)
+* Only prevent default for handled keypresses (Brad Jorsch)
+
+### Styles
+* Toolbar: Tighten whitespace on narrow displays (Bartosz Dziewoński)
+* MediaWiki theme: Add the progressive variant to the check icon (Prateek Saxena)
+* MediaWiki theme: Add warning variant to icon set (Mark Holmquist)
+* MediaWiki theme: Add "Wikicon" icons (Mun May Tee)
+* MediaWiki theme: Synchronise button styles between OOJS and MW (nirzar)
+* MediaWiki theme: Syncing some button styles with MediaWiki UI (kaldari)
+* MediaWiki theme: textInputWidget: Update focus state (Prateek Saxena)
+
+### Code
+* ActionSet: Add description for events and clarify method descriptions (Kirsten Menger-Anderson)
+* ActionSet: Clarify description (Kirsten Menger-Anderson)
+* ActionWidget: Clarify description and mark private method (Kirsten Menger-Anderson)
+* ActionWidget: Fix bad copy-paste in documentation (Bartosz Dziewoński)
+* ButtonElement: Use #setButtonElement correctly (Bartosz Dziewoński)
+* ButtonInputWidget: Clarify description of configs and methods (Kirsten Menger-Anderson)
+* Dialog: Mark private methods and add description of methods and configs (Kirsten Menger-Anderson)
+* InputWidget: Clarify description (Kirsten Menger-Anderson)
+* MessageDialog: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* OutlineControlsWidget: Add description (Kirsten Menger-Anderson)
+* OutlineSelectWidget: Add description (Kirsten Menger-Anderson)
+* ProcessDialog: Add description and example and mark private methods (Kirsten Menger-Anderson)
+* TextInputMenuSelectWidget: Add description and mark private methods (Kirsten Menger-Anderson)
+* TextInputWidget: Adjust size and label on first focus, too (Bartosz Dziewoński)
+* Window: Clarify descriptions of methods and configs (Kirsten Menger-Anderson)
+* WindowManager: Documentation typo (Ed Sanders)
+* Icon width should only be applied if there is an icon (Moriel Schottlender)
+* Remove half-baked touch event handling (Bartosz Dziewoński)
+* Remove remnants of window isolation (Bartosz Dziewoński)
+* AUTHORS: Add Derk-Jan Hartman (Derk-Jan Hartman)
+* build: Implement basic image flipping support in colorize-svg (Bartosz Dziewoński)
+* build: Move pre/post 'doc' task into package.json (Timo Tijhof)
+* build: Remove obsolete 'build' task from grunt-doc (Timo Tijhof)
+* build: Set 'generateExactDuplicates: true' for CSSJanus (Bartosz Dziewoński)
+* demo: Fix typo in toolbars demo (Bartosz Dziewoński)
+* demo: Load styles before building demo widgets (not asynchronously) (Bartosz Dziewoński)
+* demo: Simplify `@media` styles (Bartosz Dziewoński)
+* demo: Use popup with head in the toolbars demo (Bartosz Dziewoński)
+* jsduck: Add MouseEvent and KeyboardEvent to externals (Timo Tijhof)
+* jsduck: Set --processes=0 to fix warnings-exit-nonzero (Timo Tijhof)
+* package.json: Bump grunt-svg2png to 0.2.7 (Bartosz Dziewoński)
+
+## v0.9.0 / 2015-03-04
+### Breaking changes
+* [BREAKING CHANGE] Remove innerOverlay (Ed Sanders)
+* [BREAKING CHANGE] TextInputWidget: Remove `icon` and `indicator` events (Bartosz Dziewoński)
+* [BREAKING CHANGE] Remove deprecated LookupInputWidget (Bartosz Dziewoński)
+* [BREAKING CHANGE] Remove deprecated GridLayout (Bartosz Dziewoński)
+
+### Features
+* Move `OO.ui.infuse` to `OO.ui.Element.static.infuse`. (C. Scott Ananian)
+* Fake toolbar group nesting (Bartosz Dziewoński)
+* Infer retry button action flags from symbolic name (Trevor Parscal)
+* InputWidget: Focus checkboxes and radios, too, when the label is clicked (Bartosz Dziewoński)
+* ProcessDialog: Dismiss errors on teardown (Moriel Schottlender)
+
+### Styles
+* Make icon and indicator container sizes consistent (Ed Sanders)
+* Restore previous toolbar items margins and padding (Bartosz Dziewoński)
+* Use the correct color for gray buttons (Prateek Saxena)
+
+### Code
+* CheckboxInputWidget: Add description and example (Kirsten Menger-Anderson)
+* ComboBoxWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* DecoratedOptionWidget: Add description and example (Kirsten Menger-Anderson)
+* DropdownInputWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* FieldLayout: Fix display of documentation's bulleted list (Kirsten Menger-Anderson)
+* GroupWidget and ItemWidget: Mark `private` (Kirsten Menger-Anderson)
+* IndicatorWidget: Add description and example (Kirsten Menger-Anderson)
+* LabelElement: Don't call constructor twice for ActionFieldLayouts (Roan Kattouw)
+* LabelWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* PopupElement: Add description (Kirsten Menger-Anderson)
+* PopupTool: Tool constructor takes a toolGroup, not a toolbar (Bartosz Dziewoński)
+* PopupWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* PopupWidget: Add keydown listener and hide popup on ESC (Prateek Saxena)
+* ProgressBar: Add description and example (Kirsten Menger-Anderson)
+* RadioInputWidget: Add description and example (Kirsten Menger-Anderson)
+* SelectWidget: Add example and link to decorated option widget (Kirsten Menger-Anderson)
+* SelectWidget: Marked protected methods and clarified choose/press descriptions (Kirsten Menger-Anderson)
+* TextInputWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* ToggleButtonWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* ToggleSwitchWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* ToggleWidget: Add description (Kirsten Menger-Anderson)
+* Fix invalid use of border shorthand syntax (Timo Tijhof)
+* Only modify body class when first/last window opens/closes (Ed Sanders)
+* Use only two variables each for each semantic color (Prateek Saxena)
+* build: Add disconnect tolerance to karma config (James D. Forrester)
+* build: Remove footer override from jsduck (Timo Tijhof)
+* demo: Add PopupTool to toolbar demo (Bartosz Dziewoński)
+* demo: Call Toolbar#initialize in toolbar demo (Bartosz Dziewoński)
+* tests: Add infusion tests (Bartosz Dziewoński)
+* tests: Run JS/PHP tests for widgets with required parameters, too (Bartosz Dziewoński)
+
+## v0.8.3 / 2015-02-26
+### Features
+* Revert "Unbreak form submission in JavaScript" (Bartosz Dziewoński)
+
+## v0.8.2 / 2015-02-26
+### Features
+* PHP TitledElement: Actually set $this->title (Bartosz Dziewoński)
+* PHP PanelLayout: Fix getConfig() for `expanded` config option (Bartosz Dziewoński)
+
+### Code
+* testsuitegenerator: Exclude 'text' parameter from tests, like 'content' (Bartosz Dziewoński)
+* WindowManager: Don't pass `this` to window factory method (Bartosz Dziewoński)
+
+## v0.8.1 / 2015-02-25
+### Deprecations
+* [DEPRECATING CHANGE] Rename setPosition to setLabelPosition (Ed Sanders)
+
+### Features
+* Allow passing positional parameters inside the config object (Bartosz Dziewoński)
+* ComboBox: Use combobox role (Derk-Jan Hartman)
+* Element.php: Add "data" property (C. Scott Ananian)
+* Element.php: Add "text" configuration option (C. Scott Ananian)
+* Element: Add `content` config option, matching PHP side. (C. Scott Ananian)
+* FormLayout: Allow adding child layouts via config (Bartosz Dziewoński)
+* Implement OO.ui.infuse to reconstitute PHP widgets in client-side JS (C. Scott Ananian)
+* Serialize PHP widget state into data-ooui attribute (C. Scott Ananian)
+* TextInputWidget: Fix appearance of icons and labels when disabled (Ed Sanders)
+* Unbreak form submission in JavaScript (Bartosz Dziewoński)
+
+### Styles
+* Set proper spacing between interleaved FieldsetLayouts and FormLayouts (Bartosz Dziewoński)
+* MediaWiki theme: Drop unnecessary pseudo-element of CheckboxInputWidget (Timo Tijhof)
+* MediaWiki theme: Drop unnecessary pseudo-element of RadioInputWidget (Timo Tijhof)
+* MediaWiki theme: Simplify spacing of checkboxes/radios in FieldLayouts (Bartosz Dziewoński)
+
+### Code
+* ButtonOptionWidget: Add description (Kirsten Menger-Anderson)
+* ButtonSelectWidget: Add description and example (Kirsten Menger-Anderson)
+* DraggableElement: Mark private methods and add description to events (Kirsten Menger-Anderson)
+* Element.php: Tweak docs (Bartosz Dziewoński)
+* Element: Add description for configs and static property (Kirsten Menger-Anderson)
+* Error: Fix function name (Bartosz Dziewoński)
+* Fix typo: contian → contain (Bartosz Dziewoński)
+* FlaggedElement: Add description of event and config option (Kirsten Menger-Anderson)
+* Follow-up bade83bfdfc: actually remove ../ (Roan Kattouw)
+* IconElement: Add description for config options (Kirsten Menger-Anderson)
+* IconElement: Add description of methods (Kirsten Menger-Anderson)
+* IndicatorElement: Add description for configs and static properties (Kirsten Menger-Anderson)
+* LabelElement: Add description, config description, static property description (Kirsten Menger-Anderson)
+* MenuOptionWidget: Add description (Kirsten Menger-Anderson)
+* MenuSelectWidget: Add description and mark protected method (Kirsten Menger-Anderson)
+* Move toggle() from Widget to Element (Moriel Schottlender)
+* OptionWidget: Add description and descriptions of methods (Kirsten Menger-Anderson)
+* PopupButtonWidget: Add description and example and mark private method (Kirsten Menger-Anderson)
+* Prefer OO.isPlainObject to $.isPlainObject (Bartosz Dziewoński)
+* RadioOptionWidget: Add description (Kirsten Menger-Anderson)
+* RadioOptionWidget: Make disabling single options work (Bartosz Dziewoński)
+* RadioSelectWidget: Add description and example (Kirsten Menger-Anderson)
+* Remove '$: this.$' from code examples (Bartosz Dziewoński)
+* Remove loop length check (Ed Sanders)
+* SelectWidget: Add description for config, methods, events (Kirsten Menger-Anderson)
+* TabIndexelement: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* TitledElement: Add description and config and static descriptions (Kirsten Menger-Anderson)
+* Update OOjs to v1.1.5 (James D. Forrester)
+* Work around Safari 8 mis-rendering checkboxes in SVG-only distribution (Bartosz Dziewoński)
+* build: Give docparser.rb Ruby 1.9.3 compatibility (Bartosz Dziewoński)
+* build: Include 'lib' and 'dist' in jsduck output (Timo Tijhof)
+* build: Teach docparser about `@member`, `@see`, and PHP pass-by-reference (`&$foo`). (C. Scott Ananian)
+* build: Unbreak docparser.rb (Bartosz Dziewoński)
+* build: Use grunt-contrib-copy instead of custom 'copy' task (Timo Tijhof)
+* composer.json: Add description field (Kunal Mehta)
+* demo: Add disabled RadioInputWidget to demo (Bartosz Dziewoński)
+* tests: Add "composer test" command to lint PHP files and run phpcs (Kunal Mehta)
+* tests: Reduce timeout in Process test from 100 to 10 (Timo Tijhof)
+* tests: Run JS/PHP comparison tests using karma (Bartosz Dziewoński)
+
+## v0.8.0 / 2015-02-18
+### Breaking changes
+* [BREAKING CHANGE] Make default distribution provide SVG with PNG fallback (Bartosz Dziewoński)
+
+### Deprecations
+* [DEPRECATING CHANGE] ButtonWidget: Rename nofollow config option to noFollow (C. Scott Ananian)
+* [DEPRECATING CHANGE] TextInputWidget: Deprecate `icon` and `indicator` events (Bartosz Dziewoński)
+
+### Features
+* TabIndexedElement: Allow tabIndex property to be null (C. Scott Ananian)
+* TextInputWidget: Allow maxLength of 0 in JS (matching PHP) (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add focus state for frameless button (Prateek Saxena)
+* MediaWiki theme: Fix border width for frameless buttons' focus state (Prateek Saxena)
+* MediaWiki theme: Resynchronize PHP with JS (Bartosz Dziewoński)
+* MediaWiki theme: Use white icons for disabled buttons (Bartosz Dziewoński)
+
+### Code
+* ActionSet: Add `@private` to onActionChange method (Kirsten Menger-Anderson)
+* ActionSet: Add description and example (Kirsten Menger-Anderson)
+* ActionSet: Add description for specialFlags property (Kirsten Menger-Anderson)
+* ActionWidget: Add description (Kirsten Menger-Anderson)
+* Add missing ButtonInputWidget.less and corresponding mixin (Bartosz Dziewoński)
+* ButtonElement: Add description (Kirsten Menger-Anderson)
+* ButtonElement: add `protected` to event handlers (Kirsten Menger-Anderson)
+* ButtonGroupWidget: Add description and example (Kirsten Menger-Anderson)
+* ButtonInputWidget: Add description and example (Kirsten Menger-Anderson)
+* ButtonWidget: Add example and link (Kirsten Menger-Anderson)
+* Dialog: Add description and example (Kirsten Menger-Anderson)
+* DraggableElement: Add description (Kirsten Menger-Anderson)
+* DraggableGroupElement: Add description (Kirsten Menger-Anderson)
+* DropdownWidget: Add `@private` to private methods (Kirsten Menger-Anderson)
+* DropdownWidget: Add description and example (Kirsten Menger-Anderson)
+* DropdownWidget: Simplify redundant code (Bartosz Dziewoński)
+* Element: Add description (Kirsten Menger-Anderson)
+* FieldLayout: Add description (Kirsten Menger-Anderson)
+* FieldLayout: Clean up and remove lies (Bartosz Dziewoński)
+* FlaggedElement: Add description (Kirsten Menger-Anderson)
+* Follow-up 6a6bb90ab: Update CSS file path in eg-iframe.html (Roan Kattouw)
+* Follow-up c762da42: fix ProcessDialog error handling (Roan Kattouw)
+* GroupElement: Add description (Kirsten Menger-Anderson)
+* IconElement: Add description (Kirsten Menger-Anderson)
+* IconElement: Add description and fix display of static properties (Kirsten Menger-Anderson)
+* IconWidget: Add description and example (Kirsten Menger-Anderson)
+* IndicatorElement: Add description (Kirsten Menger-Anderson)
+* InputWidget: Add description (Kirsten Menger-Anderson)
+* PHP: Remove redundant documentation for getInputElement() (Bartosz Dziewoński)
+* Refactor keyboard accessibility of SelectWidgets (Bartosz Dziewoński)
+* SelectWidget: Add description (Kirsten Menger-Anderson)
+* Some documentation tweaks (Bartosz Dziewoński)
+* TextInputWidget: Add missing LabelElement mixin documentation (Ed Sanders)
+* TextInputWidget: Don't add label position classes when there's no label (Bartosz Dziewoński)
+* TextInputWidget: Hide mixin components when unused (Ed Sanders)
+* TextInputWidget: Only put $label in the DOM if needed (Bartosz Dziewoński)
+* TextInputWidget: Use margins for moving the label (Ed Sanders)
+* Update PHP widgets for accessibility-related changes in JS widgets (Bartosz Dziewoński)
+* Use Array.isArray instead of $.isArray (C. Scott Ananian)
+* Various fixes to the PHP implementation (C. Scott Ananian)
+* Widget: Add description (Kirsten Menger-Anderson)
+* Window: Add description (Kirsten Menger-Anderson)
+* WindowManager: Add description (Kirsten Menger-Anderson)
+* build: Pass RuboCop, customize settings (Bartosz Dziewoński)
+* demo: Add horizontal alignment test (Bartosz Dziewoński)
+* PHP demo: Correct path to CSS files (Bartosz Dziewoński)
+* tests: Update JS/PHP comparison test suite (Bartosz Dziewoński)
+* docparser: Add support for `protected` methods (Bartosz Dziewoński)
+* docs: Make `@example` documentation tag work (Roan Kattouw)
+* tests: Fix the check for properties (Bartosz Dziewoński)
+* testsuitegenerator: Only test every pair of config options rather than every triple (Bartosz Dziewoński)
+
+## v0.7.0 / 2015-02-11
+### Breaking changes
+* [BREAKING CHANGE] Remove window isolation (Trevor Parscal)
+
+### Deprecations
+* [DEPRECATING CHANGE] GridLayout should no longer be used, instead use MenuLayout (Bartosz Dziewoński)
+
+### Features
+* ButtonWidget: Add `nofollow` option (C. Scott Ananian)
+* ButtonWidget: Better handle non-string parameters in setHref/setTarget (C. Scott Ananian)
+* PopupWidget: Set $clippable only once, correctly (Bartosz Dziewoński)
+* SelectWidget: `listbox` wrapper role, `aria-selected` state on contents (Derk-Jan Hartman)
+* TabIndexedElement: Actually allow tabIndex of -1 (Bartosz Dziewoński)
+* TextInputWidget: Add required attribute on the basis of required config (Prateek Saxena)
+* TextInputWidget: Use aria-hidden for extra autosize textarea (Prateek Saxena)
+* ToggleSwitchWidget: Accessibility improvements (Bartosz Dziewoński)
+
+### Styles
+* FieldsetLayout: Tweak positioning of help icon (Bartosz Dziewoński)
+* Fade in window frames separately from window overlays (Ed Sanders)
+* MediaWiki theme: Consistent toggle button `active` state (Bartosz Dziewoński)
+* MediaWiki theme: Correct flagged primary button text color when pressed (Bartosz Dziewoński)
+* MediaWiki theme: Fix background color for disabled buttons (Prateek Saxena)
+* MediaWiki theme: Fix non-clickability of radios and checkboxes (Bartosz Dziewoński)
+* MediaWiki theme: Rename `@active` to `@pressed` in button mixins (Prateek Saxena)
+* MediaWiki theme: Rename `@highlight` to `@active` (Prateek Saxena)
+* MediaWiki theme: Rename active-* variables to pressed-* (Prateek Saxena)
+* MediaWiki theme: Use darker color for frameless buttons (Prateek Saxena)
+* MediaWiki theme: Use distribution's image type for backgrounds (Bartosz Dziewoński)
+
+### Code
+* ButtonWidget: Add documentation (Kirsten Menger-Anderson)
+* {Checkbox,Radio}InputWidget: Add missing configuration initialization (Bartosz Dziewoński)
+* DraggableGroupElement: Cleanup unreachable code (Moriel Schottlender)
+* DraggableGroupElement: Make sure it supports button widgets (Moriel Schottlender)
+* DraggableGroupElement: Unset dragged item when dropped (Moriel Schottlender)
+* Delete unused src/themes/apex/{raster,vector}.less (Bartosz Dziewoński)
+* DropdownInputWidget: Fix undefined variable in PHP (Bartosz Dziewoński)
+* DropdownWidget, ComboBoxWidget: Make keyboard-accessible (Bartosz Dziewoński)
+* Fix initialisation of window visible (Ed Sanders)
+* Fix text input auto-height calculation (Ed Sanders)
+* ListToolGroup: Remove hack for jQuery's .show()/.hide() (Bartosz Dziewoński)
+* MenuSelectWidget: Codify current behavior of Tab closing the menu (Bartosz Dziewoński)
+* MenuSelectWidget: Don't clobber other events when unbinding (Bartosz Dziewoński)
+* MenuSelectWidget: Remove dead code (Bartosz Dziewoński)
+* OptionWidgets: Make better use of `scrollIntoViewOnSelect` (Bartosz Dziewoński)
+* PopupElement: Correct documentation (Bartosz Dziewoński)
+* RadioOptionWidget: Make it a `<label />` (Bartosz Dziewoński)
+* Refactor clickability of buttons (Bartosz Dziewoński)
+* Remove usage of `this.$` and `config.$` (Trevor Parscal)
+* Stop treating ApexTheme class unfairly and make it proper (Bartosz Dziewoński)
+* TextInputMenuSelectWidget: Correct documentation (Bartosz Dziewoński)
+* build: Bump various devDependencies (James D. Forrester)
+* demo: Add button style showcase from PHP demo (Bartosz Dziewoński)
+* demo: Reorder widgets into somewhat logical groupings (Bartosz Dziewoński)
+* demo: Stop inline consoles from generating white space (Bartosz Dziewoński)
+* demo: Use properties instead of attributes for `<link>` (Timo Tijhof)
+* PHP demo: Add Vector/Raster and MediaWiki/Apex controls (Bartosz Dziewoński)
+* PHP demo: Just echo the autoload error message, don't trigger_error() (Bartosz Dziewoński)
+* PHP demo: Resynchronize with JS demo (Bartosz Dziewoński)
+* History: Fix date typos (James D. Forrester)
+* tests: Just echo the autoload error message, don't trigger_error() (Bartosz Dziewoński)
+* tools.less: Use distribution's image type and path for background (Prateek Saxena)
+
+## v0.6.6 / 2015-02-04
+### Features
+* BookletLayout#toggleOutline: Fix to use MenuLayout method (Ed Sanders)
+* Remove disabled elements from keyboard navigation flow (Derk-Jan Hartman)
+* TextInputWidget: Mostly revert "Don't try adjusting size when detached" (Bartosz Dziewoński)
+* Use CSS overriding trick to support RTL in menu layouts (Ed Sanders)
+
+### Styles
+* Use standard border colours for progress bars (Ed Sanders)
+
+### Code
+* Use css class instead of jQuery .show()/hide()/toggle() (Moriel Schottlender)
+* build: Use karma to v0.12.31 (Timo Tijhof)
+
+## v0.6.5 / 2015-02-01
+### Code
+* ButtonElement: Unbreak 'pressed' state (Bartosz Dziewoński)
+* Make BookletLayout inherit from MenuLayout instead of embedding a GridLayout (Ed Sanders)
+
+## v0.6.4 / 2015-01-30
+### Features
+* Add inline labels to text widgets (Ed Sanders)
+* BookletLayout: Make sure there is a page before focusing (Moriel Schottlender)
+* DropdownInputWidget: Introduce (Bartosz Dziewoński)
+* InputWidget: Resynchronize our internal .value with DOM .value in #getValue (eranroz)
+* Seriously work around the Chromium scrollbar bug for good this time (Bartosz Dziewoński)
+* TabIndexedElement: Introduce and use (Bartosz Dziewoński)
+* TextInputWidget: Accept `maxLength` configuration option (Bartosz Dziewoński)
+* MenuLayout: Introduce (Ed Sanders)
+* Window#updateSize: Add simpler API (Ed Sanders)
+
+### Styles
+* ActionFieldLayout: Add `nowrap` to the button (Moriel Schottlender)
+* FieldsetLayout: Add help icon (Moriel Schottlender)
+* Fix opening/closing animation on windows (Roan Kattouw)
+* OptionWidget: Unbreak 'pressed' state (Bartosz Dziewoński)
+* Provide default margins for buttons and other widgets (Bartosz Dziewoński)
+* MenuSelectWidget and OptionWidget: Remove the 'flash' feature (Bartosz Dziewoński)
+* MediaWiki theme: Adjust ButtonSelectWidget, ButtonGroupWidget highlights (Prateek Saxena)
+* MediaWiki theme: Adjust MenuOptionWidget selected state (Bartosz Dziewoński)
+* MediaWiki theme: Fix background issues with disabled buttons (Roan Kattouw)
+* MediaWiki theme: Reduce size of checkboxes and radio buttons by 20% (Ed Sanders)
+* MediaWiki theme: Remove SearchWidget's border now dialogs have outline (Ed Sanders)
+* MediaWiki theme: Tweak some more border-radii (Bartosz Dziewoński)
+* MediaWiki theme: Unbreak disabled buttons (Bartosz Dziewoński)
+
+### Code
+* ButtonOptionWidget: Add the TabIndexedElement mixin (Derk-Jan Hartman)
+* InputWidget: Clarify documentation of #getInputElement (Bartosz Dziewoński)
+* PopupButtonWidget: Set aria-haspopup to true (Prateek Saxena)
+* Remove labelPosition check (Ed Sanders)
+* Set input direction in html prop rather than css rule (Moriel Schottlender)
+* TextInputWidget: Don't try adjusting size when detached (Bartosz Dziewoński)
+* TextInputWidget: Remove superfluous role=textbox (Derk-Jan Hartman)
+* ToggleButtonWidget: Set aria-pressed when changing value (Derk-Jan Hartman)
+* ToggleWidget: Use aria-checked (Prateek Saxena)
+* Twiddle things (Ed Sanders)
+* Update OOjs to v1.1.4 and switch to the jQuery-optimised version (James D. Forrester)
+* Widget: Set aria-disabled too in #setDisabled (Derk-Jan Hartman)
+* AUTHORS: Update for the last six months' work (James D. Forrester)
+* build: Bump devDependencies and fix up (James D. Forrester)
+* demo: Have multiline text in multiline widgets (Bartosz Dziewoński)
+* demo: Remove nonexistent 'align' config option for a DropdownWidget (Bartosz Dziewoński)
+
+## v0.6.3 / 2015-01-14
+### Deprecations
+* [DEPRECATING CHANGE] LookupInputWidget should no longer be used, instead use LookupElement
+
+### Features
+* Add an ActionFieldLayout (Moriel Schottlender)
+* Replace old&busted LookupInputWidget with new&hot LookupElement (Bartosz Dziewoński)
+
+### Styles
+* dialog: Provide a 'larger' size for things for which 'large' isn't enough (James D. Forrester)
+* Synchronize ComboBoxWidget and DropdownWidget styles (Bartosz Dziewoński)
+* MediaWiki theme: Adjust toolbar popups' border and shadows (Bartosz Dziewoński)
+* MediaWiki theme: Don't use 'box-shadow' to produce thin grey lines in dialogs (Bartosz Dziewoński)
+
+### Code
+* Toolbar: Update #initialize docs (Bartosz Dziewoński)
+* demo: Switch the default theme from 'Apex' to 'MediaWiki' (Ricordisamoa)
+
+## v0.6.2 / 2015-01-09
+### Features
+* Clear windows when destroying window manager (Ed Sanders)
+* Element: Add support for 'id' config option (Bartosz Dziewoński)
+* TextInputWidget: Add support for 'autofocus' config option (Bartosz Dziewoński)
+
+### Styles
+* Add 'lock' icon (Trevor Parscal)
+* Make `@anchor-size` a LESS variable and calculate borders from it (Ed Sanders)
+* MediaWiki theme: Slightly reduce size of indicator arrows (Ed Sanders)
+* MediaWiki theme: Remove text-shadow on button (Prateek Saxena)
+* MediaWiki theme: Fix focus state for buttons (Prateek Saxena)
+* MediaWiki theme: Add state change transition to checkbox (Prateek Saxena)
+* MediaWiki theme: Fix disabled state of buttons (Prateek Saxena)
+* MediaWiki theme: Fix overlap between hover and active states (Prateek Saxena)
+
+### Code
+* Don't test abstract classes (Bartosz Dziewoński)
+* PHP LabelElement: Actually allow non-plaintext labels (Bartosz Dziewoński)
+* Synchronize `@abstract` class annotations between PHP and JS (Bartosz Dziewoński)
+* WindowManager#removeWindows: Documentation fix (Ed Sanders)
+* tests: Don't overwrite 'id' attribute (Bartosz Dziewoński)
+* testsuitegenerator.rb: Handle inheritance chains (Bartosz Dziewoński)
+
+## v0.6.1 / 2015-01-05
+### Styles
+* FieldsetLayout: Shrink size of label and bump the weight to compensate (James D. Forrester)
+
+### Code
+* Remove use of `Math.round()` for offset and position pixel values (Bartosz Dziewoński)
+* ButtonElement: Inherit all 'font' styles, not only 'font-family' (Bartosz Dziewoński)
+* IndicatorElement: Fix 'indicatorTitle' config option (Bartosz Dziewoński)
+* Error: Unmark as `@abstract` (Bartosz Dziewoński)
+* JSPHP-suite.json: Update (Bartosz Dziewoński)
+* build: Update various devDependencies (James D. Forrester)
+* readme: Update badges (Timo Tijhof)
+* readme: No need to put the same heading in twice (James D. Forrester)
+
+## v0.6.0 / 2014-12-16
+### Breaking changes
+* [BREAKING CHANGE] PopupToolGroup and friends: Pay off technical debt (Bartosz Dziewoński)
+
+### Features
+* Prevent parent window scroll in modal mode using overflow hidden (Ed Sanders)
+* ClippableElement: Handle clipping with left edge (Bartosz Dziewoński)
+
+### Styles
+* ButtonGroupWidget: Remove weird margin-bottom: -1px; from theme styles (Bartosz Dziewoński)
+* MediaWiki theme: RadioInputWidget tweaks (Bartosz Dziewoński)
+
+### Code
+* Sprinkle some child selectors around in BookletLayout styles (Roan Kattouw)
+
+## v0.5.0 / 2014-12-12
+### Breaking changes
+* [BREAKING CHANGE] FieldLayout: Handle 'inline' alignment better (Bartosz Dziewoński)
+* [BREAKING CHANGE] Split primary flag into primary and progressive (Trevor Parscal)
+* [BREAKING CHANGE] CheckboxInputWidget: Allow setting HTML 'value' attribute (Bartosz Dziewoński)
+
+### Features
+* Element.getClosestScrollableContainer: Use 'body' or 'documentElement' based on browser (Prateek Saxena)
+* Give non-isolated windows a tabIndex for selection holding (Ed Sanders)
+* Call .off() correctly in setButtonElement() (Roan Kattouw)
+
+### Styles
+* FieldLayout: In styles, don't assume that label is given (Bartosz Dziewoński)
+* PopupWidget: Remove box-shadow rule that generates invisible shadow (Bartosz Dziewoński)
+* TextInputWidget: Set vertical-align: middle, like buttons (Bartosz Dziewoński)
+* MediaWiki theme: Add hover state to listToolGroup (Trevor Parscal)
+* MediaWiki theme: Add radio buttons (Prateek Saxena)
+* MediaWiki theme: Add state transition to radio buttons (Prateek Saxena)
+* MediaWiki theme: Add thematic border to the bottom of toolbars (Bartosz Dziewoński)
+* MediaWiki theme: Copy .theme-oo-ui-outline{Controls,Option}Widget from Apex (Bartosz Dziewoński)
+* MediaWiki theme: Extract @active-color variable (Bartosz Dziewoński)
+* MediaWiki theme: Improve search widget styling (Trevor Parscal)
+* MediaWiki theme: Make button sizes match Apex (Trevor Parscal)
+* MediaWiki theme: Use gray instead of blue for select and highlight (Trevor Parscal)
+* MediaWiki theme: checkbox: Fix states according to spec (Prateek Saxena)
+
+### Code
+* Account for `<html>` rather than `<body>` being the scrollable root in Chrome (Bartosz Dziewoński)
+* ClippableElement: 7 is a better number than 10 (Bartosz Dziewoński)
+* Don't set line-height of unset button labels (Bartosz Dziewoński)
+* FieldLayout: Synchronise PHP with JS (Bartosz Dziewoński)
+* FieldLayout: Use `<label>` for this.$body, not this.$element (Bartosz Dziewoński)
+* Fix primary button description text (Niklas Laxström)
+* GridLayout: Don't round to 1% (Bartosz Dziewoński)
+* Kill the escape keydown event after handling a window close (Ed Sanders)
+* RadioInputWidget: Remove documentation lies (Bartosz Dziewoński)
+* Temporarily remove position:absolute on body when resizing (Ed Sanders)
+* build: Use String#slice instead of discouraged String#substr (Timo Tijhof)
+* testsuitegenerator: Actually filter out non-unique combinations (Bartosz Dziewoński)
+* README.md: Drop localisation update auto-commits from release notes (James D. Forrester)
+* README.md: Point to Phabricator, not Bugzilla (James D. Forrester)
+
+## v0.4.0 / 2014-12-05
+### Breaking changes
+* [BREAKING CHANGE] Remove deprecated Element#onDOMEvent and #offDOMEvent (Bartosz Dziewoński)
+* [BREAKING CHANGE] Make a number of Element getters static (Bartosz Dziewoński)
+* [BREAKING CHANGE] Rename BookletLayout#getPageName → #getCurrentPageName (Bartosz Dziewoński)
+
+### Features
+* IconElement: Add missing #getIconTitle (Bartosz Dziewoński)
+
+### Styles
+* Follow-up I859ff276e: Add cursor files to repo (Trevor Parscal)
+
+### Code
+* SelectWidget: Rewrite #getRelativeSelectableItem (Bartosz Dziewoński)
+* demo: Don't put buttons in a FieldsetLayout without FieldLayouts around them (Bartosz Dziewoński)
+
+## v0.3.0 / 2014-12-04
+### Breaking changes
+* [BREAKING CHANGE] ButtonWidget: Don't default 'target' to 'blank' (Bartosz Dziewoński)
+
+### Features
+* InputWidget: Update DOM value before firing 'change' event (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Reduce indentation in theme-oo-ui-checkboxInputWidget (Prateek Saxena)
+
+### Code
+* Adding DraggableGroupElement and DraggableElement mixins (Moriel Schottlender)
+* Remove window even if closing promise rejects (Ed Sanders)
+* TextInputWidget: Reuse a single clone instead of appending and removing new ones (Prateek Saxena)
+* Fix lies in documentation (Trevor Parscal)
+* build: Have grunt watch run 'quick-build' instead of 'build' (Prateek Saxena)
+
+## v0.2.4 / 2014-12-02
+### Features
+* MessageDialog: Fit actions again when the dialog is resized (Bartosz Dziewoński)
+* Window: Avoid height flickering when resizing dialogs (Bartosz Dziewoński)
+
+### Code
+* TextInputWidget: Use .css( propertyName, value ) instead of .css( properties) for single property (Prateek Saxena)
+* TextInputWidget: Stop adjustSize if the value of the textarea is the same (Prateek Saxena)
+
+## v0.2.3 / 2014-11-26
+### Features
+* BookletLayout: Make #focus not crash when there are zero pages or when there is no outline (Roan Kattouw)
+* Dialog: Only handle escape events when open (Alex Monk)
+* Pass original event with TextInputWidget#enter (Ed Sanders)
+* MessageDialog: Add Firefox hack for scrollbars when sizing dialogs (Bartosz Dziewoński)
+* MessageDialog: Actually correctly calculate and set height (Bartosz Dziewoński)
+* Window: Disable transitions when changing window height to calculate content height (Bartosz Dziewoński)
+
+### Code
+* Add missing documentation to ToolFactory (Ed Sanders)
+* Fix RadioOptionWidget demos (Trevor Parscal)
+* RadioOptionWidget: Remove lies from documentation (Trevor Parscal)
+* RadioOptionWidget: Increase rule specificity to match OptionWidget (Bartosz Dziewoński)
+
+## v0.2.2 / 2014-11-25
+### Features
+* MessageDialog: Fit actions after updating window size, not before (Bartosz Dziewoński)
+* ProcessDialog, MessageDialog: Support iconed actions (Bartosz Dziewoński)
+
+### Styles
+* Remove padding from undecorated option widgets (Ed Sanders)
+
+### Code
+* LabelWidget: Add missing documentation for input configuration option (Ed Sanders)
+* MessageDialog: Use the right superclass (Bartosz Dziewoński)
+* build: Add .npmignore (Timo Tijhof)
+
+## v0.2.1 / 2014-11-24
+
+### Features
+* Add focus method to BookletLayout (Roan Kattouw)
+* Start the window opening transition before ready, not after (Roan Kattouw)
+
+### Code
+* LabelElement: Kill inline styles (Bartosz Dziewoński)
+* Add missing History.md file now we're a proper repo (James D. Forrester)
+* readme: Update introduction, badges, advice (James D. Forrester)
+* composer: Rename package to 'oojs-ui' and require php 5.3.3 (Timo Tijhof)
+
+## v0.2.0 / 2014-11-17
+* First versioned release
+
+## v0.1.0 / 2013-11-13
+* Initial export of repo
--- /dev/null
+Copyright 2011-2018 OOUI Team and other contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+[![npm](https://img.shields.io/npm/v/oojs-ui.svg?style=flat)](https://www.npmjs.com/package/oojs-ui) [![Packagist](https://img.shields.io/packagist/v/oojs/oojs-ui.svg?style=flat)](https://packagist.org/packages/oojs/oojs-ui) [![David](https://img.shields.io/david/dev/wikimedia/oojs-ui.svg?style=flat)](https://david-dm.org/wikimedia/oojs-ui#info=devDependencies)
+
+OOUI
+=================
+
+OOUI is a component-based JavaScript UI library. Key features:
+
+* Common widgets, layouts, and dialogs
+* Classes, elements, and mixins to create custom interfaces
+* Internationalization and localization, like right-to-left (RTL) languages support
+* Theme-ability
+* Built-in icons
+* Accessibility features
+
+It is the standard library for Web products at the Wikimedia Foundation, having been originally created for use by [VisualEditor](https://www.mediawiki.org/wiki/VisualEditor).
+
+
+Quick start
+----------
+
+The library is available on [npm](https://www.npmjs.com/package/oojs-ui). To install:
+
+<pre lang="bash">
+$ npm install oojs-ui
+</pre>
+
+Once installed, include the following scripts and styles to get started:
+
+<pre lang="html">
+<script src="node_modules/jquery/dist/jquery.min.js"></script>
+<script src="node_modules/oojs/dist/oojs.min.js"></script>
+
+<script src="node_modules/oojs-ui/dist/oojs-ui.min.js"></script>
+<script src="node_modules/oojs-ui/dist/oojs-ui-wikimediaui.min.js"></script>
+<link rel="stylesheet" href="node_modules/oojs-ui/dist/oojs-ui-wikimediaui.min.css">
+</pre>
+
+
+Loading the library
+-------------------
+
+While the distribution directory is chock-full of files, you will normally load only the following three:
+
+* `oojs-ui.js`, containing the full library;
+* One of `oojs-ui-wikimediaui.css` or `oojs-ui-apex.css`, containing theme-specific styles; and
+* One of `oojs-ui-wikimediaui.js` or `oojs-ui-apex.js`, containing theme-specific code
+
+You can load additional icon packs from files named `oojs-ui-wikimediaui-icons-*.css` or `oojs-ui-apex-icons-*.css`.
+
+The remaining files make it possible to load only parts of the whole library.
+
+Furthermore, every CSS file has a right-to-left (RTL) version available, to be used on pages using right-to-left languages if your environment doesn't automatically flip them as needed.
+
+
+Issue tracker
+-------------
+
+Found a bug or missing feature? Please report it in our [issue tracker Phabricator](https://phabricator.wikimedia.org/maniphest/task/edit/form/1/?projects=PHID-PROJ-dgmoevjqeqlerleqzzx5)!
+
+
+Contributing
+------------
+
+We are always delighted when people contribute patches. To setup your development environment:
+
+
+1. Clone the repo: `$ git clone https://phabricator.wikimedia.org/diffusion/GOJU/oojs-ui.git oojs-ui`
+
+2. Move into the library directory:<br>`$ cd oojs-ui`
+
+3. Install [composer](https://getcomposer.org/download/) and make sure running `composer` will execute it (*e.g.* add it to `$PATH` in POSIX environments).
+
+4. Install dev dependencies:<br>`$ npm install`
+
+5. Build the library (you can alternatively use `grunt quick-build` if you don't need to rebuild the PNGs):<br>`$ grunt build`
+
+6. You can see a suite of demos in `/demos` by executing:<br>`$ npm run-script demos`
+
+7. You can also copy the distribution files from the dist directory into your project.
+
+
+We use [Gerrit](https://gerrit.wikimedia.org/) for code review, and [Phabricator](https://phabricator.wikimedia.org) to track issues. To contribute patches or join discussions all you need is a [developer account](https://wikitech.wikimedia.org/w/index.php?title=Special:CreateAccount&returnto=Help%3AGetting+Started).
+
+* If you've found a bug, or wish to request a feature [raise a ticket on Phabricator](https://phabricator.wikimedia.org/maniphest/task/edit/form/1/?projects=PHID-PROJ-dgmoevjqeqlerleqzzx5).
+* To submit your patch, follow [the "getting started" quick-guide](https://www.mediawiki.org/wiki/Gerrit/Getting_started). We try to review patches within a week.
+* We automatically lint and style-check changes to JavaScript, PHP, LESS/CSS, Ruby and JSON files. You can test these yourself with `npm test` and `composer test` locally before pushing changes. SVG files should be squashed in advance of committing with [SVGO](https://github.com/svg/svgo) using `svgo --pretty --disable=removeXMLProcInst --disable=cleanupIDs <filename>`.
+
+A new version of the library is released most weeks on Tuesdays.
+
+Community
+---------
+
+Get updates, ask questions and join the discussion with maintainers and contributors:
+
+* Join the Wikimedia Developers mailing list, [wikitech-l](https://lists.wikimedia.org/mailman/listinfo/wikitech-l).
+* Chat with the maintainers on `#wikimedia-dev` on `irc.freenode.net`.
+* Ask questions on [StackOverflow](https://stackoverflow.com/tags/oojs-ui/info).
+* Watchlist the [documentation](https://www.mediawiki.org/wiki/OOUI) on MediaWiki to stay updated.
+
+
+Versioning
+----------
+
+We use the [Semantic Versioning guidelines](http://semver.org/).
+
+Releases will be numbered in the following format:
+
+`<major>.<minor>.<patch>`
+
+
+Release
+----------
+
+Release process:
+<pre lang="bash">
+
+ $ cd path/to/oojs-ui/
+ $ git remote update
+ $ git checkout -B release -t origin/master
+
+ # Ensure tests pass
+ $ npm install && composer update && npm test && composer test
+
+ # Avoid using "npm version patch" because that creates
+ # both a commit and a tag, and we shouldn't tag until after
+ # the commit is merged.
+
+ # Update release notes
+ # Copy the resulting list into a new section at the top of History.md and edit
+ # into five sub-sections, in order:
+ # * Breaking changes
+ # * Deprecations
+ # * Features
+ # * Styles
+ # * Code
+ $ git log --format='* %s (%aN)' --no-merges --reverse v$(node -e 'console.log(require("./package.json").version);')...HEAD | grep -v "Localisation updates from" | sort
+ $ edit History.md
+
+ # Update the version number
+ $ edit package.json
+
+ $ git add -p
+ $ git commit -m "Tag vX.X.X"
+ $ git review
+
+ # After merging:
+ $ git remote update
+ $ git checkout origin/master
+ $ git tag "vX.X.X"
+ $ npm run publish-build && git push --tags && npm publish
+
+</pre>
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:53Z
+ * Date: 2018-03-23T23:42:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
.oo-ui-element-hidden {
display: none !important;
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
/**
* WikimediaUI Base v0.10.0
.oo-ui-buttonElement-framed.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
right: 1.07142857em;
}
-.oo-ui-buttonElement-framed.oo-ui-indicatorElement.oo-ui-labelElement > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-indicatorElement.oo-ui-iconElement > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-indicatorElement.oo-ui-labelElement > .oo-ui-buttonElement-button {
padding-right: 2.28571429em;
}
.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button {
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:53Z
+ * Date: 2018-03-23T23:42:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
/**
* WikimediaUI Base v0.10.0
padding-top: 3em;
padding-left: 3em;
}
+.oo-ui-toolbar-narrow .oo-ui-tool .oo-ui-tool-link {
+ padding-left: 2.85714286em;
+}
.oo-ui-tool-with-label .oo-ui-tool-link {
padding: 1em 0.85714286em 0.92857143em 2.64285714em;
}
display: block;
left: 0.78571429em;
}
+.oo-ui-toolbar-narrow .oo-ui-tool.oo-ui-iconElement .oo-ui-iconElement-icon {
+ left: 0.71428571em;
+}
.oo-ui-tool .oo-ui-tool-title {
line-height: 1.07142857em;
}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.iconElement > .oo-ui-tool-link > .oo-ui-iconElement-icon {
display: block;
}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool + .oo-ui-tool {
+ margin-left: -2px;
+}
.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool:not( .oo-ui-toolGroupTool ).oo-ui-widget-enabled:hover {
background-color: #eaecf0;
}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
text-align: right;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup {
+ min-width: 2.85714286em;
+}
.oo-ui-popupToolGroup.oo-ui-indicatorElement:not( .oo-ui-labelElement ):not( .oo-ui-iconElement ) {
min-width: 1.85714286em;
}
.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
left: 0.78571429em;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ left: 0.71428571em;
+}
.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
background-position: center 52%;
right: 0.57142857em;
.oo-ui-popupToolGroup.oo-ui-iconElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle {
padding-left: 3em;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-iconElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle {
+ padding-left: 2.85714286em;
+}
.oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle {
padding: 1em 0.85714286em 0.92857143em;
}
.oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
line-height: 1.07142857em;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle {
+ padding-left: 0.71428571em;
+ padding-right: 0.71428571em;
+}
.oo-ui-popupToolGroup.oo-ui-iconElement.oo-ui-labelElement .oo-ui-popupToolGroup-handle {
padding-left: 2.64285714em;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-iconElement.oo-ui-labelElement .oo-ui-popupToolGroup-handle {
+ padding-left: 2.5em;
+}
.oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle {
padding-right: 1.85714286em;
}
font-weight: bold;
line-height: 2.28571429em;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-header {
+ padding: 0 0.71428571em;
+}
.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
margin: 0 -1px;
border: 1px solid #c8ccd1;
.oo-ui-popupToolGroup .oo-ui-tool-link {
padding: 1em 0.85714286em 0.92857143em 2.64285714em;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup .oo-ui-tool-link {
+ padding-left: 0.71428571em;
+ padding-right: 2.5em;
+}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
color: #222;
}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not( :empty ) {
padding-left: 1.28571429em;
}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not( :empty ) {
+ padding-left: 1.14285714em;
+}
.oo-ui-popupToolGroup.oo-ui-widget-enabled > .oo-ui-popupToolGroup-handle {
-webkit-transition: background-color 100ms, box-shadow 100ms;
-moz-transition: background-color 100ms, box-shadow 100ms;
display: block;
}
.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
- min-width: 10em;
+ min-width: 140px;
}
.oo-ui-toolbar-narrow .oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
- min-width: 8.125em;
+ min-width: 100px;
}
.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
left: 0.78571429em;
}
+.oo-ui-toolbar-narrow .oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ left: 0.71428571em;
+}
.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconElement-icon {
background-image: url('themes/wikimediaui/images/icons/check-progressive.png');
background-image: linear-gradient(transparent, transparent), /* @embed */ url('themes/wikimediaui/images/icons/check-progressive.svg');
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:53Z
+ * Date: 2018-03-23T23:42:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
.oo-ui-draggableElement-handle:not( .oo-ui-draggableElement-undraggable ).oo-ui-widget {
cursor: move;
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
/**
* WikimediaUI Base v0.10.0
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:53Z
+ * Date: 2018-03-23T23:42:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:53Z
+ * Date: 2018-03-23T23:42:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
.oo-ui-actionWidget.oo-ui-pendingElement-pending {
background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:57Z
+ * Date: 2018-03-23T23:42:37Z
*/
/**
* WikimediaUI Base v0.10.0
/*!
- * OOUI v0.26.0
+ * OOUI v0.26.1
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-03-21T00:00:53Z
+ * Date: 2018-03-23T23:42:32Z
*/
( function ( OO ) {
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="2 2 20 20"><path fill-rule="evenodd" d="M5 21l7-6 7 6V3H5z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="2 2 20 20"><path fill-rule="evenodd" d="M17.5 4.5v13.2L12 13.5l-5.5 4.2V4.5zM5 21l7-6 7 6V3H5z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>advanced</title><circle cx="10" cy="10" r="1.75"/><path d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 9.75l-1.37.25a3.73 3.73 0 0 1-.38.93l.82 1.07L13 14.07l-1.12-.82a3.73 3.73 0 0 1-.93.38l-.2 1.37h-1.5L9 13.63a3.73 3.73 0 0 1-.93-.38L7 14.07 5.93 13l.82-1.12a3.73 3.73 0 0 1-.38-.88L5 10.75v-1.5L6.37 9a3.72 3.72 0 0 1 .38-.93L5.93 7 7 5.93l1.12.82A3.73 3.73 0 0 1 9 6.37L9.25 5h1.5L11 6.37a3.74 3.74 0 0 1 .93.38L13 5.93 14.07 7l-.82 1.12a3.73 3.73 0 0 1 .38.93l1.37.2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>advanced</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>advanced</title><circle cx="10" cy="10" r="1.75"/><path d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 9.75l-1.37.25a3.73 3.73 0 0 1-.38.93l.82 1.07L13 14.07l-1.12-.82a3.73 3.73 0 0 1-.93.38l-.2 1.37h-1.5L9 13.63a3.73 3.73 0 0 1-.93-.38L7 14.07 5.93 13l.82-1.12a3.73 3.73 0 0 1-.38-.88L5 10.75v-1.5L6.37 9a3.72 3.72 0 0 1 .38-.93L5.93 7 7 5.93l1.12.82A3.73 3.73 0 0 1 9 6.37L9.25 5h1.5L11 6.37a3.74 3.74 0 0 1 .93.38L13 5.93 14.07 7l-.82 1.12a3.73 3.73 0 0 1 .38.93l1.37.2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>advanced</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>advanced</title><circle cx="10" cy="10" r="1.75"/><path d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 9.75l-1.37.25a3.73 3.73 0 0 1-.38.93l.82 1.07L13 14.07l-1.12-.82a3.73 3.73 0 0 1-.93.38l-.2 1.37h-1.5L9 13.63a3.73 3.73 0 0 1-.93-.38L7 14.07 5.93 13l.82-1.12a3.73 3.73 0 0 1-.38-.88L5 10.75v-1.5L6.37 9a3.72 3.72 0 0 1 .38-.93L5.93 7 7 5.93l1.12.82A3.73 3.73 0 0 1 9 6.37L9.25 5h1.5L11 6.37a3.74 3.74 0 0 1 .93.38L13 5.93 14.07 7l-.82 1.12a3.73 3.73 0 0 1 .38.93l1.37.2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>advanced</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>align left</title><path d="M1 15h18v2H1zm11-8h7v2h-7zm0 4h7v2h-7zM1 3h18v2H1z"/><rect width="8" height="6" x="1" y="7" rx="1" ry="1"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>align left</title><path d="M1 15h18v2H1zm11-8h7v2h-7zm0 4h7v2h-7zM1 3h18v2H1z"/><rect width="8" height="6" x="1" y="7" rx="1" ry="1"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>align left</title><path d="M1 15h18v2H1zm11-8h7v2h-7zm0 4h7v2h-7zM1 3h18v2H1z"/><rect width="8" height="6" x="1" y="7" rx="1" ry="1"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>align right</title><path d="M1 15h18v2H1zm0-8h7v2H1zm0 4h7v2H1zm0-8h18v2H1z"/><rect width="8" height="6" x="11" y="7" rx="1" ry="1"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>align right</title><path d="M1 15h18v2H1zm0-8h7v2H1zm0 4h7v2H1zm0-8h18v2H1z"/><rect width="8" height="6" x="11" y="7" rx="1" ry="1"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>align right</title><path d="M1 15h18v2H1zm0-8h7v2H1zm0 4h7v2H1zm0-8h18v2H1z"/><rect width="8" height="6" x="11" y="7" rx="1" ry="1"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>article</title><path d="M3 3v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zm12 2h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>article</title><path d="M3 3v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zm12 2h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path d="M3 3v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zm12 2h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bookmark</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bookmark</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bookmark outlined</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm0 14.25l-5-3.5-5 3.5V3h10z"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bookmark outlined</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm0 14.25l-5-3.5-5 3.5V3h10z"/></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark outlined</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm0 14.25l-5-3.5-5 3.5V3h10z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.63 2.63 0 0 1-.34.74 3.06 3.06 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.59.52a3 3 0 0 0-.47.56A2.49 2.49 0 0 0 11 12a4.12 4.12 0 0 0-.11 1H9.08a8.68 8.68 0 0 1 .08-1.25 3.54 3.54 0 0 1 .24-.9 2.81 2.81 0 0 1 .41-.68 4.63 4.63 0 0 1 .58-.58l.51-.44a3 3 0 0 0 .44-.45 1.92 1.92 0 0 0 .3-.54 2.13 2.13 0 0 0 .11-.72 1.94 1.94 0 0 0-.18-.86 1.79 1.79 0 0 0-.43-.58 1.69 1.69 0 0 0-.54-.32 1.55 1.55 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.49 1.82H6.16a4.84 4.84 0 0 1 .28-1.68 3.57 3.57 0 0 1 .8-1.29 3.62 3.62 0 0 1 1.27-.83A4.52 4.52 0 0 1 10.18 4a4.42 4.42 0 0 1 1.43.23 3.48 3.48 0 0 1 1.16.65 3 3 0 0 1 .78 1.06 3.49 3.49 0 0 1 .28 1.44 3.63 3.63 0 0 1-.12 1.02z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>help</title><path d="M10.06 1C13 1 15 2.89 15 5.53a4.59 4.59 0 0 1-2.29 4.08c-1.42.92-1.82 1.53-1.82 2.71V13H8.38v-.81a3.84 3.84 0 0 1 2-3.84c1.34-.9 1.79-1.53 1.79-2.71a2.1 2.1 0 0 0-2.08-2.14h-.17a2.3 2.3 0 0 0-2.38 2.22v.17H5A4.71 4.71 0 0 1 9.51 1a5 5 0 0 1 .55 0zM8 17a1.89 1.89 0 0 1 1.77-2H10a1.87 1.87 0 0 1 2 1.73 1.22 1.22 0 0 1 0 .27 1.87 1.87 0 0 1-1.73 2 1.22 1.22 0 0 1-.27 0 1.88 1.88 0 0 1-2-1.75A1 1 0 0 1 8 17z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.63 2.63 0 0 1-.34.74 3.06 3.06 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.59.52a3 3 0 0 0-.47.56A2.49 2.49 0 0 0 11 12a4.12 4.12 0 0 0-.11 1H9.08a8.68 8.68 0 0 1 .08-1.25 3.54 3.54 0 0 1 .24-.9 2.81 2.81 0 0 1 .41-.68 4.63 4.63 0 0 1 .58-.58l.51-.44a3 3 0 0 0 .44-.45 1.92 1.92 0 0 0 .3-.54 2.13 2.13 0 0 0 .11-.72 1.94 1.94 0 0 0-.18-.86 1.79 1.79 0 0 0-.43-.58 1.69 1.69 0 0 0-.54-.32 1.55 1.55 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.49 1.82H6.16a4.84 4.84 0 0 1 .28-1.68 3.57 3.57 0 0 1 .8-1.29 3.62 3.62 0 0 1 1.27-.83A4.52 4.52 0 0 1 10.18 4a4.42 4.42 0 0 1 1.43.23 3.48 3.48 0 0 1 1.16.65 3 3 0 0 1 .78 1.06 3.49 3.49 0 0 1 .28 1.44 3.63 3.63 0 0 1-.12 1.02z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>help</title><path d="M10.06 1C13 1 15 2.89 15 5.53a4.59 4.59 0 0 1-2.29 4.08c-1.42.92-1.82 1.53-1.82 2.71V13H8.38v-.81a3.84 3.84 0 0 1 2-3.84c1.34-.9 1.79-1.53 1.79-2.71a2.1 2.1 0 0 0-2.08-2.14h-.17a2.3 2.3 0 0 0-2.38 2.22v.17H5A4.71 4.71 0 0 1 9.51 1a5 5 0 0 1 .55 0zM8 17a1.89 1.89 0 0 1 1.77-2H10a1.87 1.87 0 0 1 2 1.73 1.22 1.22 0 0 1 0 .27 1.87 1.87 0 0 1-1.73 2 1.22 1.22 0 0 1-.27 0 1.88 1.88 0 0 1-2-1.75A1 1 0 0 1 8 17z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.63 2.63 0 0 1-.34.74 3.06 3.06 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.59.52a3 3 0 0 0-.47.56A2.49 2.49 0 0 0 11 12a4.12 4.12 0 0 0-.11 1H9.08a8.68 8.68 0 0 1 .08-1.25 3.54 3.54 0 0 1 .24-.9 2.81 2.81 0 0 1 .41-.68 4.63 4.63 0 0 1 .58-.58l.51-.44a3 3 0 0 0 .44-.45 1.92 1.92 0 0 0 .3-.54 2.13 2.13 0 0 0 .11-.72 1.94 1.94 0 0 0-.18-.86 1.79 1.79 0 0 0-.43-.58 1.69 1.69 0 0 0-.54-.32 1.55 1.55 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.49 1.82H6.16a4.84 4.84 0 0 1 .28-1.68 3.57 3.57 0 0 1 .8-1.29 3.62 3.62 0 0 1 1.27-.83A4.52 4.52 0 0 1 10.18 4a4.42 4.42 0 0 1 1.43.23 3.48 3.48 0 0 1 1.16.65 3 3 0 0 1 .78 1.06 3.49 3.49 0 0 1 .28 1.44 3.63 3.63 0 0 1-.12 1.02z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path d="M10.06 1C13 1 15 2.89 15 5.53a4.59 4.59 0 0 1-2.29 4.08c-1.42.92-1.82 1.53-1.82 2.71V13H8.38v-.81a3.84 3.84 0 0 1 2-3.84c1.34-.9 1.79-1.53 1.79-2.71a2.1 2.1 0 0 0-2.08-2.14h-.17a2.3 2.3 0 0 0-2.38 2.22v.17H5A4.71 4.71 0 0 1 9.51 1a5 5 0 0 1 .55 0zM8 17a1.89 1.89 0 0 1 1.77-2H10a1.87 1.87 0 0 1 2 1.73 1.22 1.22 0 0 1 0 .27 1.87 1.87 0 0 1-1.73 2 1.22 1.22 0 0 1-.27 0 1.88 1.88 0 0 1-2-1.75A1 1 0 0 1 8 17z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>settings</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>settings</title><circle cx="10" cy="10" r="1.75"/><path d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 9.75l-1.37.25a3.73 3.73 0 0 1-.38.93l.82 1.07L13 14.07l-1.12-.82a3.73 3.73 0 0 1-.93.38l-.2 1.37h-1.5L9 13.63a3.73 3.73 0 0 1-.93-.38L7 14.07 5.93 13l.82-1.12a3.73 3.73 0 0 1-.38-.88L5 10.75v-1.5L6.37 9a3.72 3.72 0 0 1 .38-.93L5.93 7 7 5.93l1.12.82A3.73 3.73 0 0 1 9 6.37L9.25 5h1.5L11 6.37a3.74 3.74 0 0 1 .93.38L13 5.93 14.07 7l-.82 1.12a3.73 3.73 0 0 1 .38.93l1.37.2z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>settings</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>settings</title><circle cx="10" cy="10" r="1.75"/><path d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 9.75l-1.37.25a3.73 3.73 0 0 1-.38.93l.82 1.07L13 14.07l-1.12-.82a3.73 3.73 0 0 1-.93.38l-.2 1.37h-1.5L9 13.63a3.73 3.73 0 0 1-.93-.38L7 14.07 5.93 13l.82-1.12a3.73 3.73 0 0 1-.38-.88L5 10.75v-1.5L6.37 9a3.72 3.72 0 0 1 .38-.93L5.93 7 7 5.93l1.12.82A3.73 3.73 0 0 1 9 6.37L9.25 5h1.5L11 6.37a3.74 3.74 0 0 1 .93.38L13 5.93 14.07 7l-.82 1.12a3.73 3.73 0 0 1 .38.93l1.37.2z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><circle cx="10" cy="10" r="1.75"/><path d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 9.75l-1.37.25a3.73 3.73 0 0 1-.38.93l.82 1.07L13 14.07l-1.12-.82a3.73 3.73 0 0 1-.93.38l-.2 1.37h-1.5L9 13.63a3.73 3.73 0 0 1-.93-.38L7 14.07 5.93 13l.82-1.12a3.73 3.73 0 0 1-.38-.88L5 10.75v-1.5L6.37 9a3.72 3.72 0 0 1 .38-.93L5.93 7 7 5.93l1.12.82A3.73 3.73 0 0 1 9 6.37L9.25 5h1.5L11 6.37a3.74 3.74 0 0 1 .93.38L13 5.93 14.07 7l-.82 1.12a3.73 3.73 0 0 1 .38.93l1.37.2z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>speech bubbles</title><path d="M17 1H3a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>speech bubbles</title><path d="M18 4h-1v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2z"/><path d="M14 0H2a2 2 0 0 0-2 2v14l4-4h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>speech bubbles</title><path d="M17 1H3a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>speech bubbles</title><path d="M18 4h-1v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2z"/><path d="M14 0H2a2 2 0 0 0-2 2v14l4-4h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M17 1H3a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M18 4h-1v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2z"/><path d="M14 0H2a2 2 0 0 0-2 2v14l4-4h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>speech bubbles</title><path d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>speech bubbles</title><path d="M0 6v14l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6z"/><path d="M4 2v8c0 1.1.9 2 2 2h10l4 4V2c0-1.1-.9-2-2-2H6C4.9 0 4 .9 4 2z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>speech bubbles</title><path d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>speech bubbles</title><path d="M0 6v14l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6z"/><path d="M4 2v8c0 1.1.9 2 2 2h10l4 4V2c0-1.1-.9-2-2-2H6C4.9 0 4 .9 4 2z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M0 6v14l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6z"/><path d="M4 2v8c0 1.1.9 2 2 2h10l4 4V2c0-1.1-.9-2-2-2H6C4.9 0 4 .9 4 2z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>underline</title><path d="M3 18h14v2H3zm7-4.1a4.92 4.92 0 0 0 2-.37 4.09 4.09 0 0 0 1.45-1 4.51 4.51 0 0 0 .91-1.58 6.25 6.25 0 0 0 .31-2V1H17v7.9a8 8 0 0 1-.48 2.82A6.56 6.56 0 0 1 15.13 14a6.34 6.34 0 0 1-2.2 1.49A7.56 7.56 0 0 1 10 16a7.56 7.56 0 0 1-2.92-.54A6.4 6.4 0 0 1 4.88 14a6.5 6.5 0 0 1-1.39-2.25A8 8 0 0 1 3 8.9V1h2.37v7.88a6.27 6.27 0 0 0 .31 2 4.51 4.51 0 0 0 .91 1.58 4.15 4.15 0 0 0 1.46 1 4.89 4.89 0 0 0 1.95.44z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>underline</title><path d="M3 17h14v2H3zM7.704 10.274L10 3.731l2.296 6.543zM14.322 16H17L11.5 2h-3L3 16h2.678l1.418-3.995h5.808z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>underline</title><path d="M3 18h14v2H3zm7-4.1a4.92 4.92 0 0 0 2-.37 4.09 4.09 0 0 0 1.45-1 4.51 4.51 0 0 0 .91-1.58 6.25 6.25 0 0 0 .31-2V1H17v7.9a8 8 0 0 1-.48 2.82A6.56 6.56 0 0 1 15.13 14a6.34 6.34 0 0 1-2.2 1.49A7.56 7.56 0 0 1 10 16a7.56 7.56 0 0 1-2.92-.54A6.4 6.4 0 0 1 4.88 14a6.5 6.5 0 0 1-1.39-2.25A8 8 0 0 1 3 8.9V1h2.37v7.88a6.27 6.27 0 0 0 .31 2 4.51 4.51 0 0 0 .91 1.58 4.15 4.15 0 0 0 1.46 1 4.89 4.89 0 0 0 1.95.44z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>underline</title><path d="M3 17h14v2H3zM7.704 10.274L10 3.731l2.296 6.543zM14.322 16H17L11.5 2h-3L3 16h2.678l1.418-3.995h5.808z"/></g></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>underline</title><path d="M3 18h14v2H3zm7-4.1a4.92 4.92 0 0 0 2-.37 4.09 4.09 0 0 0 1.45-1 4.51 4.51 0 0 0 .91-1.58 6.25 6.25 0 0 0 .31-2V1H17v7.9a8 8 0 0 1-.48 2.82A6.56 6.56 0 0 1 15.13 14a6.34 6.34 0 0 1-2.2 1.49A7.56 7.56 0 0 1 10 16a7.56 7.56 0 0 1-2.92-.54A6.4 6.4 0 0 1 4.88 14a6.5 6.5 0 0 1-1.39-2.25A8 8 0 0 1 3 8.9V1h2.37v7.88a6.27 6.27 0 0 0 .31 2 4.51 4.51 0 0 0 .91 1.58 4.15 4.15 0 0 0 1.46 1 4.89 4.89 0 0 0 1.95.44z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>underline</title><path d="M3 17h14v2H3zM7.704 10.274L10 3.731l2.296 6.543zM14.322 16H17L11.5 2h-3L3 16h2.678l1.418-3.995h5.808z"/></svg>
\ No newline at end of file
*
* - `digitTransformTable`
* - `separatorTransformTable`
+ * - `minimumGroupingDigits`
* - `grammarForms`
* - `pluralRules`
* - `digitGroupingPattern`
* @private
* @param {number} value the number to be formatted, ignores sign
* @param {string} pattern the number portion of a pattern (e.g. `#,##0.00`)
- * @param {Object} [options] If provided, both option keys must be present:
+ * @param {Object} [options] If provided, all option keys must be present:
* @param {string} options.decimal The decimal separator. Defaults to: `'.'`.
* @param {string} options.group The group separator. Defaults to: `','`.
+ * @param {number|null} options.minimumGroupingDigits
* @return {string}
*/
function commafyNumber( value, pattern, options ) {
}
}
- for ( whole = valueParts[ 0 ]; whole; ) {
- off = groupSize ? whole.length - groupSize : 0;
- pieces.push( ( off > 0 ) ? whole.slice( off ) : whole );
- whole = ( off > 0 ) ? whole.slice( 0, off ) : '';
-
- if ( groupSize2 ) {
- groupSize = groupSize2;
- groupSize2 = null;
+ if (
+ options.minimumGroupingDigits === null ||
+ valueParts[ 0 ].length >= groupSize + options.minimumGroupingDigits
+ ) {
+ for ( whole = valueParts[ 0 ]; whole; ) {
+ off = groupSize ? whole.length - groupSize : 0;
+ pieces.push( ( off > 0 ) ? whole.slice( off ) : whole );
+ whole = ( off > 0 ) ? whole.slice( 0, off ) : '';
+
+ if ( groupSize2 ) {
+ groupSize = groupSize2;
+ groupSize2 = null;
+ }
}
+ valueParts[ 0 ] = pieces.reverse().join( options.group );
}
- valueParts[ 0 ] = pieces.reverse().join( options.group );
return valueParts.join( options.decimal );
}
*/
convertNumber: function ( num, integer ) {
var transformTable, digitTransformTable, separatorTransformTable,
- i, numberString, convertedNumber, pattern;
+ i, numberString, convertedNumber, pattern, minimumGroupingDigits;
// Quick shortcut for plain numbers
if ( integer && parseInt( num, 10 ) === num ) {
// When unformatting, we just use separatorTransformTable.
pattern = mw.language.getData( mw.config.get( 'wgUserLanguage' ),
'digitGroupingPattern' ) || '#,##0.###';
- numberString = mw.language.commafy( num, pattern );
+ minimumGroupingDigits = mw.language.getData( mw.config.get( 'wgUserLanguage' ),
+ 'minimumGroupingDigits' ) || null;
+ numberString = mw.language.commafy( num, pattern, minimumGroupingDigits );
}
if ( transformTable ) {
*
* @param {number} value
* @param {string} pattern Pattern string as described by Unicode TR35
+ * @param {number|null} [minimumGroupingDigits=null]
* @throws {Error} If unable to find a number expression in `pattern`.
* @return {string}
*/
- commafy: function ( value, pattern ) {
+ commafy: function ( value, pattern, minimumGroupingDigits ) {
var numberPattern,
transformTable = mw.language.getSeparatorTransformTable(),
group = transformTable[ ',' ] || ',',
pattern = patternList[ ( value < 0 ) ? 1 : 0 ] || ( '-' + positivePattern );
numberPattern = positivePattern.match( numberPatternRE );
+ minimumGroupingDigits = minimumGroupingDigits !== undefined ? minimumGroupingDigits : null;
if ( !numberPattern ) {
throw new Error( 'unable to find a number expression in pattern: ' + pattern );
}
return pattern.replace( numberPatternRE, commafyNumber( value, numberPattern[ 0 ], {
+ minimumGroupingDigits: minimumGroupingDigits,
decimal: decimal,
group: group
} ) );
// Parent
mw.rcfilters.ui.MarkSeenButtonWidget.parent.call( this, $.extend( {
label: mw.message( 'rcfilters-watchlist-markseen-button' ).text(),
- icon: 'doubleCheck'
+ icon: 'checkAll'
}, config ) );
this.controller = controller;
width: 100%;
border: 1px solid @colorFieldBorder;
border-radius: @borderRadius;
- padding: 0.625em 0.625em 0.546875em;
+ padding: 0.57142857em 0.57142857em 0.5em;
// necessary for smooth transition
box-shadow: inset 0 0 0 0.1em #fff;
font-family: inherit;
font-size: inherit;
- line-height: 1.172em;
+ line-height: 1.07142857em;
vertical-align: middle;
// Normalize & style placeholder text, see T139034
+++ /dev/null
-/* HACK: Set sane font-size for OOUI dialogs (and menus/popups inside the default overlay), in
- the most common case. This should be skin's responsibility, but alas our skins tend to have the
- weirdest font-sizes on body. This shall be removed when we make the MediaWiki skins bundled with
- tarball sane. (T91152) */
-body > .oo-ui-windowManager,
-.oo-ui-defaultOverlay {
- font-size: 0.8rem;
-}
// Set content language. This invalidates the magic word cache and title services
$lang = Language::factory( $langCode );
+ $lang->resetNamespaces();
$setup['wgContLang'] = $lang;
$reset = function () {
MagicWord::clearCache();
* @covers ApiBlock
*/
class ApiBlockTest extends ApiTestCase {
+ protected $mUser = null;
+
protected function setUp() {
parent::setUp();
$this->doLogin();
+
+ $this->mUser = $this->getMutableTestUser()->getUser();
}
protected function tearDown() {
- $block = Block::newFromTarget( 'UTApiBlockee' );
+ $block = Block::newFromTarget( $this->mUser->getName() );
if ( !is_null( $block ) ) {
$block->delete();
}
return $this->getTokenList( self::$users['sysop'] );
}
- function addDBDataOnce() {
- $user = User::newFromName( 'UTApiBlockee' );
-
- if ( $user->getId() == 0 ) {
- $user->addToDatabase();
- TestUser::setPasswordForUser( $user, 'UTApiBlockeePassword' );
-
- $user->saveSettings();
- }
- }
-
/**
- * This test has probably always been broken and use an invalid token
- * Bug tracking brokenness is https://phabricator.wikimedia.org/T37646
- *
- * Root cause is https://gerrit.wikimedia.org/r/3434
- * Which made the Block/Unblock API to actually verify the token
- * previously always considered valid (T36212).
+ * @param array $extraParams Extra API parameters to pass to doApiRequest
+ * @param User $blocker User to do the blocking, null to pick
+ * arbitrarily
*/
- public function testMakeNormalBlock() {
- $tokens = $this->getTokens();
+ private function doBlock( array $extraParams = [], User $blocker = null ) {
+ if ( $blocker === null ) {
+ $blocker = self::$users['sysop']->getUser();
+ }
- $user = User::newFromName( 'UTApiBlockee' );
+ $tokens = $this->getTokens();
- if ( !$user->getId() ) {
- $this->markTestIncomplete( "The user UTApiBlockee does not exist" );
- }
+ $this->assertNotNull( $this->mUser, 'Sanity check' );
+ $this->assertNotSame( 0, $this->mUser->getId(), 'Sanity check' );
- if ( !array_key_exists( 'blocktoken', $tokens ) ) {
- $this->markTestIncomplete( "No block token found" );
- }
+ $this->assertArrayHasKey( 'blocktoken', $tokens, 'Sanity check' );
- $this->doApiRequest( [
+ $params = [
'action' => 'block',
- 'user' => 'UTApiBlockee',
+ 'user' => $this->mUser->getName(),
'reason' => 'Some reason',
- 'token' => $tokens['blocktoken'] ], null, false, self::$users['sysop']->getUser() );
+ 'token' => $tokens['blocktoken'],
+ ];
+ if ( array_key_exists( 'userid', $extraParams ) ) {
+ // Make sure we don't have both user and userid
+ unset( $params['user'] );
+ }
+ $ret = $this->doApiRequest( array_merge( $params, $extraParams ), null,
+ false, $blocker );
- $block = Block::newFromTarget( 'UTApiBlockee' );
+ $block = Block::newFromTarget( $this->mUser->getName() );
$this->assertTrue( !is_null( $block ), 'Block is valid' );
- $this->assertEquals( 'UTApiBlockee', (string)$block->getTarget() );
- $this->assertEquals( 'Some reason', $block->mReason );
- $this->assertEquals( 'infinity', $block->mExpiry );
+ $this->assertSame( $this->mUser->getName(), (string)$block->getTarget() );
+ $this->assertSame( 'Some reason', $block->mReason );
+
+ return $ret;
+ }
+
+ /**
+ * Block by username
+ */
+ public function testNormalBlock() {
+ $this->doBlock();
}
/**
* Block by user ID
*/
- public function testMakeNormalBlockId() {
- $tokens = $this->getTokens();
- $user = User::newFromName( 'UTApiBlockee' );
+ public function testBlockById() {
+ $this->doBlock( [ 'userid' => $this->mUser->getId() ] );
+ }
- if ( !$user->getId() ) {
- $this->markTestIncomplete( "The user UTApiBlockee does not exist." );
- }
+ /**
+ * A blocked user can't block
+ */
+ public function testBlockByBlockedUser() {
+ $this->setExpectedException( ApiUsageException::class,
+ 'You cannot block or unblock other users because you are yourself blocked.' );
+
+ $blocked = $this->getMutableTestUser( [ 'sysop' ] )->getUser();
+ $block = new Block( [
+ 'address' => $blocked->getName(),
+ 'by' => self::$users['sysop']->getUser()->getId(),
+ 'reason' => 'Capriciousness',
+ 'timestamp' => '19370101000000',
+ 'expiry' => 'infinity',
+ ] );
+ $block->insert();
+
+ $this->doBlock( [], $blocked );
+ }
- if ( !array_key_exists( 'blocktoken', $tokens ) ) {
- $this->markTestIncomplete( "No block token found" );
- }
+ public function testBlockOfNonexistentUser() {
+ $this->setExpectedException( ApiUsageException::class,
+ 'There is no user by the name "Nonexistent". Check your spelling.' );
- $data = $this->doApiRequest( [
- 'action' => 'block',
- 'userid' => $user->getId(),
- 'reason' => 'Some reason',
- 'token' => $tokens['blocktoken'] ], null, false, self::$users['sysop']->getUser() );
+ $this->doBlock( [ 'user' => 'Nonexistent' ] );
+ }
+
+ public function testBlockOfNonexistentUserId() {
+ $id = 948206325;
+ $this->setExpectedException( ApiUsageException::class,
+ "There is no user with ID $id." );
+
+ $this->assertFalse( User::whoIs( $id ), 'Sanity check' );
+
+ $this->doBlock( [ 'userid' => $id ] );
+ }
+
+ public function testBlockWithTag() {
+ ChangeTags::defineTag( 'custom tag' );
+
+ $this->doBlock( [ 'tags' => 'custom tag' ] );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $this->assertSame( 'custom tag', $dbw->selectField(
+ [ 'change_tag', 'logging' ],
+ 'ct_tag',
+ [ 'log_type' => 'block' ],
+ __METHOD__,
+ [],
+ [ 'change_tag' => [ 'INNER JOIN', 'ct_log_id = log_id' ] ]
+ ) );
+ }
+
+ public function testBlockWithProhibitedTag() {
+ $this->setExpectedException( ApiUsageException::class,
+ 'You do not have permission to apply change tags along with your changes.' );
+
+ ChangeTags::defineTag( 'custom tag' );
+
+ $this->setMwGlobals( 'wgRevokePermissions',
+ [ 'user' => [ 'applychangetags' => true ] ] );
+
+ $this->doBlock( [ 'tags' => 'custom tag' ] );
+ }
+
+ public function testBlockWithHide() {
+ global $wgGroupPermissions;
+ $newPermissions = $wgGroupPermissions['sysop'];
+ $newPermissions['hideuser'] = true;
+ $this->mergeMwGlobalArrayValue( 'wgGroupPermissions',
+ [ 'sysop' => $newPermissions ] );
+
+ $res = $this->doBlock( [ 'hidename' => '' ] );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $this->assertSame( '1', $dbw->selectField(
+ 'ipblocks',
+ 'ipb_deleted',
+ [ 'ipb_id' => $res[0]['block']['id'] ],
+ __METHOD__
+ ) );
+ }
+
+ public function testBlockWithProhibitedHide() {
+ $this->setExpectedException( ApiUsageException::class,
+ "You don't have permission to hide user names from the block log." );
+
+ $this->doBlock( [ 'hidename' => '' ] );
+ }
+
+ public function testBlockWithEmailBlock() {
+ $res = $this->doBlock( [ 'noemail' => '' ] );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $this->assertSame( '1', $dbw->selectField(
+ 'ipblocks',
+ 'ipb_block_email',
+ [ 'ipb_id' => $res[0]['block']['id'] ],
+ __METHOD__
+ ) );
+ }
+
+ public function testBlockWithProhibitedEmailBlock() {
+ $this->setExpectedException( ApiUsageException::class,
+ "You don't have permission to block users from sending email through the wiki." );
+
+ $this->setMwGlobals( 'wgRevokePermissions',
+ [ 'sysop' => [ 'blockemail' => true ] ] );
+
+ $this->doBlock( [ 'noemail' => '' ] );
+ }
+
+ public function testBlockWithExpiry() {
+ $res = $this->doBlock( [ 'expiry' => '1 day' ] );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $expiry = $dbw->selectField(
+ 'ipblocks',
+ 'ipb_expiry',
+ [ 'ipb_id' => $res[0]['block']['id'] ],
+ __METHOD__
+ );
+
+ // Allow flakiness up to one second
+ $this->assertLessThanOrEqual( 1,
+ abs( wfTimestamp( TS_UNIX, $expiry ) - ( time() + 86400 ) ) );
+ }
- $block = Block::newFromTarget( 'UTApiBlockee' );
+ public function testBlockWithInvalidExpiry() {
+ $this->setExpectedException( ApiUsageException::class, "Expiry time invalid." );
- $this->assertTrue( !is_null( $block ), 'Block is valid.' );
- $this->assertEquals( 'UTApiBlockee', (string)$block->getTarget() );
- $this->assertEquals( 'Some reason', $block->mReason );
- $this->assertEquals( 'infinity', $block->mExpiry );
+ $this->doBlock( [ 'expiry' => '' ] );
}
/**
$this->doApiRequest(
[
'action' => 'block',
- 'user' => 'UTApiBlockee',
+ 'user' => $this->mUser->getName(),
'reason' => 'Some reason',
],
null,
}
public function testDelete() {
- $name = 'Help:ApiDeleteTest_testDelete';
-
- // test non-existing page
- try {
- $this->doApiRequestWithToken( [
- 'action' => 'delete',
- 'title' => $name,
- ] );
- $this->fail( "Should have raised an ApiUsageException" );
- } catch ( ApiUsageException $e ) {
- $this->assertTrue( self::apiExceptionHasCode( $e, 'missingtitle' ) );
- }
+ $name = 'Help:' . ucfirst( __FUNCTION__ );
// create new page
$this->editPage( $name, 'Some text' );
$apiResult = $this->doApiRequestWithToken( [
'action' => 'delete',
'title' => $name,
- ] );
- $apiResult = $apiResult[0];
+ ] )[0];
$this->assertArrayHasKey( 'delete', $apiResult );
$this->assertArrayHasKey( 'title', $apiResult['delete'] );
- // Normalized $name is used
- $this->assertSame(
- 'Help:ApiDeleteTest testDelete',
- $apiResult['delete']['title']
- );
+ $this->assertSame( $name, $apiResult['delete']['title'] );
$this->assertArrayHasKey( 'logid', $apiResult['delete'] );
$this->assertFalse( Title::newFromText( $name )->exists() );
}
+ public function testDeleteNonexistent() {
+ $this->setExpectedException( ApiUsageException::class,
+ "The page you specified doesn't exist." );
+
+ $this->doApiRequestWithToken( [
+ 'action' => 'delete',
+ 'title' => 'This page deliberately left nonexistent',
+ ] );
+ }
+
public function testDeletionWithoutPermission() {
- $name = 'Help:ApiDeleteTest_testDeleteWithoutPermission';
+ $this->setExpectedException( ApiUsageException::class,
+ 'The action you have requested is limited to users in the group:' );
+
+ $name = 'Help:' . ucfirst( __FUNCTION__ );
// create new page
$this->editPage( $name, 'Some text' );
'title' => $name,
'token' => $user->getEditToken(),
], null, null, $user );
- $this->fail( "Should have raised an ApiUsageException" );
- } catch ( ApiUsageException $e ) {
- $this->assertTrue( self::apiExceptionHasCode( $e, 'permissiondenied' ) );
+ } finally {
+ $this->assertTrue( Title::newFromText( $name )->exists() );
+ }
+ }
+
+ public function testDeleteWithTag() {
+ $name = 'Help:' . ucfirst( __FUNCTION__ );
+
+ ChangeTags::defineTag( 'custom tag' );
+
+ $this->editPage( $name, 'Some text' );
+
+ $this->doApiRequestWithToken( [
+ 'action' => 'delete',
+ 'title' => $name,
+ 'tags' => 'custom tag',
+ ] );
+
+ $this->assertFalse( Title::newFromText( $name )->exists() );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $this->assertSame( 'custom tag', $dbw->selectField(
+ [ 'change_tag', 'logging' ],
+ 'ct_tag',
+ [
+ 'log_namespace' => NS_HELP,
+ 'log_title' => ucfirst( __FUNCTION__ ),
+ ],
+ __METHOD__,
+ [],
+ [ 'change_tag' => [ 'INNER JOIN', 'ct_log_id = log_id' ] ]
+ ) );
+ }
+
+ public function testDeleteWithoutTagPermission() {
+ $this->setExpectedException( ApiUsageException::class,
+ 'You do not have permission to apply change tags along with your changes.' );
+
+ $name = 'Help:' . ucfirst( __FUNCTION__ );
+
+ ChangeTags::defineTag( 'custom tag' );
+ $this->setMwGlobals( 'wgRevokePermissions',
+ [ 'user' => [ 'applychangetags' => true ] ] );
+
+ $this->editPage( $name, 'Some text' );
+
+ try {
+ $this->doApiRequestWithToken( [
+ 'action' => 'delete',
+ 'title' => $name,
+ 'tags' => 'custom tag',
+ ] );
+ } finally {
+ $this->assertTrue( Title::newFromText( $name )->exists() );
+ }
+ }
+
+ public function testDeleteAbortedByHook() {
+ $this->setExpectedException( ApiUsageException::class,
+ 'Deletion aborted by hook. It gave no explanation.' );
+
+ $name = 'Help:' . ucfirst( __FUNCTION__ );
+
+ $this->editPage( $name, 'Some text' );
+
+ $this->setTemporaryHook( 'ArticleDelete',
+ function () {
+ return false;
+ }
+ );
+
+ try {
+ $this->doApiRequestWithToken( [ 'action' => 'delete', 'title' => $name ] );
+ } finally {
+ $this->assertTrue( Title::newFromText( $name )->exists() );
}
+ }
+
+ public function testDeleteWatch() {
+ $name = 'Help:' . ucfirst( __FUNCTION__ );
+ $user = self::$users['sysop']->getUser();
+
+ $this->editPage( $name, 'Some text' );
+ $this->assertTrue( Title::newFromText( $name )->exists() );
+ $this->assertFalse( $user->isWatched( Title::newFromText( $name ) ) );
+
+ $this->doApiRequestWithToken( [ 'action' => 'delete', 'title' => $name, 'watch' => '' ] );
+ $this->assertFalse( Title::newFromText( $name )->exists() );
+ $this->assertTrue( $user->isWatched( Title::newFromText( $name ) ) );
+ }
+
+ public function testDeleteUnwatch() {
+ $name = 'Help:' . ucfirst( __FUNCTION__ );
+ $user = self::$users['sysop']->getUser();
+
+ $this->editPage( $name, 'Some text' );
$this->assertTrue( Title::newFromText( $name )->exists() );
+ $user->addWatch( Title::newFromText( $name ) );
+ $this->assertTrue( $user->isWatched( Title::newFromText( $name ) ) );
+
+ $this->doApiRequestWithToken( [ 'action' => 'delete', 'title' => $name, 'unwatch' => '' ] );
+
+ $this->assertFalse( Title::newFromText( $name )->exists() );
+ $this->assertFalse( $user->isWatched( Title::newFromText( $name ) ) );
}
}
$this->assertEquals( 'Success', $a );
}
+ public function testLoginWithNoSameOriginSecurity() {
+ $this->setTemporaryHook( 'RequestHasSameOriginSecurity',
+ function () {
+ return false;
+ }
+ );
+
+ $result = $this->doApiRequest( [
+ 'action' => 'login',
+ ] )[0]['login'];
+
+ $this->assertSame( [
+ 'result' => 'Aborted',
+ 'reason' => 'Cannot log in when the same-origin policy is not applied.',
+ ], $result );
+ }
}
private static $allcategories = [
[ 'list' => 'allcategories', 'acprefix' => 'AQBT-' ],
[ 'allcategories' => [
- [ '*' => 'AQBT-Cat' ],
+ [ 'category' => 'AQBT-Cat' ],
] ]
];
$this->check( self::$allpages );
$this->check( self::$alllinks );
$this->check( self::$alltransclusions );
- // This test is temporarily disabled until a sqlite bug is fixed
- // Confirmed still broken 15-nov-2013
- // $this->check( self::$allcategories );
+ $this->check( self::$allcategories );
$this->check( self::$backlinks );
$this->check( self::$embeddedin );
$this->check( self::$categorymembers );
$db->listViews( '' ) );
}
+ /**
+ * @covers Wikimedia\Rdbms\MySQLMasterPos
+ */
public function testBinLogName() {
$pos = new MySQLMasterPos( "db1052.2424/4643", 1 );
- $this->assertEquals( "db1052", $pos->binlog );
+ $this->assertEquals( "db1052", $pos->getLogName() );
$this->assertEquals( "db1052.2424", $pos->getLogFile() );
- $this->assertEquals( [ 2424, 4643 ], $pos->pos );
+ $this->assertEquals( [ 2424, 4643 ], $pos->getLogPosition() );
}
/**
],
// MySQL GTID style
[
- new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:23', $now ),
- new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:24', $now ),
+ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:1-23', $now ),
+ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:5-24', $now ),
true,
false
],
[
- new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:99', $now ),
- new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:100', $now ),
+ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:5-99', $now ),
+ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:1-100', $now ),
true,
false
],
[
- new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:99', $now ),
- new MySQLMasterPos( '1E11FA47-71CA-11E1-9E33-C80AA9429562:100', $now ),
+ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:1-99', $now ),
+ new MySQLMasterPos( '1E11FA47-71CA-11E1-9E33-C80AA9429562:1-100', $now ),
false,
false
],
],
[
new MySQLMasterPos(
- '2E11FA47-71CA-11E1-9E33-C80AA9429562:5,' .
- '3E11FA47-71CA-11E1-9E33-C80AA9429562:99,' .
- '7E11FA47-71CA-11E1-9E33-C80AA9429562:30',
+ '2E11FA47-71CA-11E1-9E33-C80AA9429562:1-5,' .
+ '3E11FA47-71CA-11E1-9E33-C80AA9429562:20-99,' .
+ '7E11FA47-71CA-11E1-9E33-C80AA9429562:1-30',
1
),
new MySQLMasterPos(
- '1E11FA47-71CA-11E1-9E33-C80AA9429562:100,' .
- '3E11FA47-71CA-11E1-9E33-C80AA9429562:66',
+ '1E11FA47-71CA-11E1-9E33-C80AA9429562:30-100,' .
+ '3E11FA47-71CA-11E1-9E33-C80AA9429562:30-66',
1
),
- [ '3E11FA47-71CA-11E1-9E33-C80AA9429562:99' ]
+ [ '3E11FA47-71CA-11E1-9E33-C80AA9429562:20-99' ]
]
];
}
];
}
+ /**
+ * @dataProvider provideGtidData
+ * @covers Wikimedia\Rdbms\MySQLMasterPos
+ * @covers Wikimedia\Rdbms\DatabaseMysqlBase::getReplicaPos
+ * @covers Wikimedia\Rdbms\DatabaseMysqlBase::getMasterPos
+ */
+ public function testServerGtidTable( $gtable, $rBLtable, $mBLtable, $rGTIDs, $mGTIDs ) {
+ $db = $this->getMockBuilder( DatabaseMysqli::class )
+ ->disableOriginalConstructor()
+ ->setMethods( [
+ 'useGTIDs',
+ 'getServerGTIDs',
+ 'getServerRoleStatus',
+ 'getServerId',
+ 'getServerUUID'
+ ] )
+ ->getMock();
+
+ $db->method( 'useGTIDs' )->willReturn( true );
+ $db->method( 'getServerGTIDs' )->willReturn( $gtable );
+ $db->method( 'getServerRoleStatus' )->willReturnCallback(
+ function ( $role ) use ( $rBLtable, $mBLtable ) {
+ if ( $role === 'SLAVE' ) {
+ return $rBLtable;
+ } elseif ( $role === 'MASTER' ) {
+ return $mBLtable;
+ }
+
+ return null;
+ }
+ );
+ $db->method( 'getServerId' )->willReturn( 1 );
+ $db->method( 'getServerUUID' )->willReturn( '2E11FA47-71CA-11E1-9E33-C80AA9429562' );
+
+ if ( is_array( $rGTIDs ) ) {
+ $this->assertEquals( $rGTIDs, $db->getReplicaPos()->getGTIDs() );
+ } else {
+ $this->assertEquals( false, $db->getReplicaPos() );
+ }
+ if ( is_array( $mGTIDs ) ) {
+ $this->assertEquals( $mGTIDs, $db->getMasterPos()->getGTIDs() );
+ } else {
+ $this->assertEquals( false, $db->getMasterPos() );
+ }
+ }
+
+ public static function provideGtidData() {
+ return [
+ // MariaDB
+ [
+ [
+ 'gtid_domain_id' => 100,
+ 'gtid_current_pos' => '100-13-77',
+ 'gtid_binlog_pos' => '100-13-77',
+ 'gtid_slave_pos' => null // master
+ ],
+ [],
+ [
+ 'File' => 'host.1600',
+ 'Pos' => '77'
+ ],
+ [ '100' => '100-13-77' ],
+ [ '100' => '100-13-77' ]
+ ],
+ [
+ [
+ 'gtid_domain_id' => 100,
+ 'gtid_current_pos' => '100-13-77',
+ 'gtid_binlog_pos' => '100-13-77',
+ 'gtid_slave_pos' => '100-13-77' // replica
+ ],
+ [
+ 'Relay_Master_Log_File' => 'host.1600',
+ 'Exec_Master_Log_Pos' => '77'
+ ],
+ [],
+ [ '100' => '100-13-77' ],
+ [ '100' => '100-13-77' ]
+ ],
+ [
+ [
+ 'gtid_current_pos' => '100-13-77',
+ 'gtid_binlog_pos' => '100-13-77',
+ 'gtid_slave_pos' => '100-13-77' // replica
+ ],
+ [
+ 'Relay_Master_Log_File' => 'host.1600',
+ 'Exec_Master_Log_Pos' => '77'
+ ],
+ [],
+ [ '100' => '100-13-77' ],
+ [ '100' => '100-13-77' ]
+ ],
+ // MySQL
+ [
+ [
+ 'gtid_executed' => '2E11FA47-71CA-11E1-9E33-C80AA9429562:1-77'
+ ],
+ [
+ 'Relay_Master_Log_File' => 'host.1600',
+ 'Exec_Master_Log_Pos' => '77'
+ ],
+ [], // only a replica
+ [ '2E11FA47-71CA-11E1-9E33-C80AA9429562'
+ => '2E11FA47-71CA-11E1-9E33-C80AA9429562:1-77' ],
+ // replica/master use same var
+ [ '2E11FA47-71CA-11E1-9E33-C80AA9429562'
+ => '2E11FA47-71CA-11E1-9E33-C80AA9429562:1-77' ],
+ ],
+ [
+ [
+ 'gtid_executed' => '2E11FA47-71CA-11E1-9E33-C80AA9429562:1-49,' .
+ '2E11FA47-71CA-11E1-9E33-C80AA9429562:51-77'
+ ],
+ [
+ 'Relay_Master_Log_File' => 'host.1600',
+ 'Exec_Master_Log_Pos' => '77'
+ ],
+ [], // only a replica
+ [ '2E11FA47-71CA-11E1-9E33-C80AA9429562'
+ => '2E11FA47-71CA-11E1-9E33-C80AA9429562:51-77' ],
+ // replica/master use same var
+ [ '2E11FA47-71CA-11E1-9E33-C80AA9429562'
+ => '2E11FA47-71CA-11E1-9E33-C80AA9429562:51-77' ],
+ ],
+ [
+ [
+ 'gtid_executed' => null // not enabled?
+ ],
+ [
+ 'Relay_Master_Log_File' => 'host.1600',
+ 'Exec_Master_Log_Pos' => '77'
+ ],
+ [], // only a replica
+ [], // binlog fallback
+ false
+ ],
+ [
+ [
+ 'gtid_executed' => null // not enabled?
+ ],
+ [], // no replication
+ [], // no replication
+ false,
+ false
+ ]
+ ];
+ }
+
/**
* @covers Wikimedia\Rdbms\MySQLMasterPos
*/
<?php
+use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\LikeMatch;
use Wikimedia\Rdbms\Database;
$this->assertSame( 'CAST( fieldName AS INTEGER )', $output );
}
+ /**
+ * @covers \Wikimedia\Rdbms\Database::doSavepoint
+ * @covers \Wikimedia\Rdbms\Database::doReleaseSavepoint
+ * @covers \Wikimedia\Rdbms\Database::doRollbackToSavepoint
+ * @covers \Wikimedia\Rdbms\Database::startAtomic
+ * @covers \Wikimedia\Rdbms\Database::endAtomic
+ * @covers \Wikimedia\Rdbms\Database::cancelAtomic
+ * @covers \Wikimedia\Rdbms\Database::doAtomicSection
+ */
+ public function testAtomicSections() {
+ $this->database->startAtomic( __METHOD__ );
+ $this->database->endAtomic( __METHOD__ );
+ $this->assertLastSql( 'BEGIN; COMMIT' );
+
+ $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
+ $this->database->cancelAtomic( __METHOD__ );
+ $this->assertLastSql( 'BEGIN; ROLLBACK' );
+
+ $this->database->begin( __METHOD__ );
+ $this->database->startAtomic( __METHOD__ );
+ $this->database->endAtomic( __METHOD__ );
+ $this->database->commit( __METHOD__ );
+ $this->assertLastSql( 'BEGIN; COMMIT' );
+
+ $this->database->begin( __METHOD__ );
+ $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
+ $this->database->endAtomic( __METHOD__ );
+ $this->database->commit( __METHOD__ );
+ // phpcs:ignore Generic.Files.LineLength
+ $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; RELEASE SAVEPOINT wikimedia_rdbms_atomic1; COMMIT' );
+
+ $this->database->begin( __METHOD__ );
+ $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
+ $this->database->cancelAtomic( __METHOD__ );
+ $this->database->commit( __METHOD__ );
+ // phpcs:ignore Generic.Files.LineLength
+ $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1; COMMIT' );
+
+ $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
+ $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
+ $this->database->cancelAtomic( __METHOD__ );
+ $this->database->endAtomic( __METHOD__ );
+ // phpcs:ignore Generic.Files.LineLength
+ $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1; COMMIT' );
+
+ $this->database->doAtomicSection( __METHOD__, function () {
+ } );
+ $this->assertLastSql( 'BEGIN; COMMIT' );
+
+ $this->database->begin( __METHOD__ );
+ $this->database->doAtomicSection( __METHOD__, function () {
+ } );
+ $this->database->rollback( __METHOD__ );
+ // phpcs:ignore Generic.Files.LineLength
+ $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; RELEASE SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK' );
+
+ $this->database->begin( __METHOD__ );
+ try {
+ $this->database->doAtomicSection( __METHOD__, function () {
+ throw new RuntimeException( 'Test exception' );
+ } );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( RuntimeException $ex ) {
+ $this->assertSame( 'Test exception', $ex->getMessage() );
+ }
+ $this->database->commit( __METHOD__ );
+ // phpcs:ignore Generic.Files.LineLength
+ $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1; COMMIT' );
+ }
+
+ public static function provideAtomicSectionMethodsForErrors() {
+ return [
+ [ 'endAtomic' ],
+ [ 'cancelAtomic' ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideAtomicSectionMethodsForErrors
+ * @covers \Wikimedia\Rdbms\Database::endAtomic
+ * @covers \Wikimedia\Rdbms\Database::cancelAtomic
+ */
+ public function testNoAtomicSection( $method ) {
+ try {
+ $this->database->$method( __METHOD__ );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( DBUnexpectedError $ex ) {
+ $this->assertSame(
+ 'No atomic transaction is open (got ' . __METHOD__ . ').',
+ $ex->getMessage()
+ );
+ }
+ }
+
+ /**
+ * @dataProvider provideAtomicSectionMethodsForErrors
+ * @covers \Wikimedia\Rdbms\Database::endAtomic
+ * @covers \Wikimedia\Rdbms\Database::cancelAtomic
+ */
+ public function testInvalidAtomicSectionEnded( $method ) {
+ $this->database->startAtomic( __METHOD__ . 'X' );
+ try {
+ $this->database->$method( __METHOD__ );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( DBUnexpectedError $ex ) {
+ $this->assertSame(
+ 'Invalid atomic section ended (got ' . __METHOD__ . ').',
+ $ex->getMessage()
+ );
+ }
+ }
+
+ /**
+ * @covers \Wikimedia\Rdbms\Database::cancelAtomic
+ */
+ public function testUncancellableAtomicSection() {
+ $this->database->startAtomic( __METHOD__ );
+ try {
+ $this->database->cancelAtomic( __METHOD__ );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( DBUnexpectedError $ex ) {
+ $this->assertSame(
+ 'Uncancelable atomic section canceled (got ' . __METHOD__ . ').',
+ $ex->getMessage()
+ );
+ }
+ }
+
}
$this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX is set' );
$called = false;
- $db->onTransactionPreCommitOrIdle(
- function () use ( &$called ) {
- $called = true;
- }
- );
+ $callback = function () use ( &$called ) {
+ $called = true;
+ };
+ $db->onTransactionPreCommitOrIdle( $callback, __METHOD__ );
$this->assertFalse( $called, 'Not called when idle if DBO_TRX is set' );
$lbFactory->beginMasterChanges( __METHOD__ );
$lbFactory->commitMasterChanges( __METHOD__ );
$this->assertTrue( $called, 'Called when lb-transaction is committed' );
+
+ $called = false;
+ $lbFactory->beginMasterChanges( __METHOD__ );
+ $db->onTransactionPreCommitOrIdle( $callback, __METHOD__ );
+ $this->assertFalse( $called, 'Not called when lb-transaction is active' );
+
+ $lbFactory->rollbackMasterChanges( __METHOD__ );
+ $this->assertFalse( $called, 'Not called when lb-transaction is rolled back' );
+
+ $lbFactory->commitMasterChanges( __METHOD__ );
+ $this->assertFalse( $called, 'Not called in next round commit' );
}
/**
$user = $this->getTestSysop()->getUser();
$this->assertConditions(
[ # expected
- "rc_patrolled = 1",
+ "rc_patrolled != 0",
],
[
'hideunpatrolled' => 1,
$user->setOption( 'userjs-someoption', 'test' );
$user->setOption( 'rclimit', 200 );
+ $user->setOption( 'wpwatchlistdays', '0' );
$user->saveSettings();
$user = User::newFromName( $user->getName() );
MediaWikiServices::getInstance()->getMainWANObjectCache()->clearProcessCache();
$this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) );
$this->assertEquals( 200, $user->getOption( 'rclimit' ) );
+
+ // Check that an option saved as a string '0' is returned as an integer.
+ $user = User::newFromName( $user->getName() );
+ $user->load( User::READ_LATEST );
+ $this->assertSame( 0, $user->getOption( 'wpwatchlistdays' ) );
}
/**
} catch ( InvalidArgumentException $ex ) {
}
}
+
+ /**
+ * @covers User::getBlockedStatus
+ * @covers User::getBlock
+ * @covers User::blockedBy
+ * @covers User::blockedFor
+ * @covers User::isHidden
+ * @covers User::isBlockedFrom
+ */
+ public function testBlockInstanceCache() {
+ // First, check the user isn't blocked
+ $user = $this->getMutableTestUser()->getUser();
+ $ut = Title::makeTitle( NS_USER_TALK, $user->getName() );
+ $this->assertNull( $user->getBlock( false ), 'sanity check' );
+ $this->assertSame( '', $user->blockedBy(), 'sanity check' );
+ $this->assertSame( '', $user->blockedFor(), 'sanity check' );
+ $this->assertFalse( (bool)$user->isHidden(), 'sanity check' );
+ $this->assertFalse( $user->isBlockedFrom( $ut ), 'sanity check' );
+
+ // Block the user
+ $blocker = $this->getTestSysop()->getUser();
+ $block = new Block( [
+ 'hideName' => true,
+ 'allowUsertalk' => false,
+ 'reason' => 'Because',
+ ] );
+ $block->setTarget( $user );
+ $block->setBlocker( $blocker );
+ $res = $block->insert();
+ $this->assertTrue( (bool)$res['id'], 'sanity check: Failed to insert block' );
+
+ // Clear cache and confirm it loaded the block properly
+ $user->clearInstanceCache();
+ $this->assertInstanceOf( Block::class, $user->getBlock( false ) );
+ $this->assertSame( $blocker->getName(), $user->blockedBy() );
+ $this->assertSame( 'Because', $user->blockedFor() );
+ $this->assertTrue( (bool)$user->isHidden() );
+ $this->assertTrue( $user->isBlockedFrom( $ut ) );
+
+ // Unblock
+ $block->delete();
+
+ // Clear cache and confirm it loaded the not-blocked properly
+ $user->clearInstanceCache();
+ $this->assertNull( $user->getBlock( false ) );
+ $this->assertSame( '', $user->blockedBy() );
+ $this->assertSame( '', $user->blockedFor() );
+ $this->assertFalse( (bool)$user->isHidden() );
+ $this->assertFalse( $user->isBlockedFrom( $ut ) );
+ }
+
}
mw.language.setData( 'en', 'digitGroupingPattern', null );
mw.language.setData( 'en', 'digitTransformTable', null );
mw.language.setData( 'en', 'separatorTransformTable', { ',': '.', '.': ',' } );
+ mw.language.setData( 'en', 'minimumGroupingDigits', null );
mw.config.set( 'wgUserLanguage', 'en' );
mw.config.set( 'wgTranslateNumerals', true );
- assert.equal( mw.language.convertNumber( 1800 ), '1.800', 'formatting' );
+ assert.equal( mw.language.convertNumber( 180 ), '180', 'formatting 3-digit' );
+ assert.equal( mw.language.convertNumber( 1800 ), '1.800', 'formatting 4-digit' );
+ assert.equal( mw.language.convertNumber( 18000 ), '18.000', 'formatting 5-digit' );
+
assert.equal( mw.language.convertNumber( '1.800', true ), '1800', 'unformatting' );
+
+ mw.language.setData( 'en', 'minimumGroupingDigits', 2 );
+ assert.equal( mw.language.convertNumber( 180 ), '180', 'formatting 3-digit with minimumGroupingDigits=2' );
+ assert.equal( mw.language.convertNumber( 1800 ), '1800', 'formatting 4-digit with minimumGroupingDigits=2' );
+ assert.equal( mw.language.convertNumber( 18000 ), '18.000', 'formatting 5-digit with minimumGroupingDigits=2' );
} );
QUnit.test( 'mw.language.convertNumber - digitTransformTable', function ( assert ) {
mw.config.set( 'wgTranslateNumerals', true );
mw.language.setData( 'hi', 'digitGroupingPattern', null );
mw.language.setData( 'hi', 'separatorTransformTable', { ',': '.', '.': ',' } );
+ mw.language.setData( 'hi', 'minimumGroupingDigits', null );
// Example from Hindi (MessagesHi.php)
mw.language.setData( 'hi', 'digitTransformTable', {